diff --git a/posix/Makefile b/posix/Makefile index a650abf598..c0e224236a 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -253,7 +253,8 @@ tests := \ tst-boost \ tst-chmod \ tst-cpucount \ - tst-cpuset \ + tst-cpuset-dynamic \ + tst-cpuset-static \ tst-dir \ tst-execl1 \ tst-execl2 \ diff --git a/posix/tst-cpuset-dynamic.c b/posix/tst-cpuset-dynamic.c new file mode 100644 index 0000000000..6e0f06dfd8 --- /dev/null +++ b/posix/tst-cpuset-dynamic.c @@ -0,0 +1,63 @@ +/* Test that CPU_* macros comply with their specifications. + + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#define LOCAL_NUM_CPUS 2048 +#define LOCAL_CPU_SETSIZE LOCAL_NUM_CPUS / 8 + +#define PREPARE_CPU_SET(X) \ + X = CPU_ALLOC (LOCAL_NUM_CPUS); + +/* Create a mapping so that access to the page before the cpuset generates a + fault. The aim is to check the behavior for negative values since the + interface accepts signed int. */ +#define PREPARE_CPU_SET_TO_FAULT_BEFORE(X) \ + size_t local_sz_##X = CPU_ALLOC_SIZE(LOCAL_NUM_CPUS); \ + struct support_next_to_fault local_##X = support_next_to_fault_allocate_before(local_sz_##X); \ + X = (cpu_set_t *) local_##X.buffer; + +/* Create a mapping so that access to the page after the cpuset generates a + fault. The aim is to check the behavior for values above CPU count since the + interface accepts signed int. */ +#define PREPARE_CPU_SET_TO_FAULT(X) \ + size_t local_sz_##X = CPU_ALLOC_SIZE(LOCAL_NUM_CPUS); \ + struct support_next_to_fault local_##X = support_next_to_fault_allocate(local_sz_##X); \ + X = (cpu_set_t *) local_##X.buffer; + +#define GET_SIZE() (size_t) CPU_ALLOC_SIZE(LOCAL_NUM_CPUS) + +#define LOCAL_CPU_ZERO(sz, cpusetp) CPU_ZERO_S(sz, cpusetp) +#define LOCAL_CPU_SET(cpu, sz, cpusetp) CPU_SET_S(cpu, sz, cpusetp) +#define LOCAL_CPU_CLR(cpu, sz, cpusetp) CPU_CLR_S(cpu, sz, cpusetp) +#define LOCAL_CPU_ISSET(cpu, sz, cpusetp) CPU_ISSET_S(cpu, sz, cpusetp) +#define LOCAL_CPU_COUNT(sz, cpusetp) CPU_COUNT_S(sz, cpusetp) +#define LOCAL_CPU_AND(sz, destsetp, srcsetp1, srcsetp2) \ + CPU_AND_S(sz, destsetp, srcsetp1, srcsetp2) +#define LOCAL_CPU_OR(sz, destsetp, srcsetp1, srcsetp2) \ + CPU_OR_S(sz, destsetp, srcsetp1, srcsetp2) +#define LOCAL_CPU_XOR(sz, destsetp, srcsetp1, srcsetp2) \ + CPU_XOR_S(sz, destsetp, srcsetp1, srcsetp2) +#define LOCAL_CPU_EQUAL(sz, setp1, setp2) CPU_EQUAL_S(sz, setp1, setp2) + +#define CLEAN_CPU_SET(cpusetp) CPU_FREE(cpusetp) +#define CLEAN_CPU_SET_TO_FAULT_BEFORE(X) support_next_to_fault_free(&local_##X) +#define CLEAN_CPU_SET_TO_FAULT(X) support_next_to_fault_free(&local_##X) + +#include "tst-cpuset-skeleton.c" diff --git a/posix/tst-cpuset-skeleton.c b/posix/tst-cpuset-skeleton.c new file mode 100644 index 0000000000..2c04989c0d --- /dev/null +++ b/posix/tst-cpuset-skeleton.c @@ -0,0 +1,123 @@ +/* Test that CPU_* macros comply with their specifications. + + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include + +static int +do_test (void) +{ + cpu_set_t *cpusetp_A = NULL; + cpu_set_t *cpusetp_B = NULL; + cpu_set_t *cpusetp_C = NULL; + + size_t setsz __attribute__ ((unused)) = GET_SIZE(); + + TEST_VERIFY (CPU_ALLOC_SIZE (-1) == 0); + TEST_VERIFY (CPU_ALLOC_SIZE (0) == 0); + TEST_VERIFY (CPU_ALLOC_SIZE (1) == sizeof (__cpu_mask)); + TEST_VERIFY (CPU_ALLOC_SIZE (INT_MAX) > 0); + + PREPARE_CPU_SET_TO_FAULT_BEFORE(cpusetp_A); + PREPARE_CPU_SET_TO_FAULT(cpusetp_B); + PREPARE_CPU_SET(cpusetp_C); + + /* Bad actor access, negative CPU number */ + LOCAL_CPU_SET (-1, setsz, cpusetp_A); + TEST_VERIFY (!LOCAL_CPU_ISSET (-1, setsz, cpusetp_A)); + + /* Bad actor access, above CPU number */ + LOCAL_CPU_SET (LOCAL_NUM_CPUS, setsz, cpusetp_B); + TEST_VERIFY (!LOCAL_CPU_ISSET (LOCAL_NUM_CPUS, setsz, cpusetp_B)); + + LOCAL_CPU_ZERO (setsz, cpusetp_A); + LOCAL_CPU_ZERO (setsz, cpusetp_B); + LOCAL_CPU_ZERO (setsz, cpusetp_C); + + for (int cpu = 0; cpu < LOCAL_NUM_CPUS; cpu += 2) + { + /* Set A = 0x55..55 */ + LOCAL_CPU_SET (cpu, setsz, cpusetp_A); + TEST_VERIFY (LOCAL_CPU_ISSET (cpu, setsz, cpusetp_A)); + } + for (int cpu = 1; cpu < LOCAL_NUM_CPUS; cpu += 2) + { + /* Set B = 0xAA..AA */ + LOCAL_CPU_SET (cpu, setsz, cpusetp_B); + TEST_VERIFY (LOCAL_CPU_ISSET (cpu, setsz, cpusetp_B)); + } + + /* Ensure CPU_COUNT matches expected count */ + TEST_VERIFY (LOCAL_CPU_COUNT (setsz, cpusetp_A) == LOCAL_CPU_COUNT (setsz, cpusetp_B)); + TEST_VERIFY (LOCAL_CPU_COUNT (setsz, cpusetp_A) == LOCAL_NUM_CPUS / 2); + + LOCAL_CPU_AND (setsz, cpusetp_C, cpusetp_A, cpusetp_B); + for (int cpu = 0; cpu < LOCAL_NUM_CPUS; cpu++) + { + /* A setsz, B == 0 */ + TEST_VERIFY (!LOCAL_CPU_ISSET (cpu, setsz, cpusetp_C)); + } + + LOCAL_CPU_OR (setsz, cpusetp_C, cpusetp_A, cpusetp_B); + for (int cpu = 0; cpu < LOCAL_NUM_CPUS; cpu++) + { + /* A | B == 0xFF..FF */ + TEST_VERIFY (LOCAL_CPU_ISSET (cpu, setsz, cpusetp_C)); + } + + /* Check that CPU_ZERO actually does something */ + TEST_VERIFY (LOCAL_CPU_COUNT (setsz, cpusetp_C) == LOCAL_NUM_CPUS); + LOCAL_CPU_ZERO (setsz, cpusetp_C); + TEST_VERIFY (LOCAL_CPU_COUNT (setsz, cpusetp_C) == 0); + + LOCAL_CPU_XOR (setsz, cpusetp_C, cpusetp_A, cpusetp_A); + for (int cpu = 0; cpu < LOCAL_NUM_CPUS; cpu++) + { + /* A ^ A == 0 */ + TEST_VERIFY (!LOCAL_CPU_ISSET (cpu, setsz, cpusetp_C)); + } + + LOCAL_CPU_XOR (setsz, cpusetp_C, cpusetp_A, cpusetp_B); + for (int cpu = 0; cpu < LOCAL_NUM_CPUS; cpu++) + { + /* C = A ^ B == 0xFF..FF */ + TEST_VERIFY (LOCAL_CPU_ISSET (cpu, setsz, cpusetp_C)); + } + + for (int cpu = 1; cpu < LOCAL_NUM_CPUS; cpu += 2) + { + /* C = 0x55..55 */ + LOCAL_CPU_CLR (cpu, setsz, cpusetp_C); + TEST_VERIFY (!LOCAL_CPU_ISSET (cpu, setsz, cpusetp_C)); + } + + TEST_VERIFY (LOCAL_CPU_EQUAL (setsz, cpusetp_A, cpusetp_C)); + + CLEAN_CPU_SET(cpusetp_C); + CLEAN_CPU_SET_TO_FAULT(cpusetp_B); + CLEAN_CPU_SET_TO_FAULT_BEFORE(cpusetp_A); + + return 0; +} + +#include diff --git a/posix/tst-cpuset-static.c b/posix/tst-cpuset-static.c new file mode 100644 index 0000000000..ad4c40e422 --- /dev/null +++ b/posix/tst-cpuset-static.c @@ -0,0 +1,61 @@ +/* Test that CPU_* macros comply with their specifications. + + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#define LOCAL_NUM_CPUS CPU_SETSIZE + +/* Create a mapping so that access to the page before the cpuset generates a + fault. The aim is to check the behavior for negative values since the + interface accepts signed int. */ +#define PREPARE_CPU_SET_TO_FAULT_BEFORE(X) \ + struct support_next_to_fault local_##X = support_next_to_fault_allocate_before(sizeof(*X)); \ + X = (cpu_set_t *) local_##X.buffer; + +/* Create a mapping so that access to the page after the cpuset generates a + fault. The aim is to check the behavior for values above CPU count since the + interface accepts signed int. */ +#define PREPARE_CPU_SET_TO_FAULT(X) \ + struct support_next_to_fault local_##X = support_next_to_fault_allocate(sizeof(*X)); \ + X = (cpu_set_t *) local_##X.buffer; + +#define PREPARE_CPU_SET(X) \ + cpu_set_t local_##X = {}; \ + X = &local_##X; + +#define GET_SIZE() (size_t) sizeof (cpu_set_t) + +#define LOCAL_CPU_ZERO(sz, cpusetp) CPU_ZERO(cpusetp) +#define LOCAL_CPU_SET(cpu, sz, cpusetp) CPU_SET(cpu, cpusetp) +#define LOCAL_CPU_CLR(cpu, sz, cpusetp) CPU_CLR(cpu, cpusetp) +#define LOCAL_CPU_ISSET(cpu, sz, cpusetp) CPU_ISSET(cpu, cpusetp) +#define LOCAL_CPU_COUNT(sz, cpusetp) CPU_COUNT(cpusetp) +#define LOCAL_CPU_AND(sz, destsetp, srcsetp1, srcsetp2) \ + CPU_AND(destsetp, srcsetp1, srcsetp2) +#define LOCAL_CPU_OR(sz, destsetp, srcsetp1, srcsetp2) \ + CPU_OR(destsetp, srcsetp1, srcsetp2) +#define LOCAL_CPU_XOR(sz, destsetp, srcsetp1, srcsetp2) \ + CPU_XOR(destsetp, srcsetp1, srcsetp2) +#define LOCAL_CPU_EQUAL(sz, setp1, setp2) CPU_EQUAL(setp1, setp2) + +#define CLEAN_CPU_SET(X) +#define CLEAN_CPU_SET_TO_FAULT_BEFORE(X) support_next_to_fault_free(&local_##X) +#define CLEAN_CPU_SET_TO_FAULT(X) support_next_to_fault_free(&local_##X) + +#include "tst-cpuset-skeleton.c" diff --git a/posix/tst-cpuset.c b/posix/tst-cpuset.c deleted file mode 100644 index d736793222..0000000000 --- a/posix/tst-cpuset.c +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -static int -do_test (void) -{ - int result = 0; - - cpu_set_t s1; - cpu_set_t s2; - cpu_set_t s3; - - CPU_ZERO (&s1); - CPU_SET (0, &s1); - - CPU_ZERO (&s2); - CPU_SET (0, &s2); - CPU_SET (1, &s2); - - CPU_AND (&s3, &s1, &s2); - if (! CPU_EQUAL (&s3, &s1)) - { - puts ("result of CPU_AND wrong"); - result = 1; - } - - CPU_OR (&s3, &s1, &s2); - if (! CPU_EQUAL (&s3, &s2)) - { - puts ("result of CPU_OR wrong"); - result = 1; - } - - CPU_XOR (&s3, &s1, &s2); - if (CPU_COUNT (&s3) != 1) - { - puts ("result of CPU_XOR wrong"); - result = 1; - } - - cpu_set_t *vs1 = CPU_ALLOC (2048); - cpu_set_t *vs2 = CPU_ALLOC (2048); - cpu_set_t *vs3 = CPU_ALLOC (2048); - size_t vssize = CPU_ALLOC_SIZE (2048); - - CPU_ZERO_S (vssize, vs1); - CPU_SET_S (0, vssize, vs1); - - CPU_ZERO_S (vssize, vs2); - CPU_SET_S (0, vssize, vs2); - CPU_SET_S (2047, vssize, vs2); - - CPU_AND_S (vssize, vs3, vs1, vs2); - if (! CPU_EQUAL_S (vssize, vs3, vs1)) - { - puts ("result of CPU_AND_S wrong"); - result = 1; - } - - CPU_OR_S (vssize, vs3, vs1, vs2); - if (! CPU_EQUAL_S (vssize, vs3, vs2)) - { - puts ("result of CPU_OR_S wrong"); - result = 1; - } - - CPU_XOR_S (vssize, vs3, vs1, vs2); - if (CPU_COUNT_S (vssize, vs3) != 1) - { - puts ("result of CPU_XOR_S wrong"); - result = 1; - } - - CPU_FREE (vs1); - CPU_FREE (vs2); - CPU_FREE (vs3); - - return result; -} - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c"