Message ID | 20220119091311.22150-3-andrea.cervesato@suse.de |
---|---|
State | Superseded |
Headers | show |
Series | Add futex_wait testing suite | expand |
Hi! > new file mode 100644 > index 000000000..ccf1699de > --- /dev/null > +++ b/testcases/kernel/syscalls/futex/futex_waitv01.c > @@ -0,0 +1,129 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> > + */ > + > +/*\ > + * [Description] > + * > + * This test verifies EINVAL for futex_waitv syscall. > + */ > + > +#include <stdlib.h> > +#include <time.h> > +#include "tst_test.h" > +#include "futextest.h" > + > +static char *str_numfutex; > +static int numfutex = 30; > + > +static uint32_t *futexes; > +static struct futex_waitv *waitv; > + > +static void setup(void) > +{ > + struct futex_test_variants tv; > + int i; > + > + tv = futex_variants[tst_variant]; > + > + tst_res(TINFO, "Testing variant: %s", tv.desc); > + futex_supported_by_kernel(tv.fntype); > + > + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) > + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); > + > + futexes = SAFE_MALLOC(sizeof(uint32_t) * numfutex); > + memset(futexes, 0, numfutex); > + > + waitv = SAFE_MALLOC(sizeof(struct futex_waitv) * numfutex); > + for (i = 0; i < numfutex; i++) { > + waitv[i].uaddr = (uintptr_t)&futexes[i]; > + waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; > + waitv[i].val = 0; > + } Can we allocate these data structures with the guarded buffers? https://github.com/linux-test-project/ltp/wiki/C-Test-API#131-guarded-buffers > +} > + > +static void cleanup(void) > +{ > + free(futexes); > + free(waitv); > +} > + > +static void init_timeout(struct timespec *to) > +{ > + if (clock_gettime(CLOCK_MONOTONIC, to)) > + tst_brk(TBROK, "gettime64 failed"); SAFE_CLOCK_GETTIME() > + to->tv_sec++; > +} > + > +static void run(void) > +{ > + struct timespec to; > + int res; > + > + /* Testing a waiter without FUTEX_32 flag */ > + waitv[0].flags = FUTEX_PRIVATE_FLAG; > + > + init_timeout(&to); > + > + res = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); > + if (res == EINVAL) > + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); > + else > + tst_res(TPASS, "futex_waitv without FUTEX_32"); > + > + /* Testing a waiter with an unaligned address */ > + waitv[0].flags = FUTEX_PRIVATE_FLAG | FUTEX_32; > + waitv[0].uaddr = 1; > + > + init_timeout(&to); > + > + res = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); > + if (res == EINVAL) > + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); > + else > + tst_res(TPASS, "futex_waitv with an unaligned address"); > + > + /* Testing a NULL address for waiters.uaddr */ > + waitv[0].uaddr = 0x00000000; > + > + init_timeout(&to); > + > + res = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); > + if (res == EINVAL) > + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); > + else > + tst_res(TPASS, "futex_waitv NULL address in waitv.uaddr"); > + > + /* Testing a NULL address for *waiters */ > + init_timeout(&to); > + > + res = tst_futex_waitv(NULL, numfutex, 0, &to, CLOCK_MONOTONIC); > + if (res == EINVAL) > + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); > + else > + tst_res(TPASS, "futex_waitv NULL address in *waiters"); > + > + /* Testing an invalid clockid */ > + init_timeout(&to); > + > + res = tst_futex_waitv(NULL, numfutex, 0, &to, CLOCK_TAI); > + if (res == EINVAL) > + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); > + else > + tst_res(TPASS, "futex_waitv invalid clockid"); Can we put these testcases into a tcase structure as we usually do in tests? > +} > + > +static struct tst_test test = { > + .test_all = run, > + .setup = setup, > + .cleanup = cleanup, > + .min_kver = "5.16", > + .test_variants = ARRAY_SIZE(futex_variants), > + .options = (struct tst_option[]){ > + {"n:", &str_numfutex, "Number of futex (default 30)"}, I'm not sure if it makes that much sense to add the number of futexes to this test. > + {}, > + }, > +}; > diff --git a/testcases/kernel/syscalls/futex/futex_waitv02.c b/testcases/kernel/syscalls/futex/futex_waitv02.c > new file mode 100644 > index 000000000..a19568993 > --- /dev/null > +++ b/testcases/kernel/syscalls/futex/futex_waitv02.c > @@ -0,0 +1,104 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> > + */ > + > +/*\ > + * [Description] > + * > + * This test verifies futex_waitv syscall using private data. > + */ > + > +#include <stdlib.h> > +#include <time.h> > +#include "tst_test.h" > +#include "tst_safe_pthread.h" > +#include "futextest.h" > + > +static char *str_numfutex; > +static int numfutex = 30; > + > +static uint32_t *futexes; > +static struct futex_waitv *waitv; > + > +static void setup(void) > +{ > + struct futex_test_variants tv; > + int i; > + > + tv = futex_variants[tst_variant]; > + > + tst_res(TINFO, "Testing variant: %s", tv.desc); > + futex_supported_by_kernel(tv.fntype); > + > + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) > + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); > + > + futexes = SAFE_MALLOC(sizeof(uint32_t) * numfutex); > + memset(futexes, 0, numfutex); > + > + waitv = SAFE_MALLOC(sizeof(struct futex_waitv) * numfutex); > + for (i = 0; i < numfutex; i++) { > + waitv[i].uaddr = (uintptr_t)&futexes[i]; > + waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; > + waitv[i].val = 0; > + } Here as well, guarded buffers please. > +} > + > +static void cleanup(void) > +{ > + free(futexes); > + free(waitv); > +} > + > +static void *threaded(void *arg) > +{ > + struct futex_test_variants tv; > + int ret, pid = *(int *)arg; > + > + tv = futex_variants[tst_variant]; > + > + TST_PROCESS_STATE_WAIT(pid, 'S', 0); > + > + ret = futex_wake(tv.fntype, (void *)(uintptr_t)waitv[numfutex - 1].uaddr, 1, FUTEX_PRIVATE_FLAG); > + if (ret < 0) > + tst_brk(TBROK, "futex_wake private returned: %d %s", ret, tst_strerrno(-ret)); > + > + return NULL; > +} > + > +static void run(void) > +{ > + struct timespec to; > + int ret, pid = getpid(); > + pthread_t t; > + > + SAFE_PTHREAD_CREATE(&t, NULL, threaded, (void *)&pid); > + > + /* setting absolute timeout for futex2 */ > + if (clock_gettime(CLOCK_MONOTONIC, &to)) > + tst_brk(TBROK, "gettime64 failed"); > + > + to.tv_sec++; > + > + ret = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); > + if (ret < 0) > + tst_brk(TBROK, "futex_waitv returned: %d %s", ret, tst_strerrno(-ret)); > + else if (ret != numfutex - 1) > + tst_res(TFAIL, "futex_waitv returned: %d, expecting %d", ret, numfutex - 1); > + > + SAFE_PTHREAD_JOIN(t, NULL); > + tst_res(TPASS, "futex_waitv returned correctly"); > +} > + > +static struct tst_test test = { > + .test_all = run, > + .setup = setup, > + .cleanup = cleanup, > + .min_kver = "5.16", > + .test_variants = ARRAY_SIZE(futex_variants), > + .options = (struct tst_option[]){ > + {"n:", &str_numfutex, "Number of futex (default 30)"}, > + {}, > + }, > +}; > diff --git a/testcases/kernel/syscalls/futex/futex_waitv03.c b/testcases/kernel/syscalls/futex/futex_waitv03.c > new file mode 100644 > index 000000000..3f18a15a2 > --- /dev/null > +++ b/testcases/kernel/syscalls/futex/futex_waitv03.c > @@ -0,0 +1,112 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> > + */ > + > +/*\ > + * [Description] > + * > + * This test verifies futex_waitv syscall using shared data. > + */ > + > +#include <stdlib.h> > +#include <time.h> > +#include <sys/shm.h> > +#include "tst_test.h" > +#include "tst_safe_pthread.h" > +#include "futextest.h" > + > +static char *str_numfutex; > +static int numfutex = 30; > + > +static struct futex_waitv *waitv; > + > +static void setup(void) > +{ > + struct futex_test_variants tv; > + int shm_id; > + int i; > + > + tv = futex_variants[tst_variant]; > + > + tst_res(TINFO, "Testing variant: %s", tv.desc); > + futex_supported_by_kernel(tv.fntype); > + > + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) > + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); > + > + waitv = SAFE_MALLOC(sizeof(struct futex_waitv) * numfutex); > + for (i = 0; i < numfutex; i++) { > + shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); > + if (shm_id < 0) > + tst_brk(TBROK, "shmget"); > + > + unsigned int *shared_data = shmat(shm_id, NULL, 0); > + > + waitv[i].uaddr = (uintptr_t)shared_data; > + waitv[i].flags = FUTEX_32; > + waitv[i].val = 0; > + } > +} > + > +static void cleanup(void) > +{ > + int i; > + > + for (i = 0; i < numfutex; i++) > + shmdt((void *)(uintptr_t)waitv[i].uaddr); > + > + free(waitv); > +} > + > +static void *threaded(void *arg) > +{ > + struct futex_test_variants tv; > + int ret, pid = *(int *)arg; > + > + tv = futex_variants[tst_variant]; > + > + TST_PROCESS_STATE_WAIT(pid, 'S', 0); Hmm I guess that this works because the original thread that executes the run() function is the one whose status is exported in the /proc/$PID/stat file. Technically there is no need to pass the pid like this since all threads would have the same pid. What they differ in is the tid (there is no difference in tid and pid from the kernel point of view though). I guess that it would be cleaner though to add TST_THREAD_STATE_WAIT() that would look exactly the same as TST_PROCESS_STATE_WAIT() but would operate on the tid (see gettid()) and would open /proc/self/task/$TID/stat instead of /proc/$PID/stat. That way we could wait on any thread, not only the first one the program had started with. > + ret = futex_wake(tv.fntype, (void *)(uintptr_t)waitv[numfutex - 1].uaddr, 1, 0); > + if (ret < 0) > + tst_brk(TBROK, "futex_wake private returned: %d %s", ret, tst_strerrno(-ret)); > + > + return NULL; > +} > + > +static void run(void) > +{ > + struct timespec to; > + int ret, pid = getpid(); > + pthread_t t; > + > + SAFE_PTHREAD_CREATE(&t, NULL, threaded, (void *)&pid); > + > + /* setting absolute timeout for futex2 */ > + if (clock_gettime(CLOCK_MONOTONIC, &to)) > + tst_brk(TBROK, "gettime64 failed"); SAFE_CLOCK_GETTIME() > + to.tv_sec++; > + > + ret = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); > + if (ret < 0) > + tst_brk(TBROK, "futex_waitv returned: %d %s", ret, tst_strerrno(-ret)); > + else if (ret != numfutex - 1) > + tst_res(TFAIL, "futex_waitv returned: %d, expecting %d", ret, numfutex - 1); > + > + SAFE_PTHREAD_JOIN(t, NULL); > + tst_res(TPASS, "futex_waitv returned correctly"); > +} > + > +static struct tst_test test = { > + .test_all = run, > + .setup = setup, > + .cleanup = cleanup, > + .min_kver = "5.16", > + .test_variants = ARRAY_SIZE(futex_variants), > + .options = (struct tst_option[]){ > + {"n:", &str_numfutex, "Number of futex (default 30)"}, > + {}, > + }, > +}; > -- > 2.34.1 > > > -- > Mailing list info: https://lists.linux.it/listinfo/ltp
diff --git a/testcases/kernel/syscalls/futex/.gitignore b/testcases/kernel/syscalls/futex/.gitignore index 54cd02b02..9d08ba7d3 100644 --- a/testcases/kernel/syscalls/futex/.gitignore +++ b/testcases/kernel/syscalls/futex/.gitignore @@ -10,3 +10,6 @@ /futex_wake02 /futex_wake03 /futex_wake04 +/futex_waitv01 +/futex_waitv02 +/futex_waitv03 diff --git a/testcases/kernel/syscalls/futex/Makefile b/testcases/kernel/syscalls/futex/Makefile index 5713c615d..7228496bc 100644 --- a/testcases/kernel/syscalls/futex/Makefile +++ b/testcases/kernel/syscalls/futex/Makefile @@ -3,8 +3,18 @@ top_srcdir ?= ../../../.. -futex_cmp_requeue01 futex_cmp_requeue02 futex_wait02 futex_wake03 futex_wait05 futex_wait_bitset01: LDLIBS += -lrt -futex_wait03 futex_wake02 futex_wake04: CFLAGS += -pthread +futex_cmp_requeue01: LDLIBS+=-lrt +futex_cmp_requeue02: LDLIBS+=-lrt +futex_wait02: LDLIBS+=-lrt +futex_wake03: LDLIBS+=-lrt +futex_wait05: LDLIBS+=-lrt +futex_wait_bitset01: LDLIBS+=-lrt + +futex_wait03: CFLAGS+=-pthread +futex_wake02: CFLAGS+=-pthread +futex_wake04: CFLAGS+=-pthread +futex_waitv02: CFLAGS+=-pthread +futex_waitv03: CFLAGS+=-pthread include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/futex/futex_waitv01.c b/testcases/kernel/syscalls/futex/futex_waitv01.c new file mode 100644 index 000000000..ccf1699de --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex_waitv01.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies EINVAL for futex_waitv syscall. + */ + +#include <stdlib.h> +#include <time.h> +#include "tst_test.h" +#include "futextest.h" + +static char *str_numfutex; +static int numfutex = 30; + +static uint32_t *futexes; +static struct futex_waitv *waitv; + +static void setup(void) +{ + struct futex_test_variants tv; + int i; + + tv = futex_variants[tst_variant]; + + tst_res(TINFO, "Testing variant: %s", tv.desc); + futex_supported_by_kernel(tv.fntype); + + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); + + futexes = SAFE_MALLOC(sizeof(uint32_t) * numfutex); + memset(futexes, 0, numfutex); + + waitv = SAFE_MALLOC(sizeof(struct futex_waitv) * numfutex); + for (i = 0; i < numfutex; i++) { + waitv[i].uaddr = (uintptr_t)&futexes[i]; + waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; + waitv[i].val = 0; + } +} + +static void cleanup(void) +{ + free(futexes); + free(waitv); +} + +static void init_timeout(struct timespec *to) +{ + if (clock_gettime(CLOCK_MONOTONIC, to)) + tst_brk(TBROK, "gettime64 failed"); + + to->tv_sec++; +} + +static void run(void) +{ + struct timespec to; + int res; + + /* Testing a waiter without FUTEX_32 flag */ + waitv[0].flags = FUTEX_PRIVATE_FLAG; + + init_timeout(&to); + + res = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); + if (res == EINVAL) + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); + else + tst_res(TPASS, "futex_waitv without FUTEX_32"); + + /* Testing a waiter with an unaligned address */ + waitv[0].flags = FUTEX_PRIVATE_FLAG | FUTEX_32; + waitv[0].uaddr = 1; + + init_timeout(&to); + + res = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); + if (res == EINVAL) + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); + else + tst_res(TPASS, "futex_waitv with an unaligned address"); + + /* Testing a NULL address for waiters.uaddr */ + waitv[0].uaddr = 0x00000000; + + init_timeout(&to); + + res = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); + if (res == EINVAL) + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); + else + tst_res(TPASS, "futex_waitv NULL address in waitv.uaddr"); + + /* Testing a NULL address for *waiters */ + init_timeout(&to); + + res = tst_futex_waitv(NULL, numfutex, 0, &to, CLOCK_MONOTONIC); + if (res == EINVAL) + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); + else + tst_res(TPASS, "futex_waitv NULL address in *waiters"); + + /* Testing an invalid clockid */ + init_timeout(&to); + + res = tst_futex_waitv(NULL, numfutex, 0, &to, CLOCK_TAI); + if (res == EINVAL) + tst_res(TFAIL, "futex_waitv private returned: %d %s", res, tst_strerrno(res)); + else + tst_res(TPASS, "futex_waitv invalid clockid"); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_kver = "5.16", + .test_variants = ARRAY_SIZE(futex_variants), + .options = (struct tst_option[]){ + {"n:", &str_numfutex, "Number of futex (default 30)"}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/futex/futex_waitv02.c b/testcases/kernel/syscalls/futex/futex_waitv02.c new file mode 100644 index 000000000..a19568993 --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex_waitv02.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies futex_waitv syscall using private data. + */ + +#include <stdlib.h> +#include <time.h> +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "futextest.h" + +static char *str_numfutex; +static int numfutex = 30; + +static uint32_t *futexes; +static struct futex_waitv *waitv; + +static void setup(void) +{ + struct futex_test_variants tv; + int i; + + tv = futex_variants[tst_variant]; + + tst_res(TINFO, "Testing variant: %s", tv.desc); + futex_supported_by_kernel(tv.fntype); + + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); + + futexes = SAFE_MALLOC(sizeof(uint32_t) * numfutex); + memset(futexes, 0, numfutex); + + waitv = SAFE_MALLOC(sizeof(struct futex_waitv) * numfutex); + for (i = 0; i < numfutex; i++) { + waitv[i].uaddr = (uintptr_t)&futexes[i]; + waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; + waitv[i].val = 0; + } +} + +static void cleanup(void) +{ + free(futexes); + free(waitv); +} + +static void *threaded(void *arg) +{ + struct futex_test_variants tv; + int ret, pid = *(int *)arg; + + tv = futex_variants[tst_variant]; + + TST_PROCESS_STATE_WAIT(pid, 'S', 0); + + ret = futex_wake(tv.fntype, (void *)(uintptr_t)waitv[numfutex - 1].uaddr, 1, FUTEX_PRIVATE_FLAG); + if (ret < 0) + tst_brk(TBROK, "futex_wake private returned: %d %s", ret, tst_strerrno(-ret)); + + return NULL; +} + +static void run(void) +{ + struct timespec to; + int ret, pid = getpid(); + pthread_t t; + + SAFE_PTHREAD_CREATE(&t, NULL, threaded, (void *)&pid); + + /* setting absolute timeout for futex2 */ + if (clock_gettime(CLOCK_MONOTONIC, &to)) + tst_brk(TBROK, "gettime64 failed"); + + to.tv_sec++; + + ret = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); + if (ret < 0) + tst_brk(TBROK, "futex_waitv returned: %d %s", ret, tst_strerrno(-ret)); + else if (ret != numfutex - 1) + tst_res(TFAIL, "futex_waitv returned: %d, expecting %d", ret, numfutex - 1); + + SAFE_PTHREAD_JOIN(t, NULL); + tst_res(TPASS, "futex_waitv returned correctly"); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_kver = "5.16", + .test_variants = ARRAY_SIZE(futex_variants), + .options = (struct tst_option[]){ + {"n:", &str_numfutex, "Number of futex (default 30)"}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/futex/futex_waitv03.c b/testcases/kernel/syscalls/futex/futex_waitv03.c new file mode 100644 index 000000000..3f18a15a2 --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex_waitv03.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] + * + * This test verifies futex_waitv syscall using shared data. + */ + +#include <stdlib.h> +#include <time.h> +#include <sys/shm.h> +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "futextest.h" + +static char *str_numfutex; +static int numfutex = 30; + +static struct futex_waitv *waitv; + +static void setup(void) +{ + struct futex_test_variants tv; + int shm_id; + int i; + + tv = futex_variants[tst_variant]; + + tst_res(TINFO, "Testing variant: %s", tv.desc); + futex_supported_by_kernel(tv.fntype); + + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); + + waitv = SAFE_MALLOC(sizeof(struct futex_waitv) * numfutex); + for (i = 0; i < numfutex; i++) { + shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); + if (shm_id < 0) + tst_brk(TBROK, "shmget"); + + unsigned int *shared_data = shmat(shm_id, NULL, 0); + + waitv[i].uaddr = (uintptr_t)shared_data; + waitv[i].flags = FUTEX_32; + waitv[i].val = 0; + } +} + +static void cleanup(void) +{ + int i; + + for (i = 0; i < numfutex; i++) + shmdt((void *)(uintptr_t)waitv[i].uaddr); + + free(waitv); +} + +static void *threaded(void *arg) +{ + struct futex_test_variants tv; + int ret, pid = *(int *)arg; + + tv = futex_variants[tst_variant]; + + TST_PROCESS_STATE_WAIT(pid, 'S', 0); + + ret = futex_wake(tv.fntype, (void *)(uintptr_t)waitv[numfutex - 1].uaddr, 1, 0); + if (ret < 0) + tst_brk(TBROK, "futex_wake private returned: %d %s", ret, tst_strerrno(-ret)); + + return NULL; +} + +static void run(void) +{ + struct timespec to; + int ret, pid = getpid(); + pthread_t t; + + SAFE_PTHREAD_CREATE(&t, NULL, threaded, (void *)&pid); + + /* setting absolute timeout for futex2 */ + if (clock_gettime(CLOCK_MONOTONIC, &to)) + tst_brk(TBROK, "gettime64 failed"); + + to.tv_sec++; + + ret = tst_futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC); + if (ret < 0) + tst_brk(TBROK, "futex_waitv returned: %d %s", ret, tst_strerrno(-ret)); + else if (ret != numfutex - 1) + tst_res(TFAIL, "futex_waitv returned: %d, expecting %d", ret, numfutex - 1); + + SAFE_PTHREAD_JOIN(t, NULL); + tst_res(TPASS, "futex_waitv returned correctly"); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_kver = "5.16", + .test_variants = ARRAY_SIZE(futex_variants), + .options = (struct tst_option[]){ + {"n:", &str_numfutex, "Number of futex (default 30)"}, + {}, + }, +};
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.de> --- testcases/kernel/syscalls/futex/.gitignore | 3 + testcases/kernel/syscalls/futex/Makefile | 14 +- .../kernel/syscalls/futex/futex_waitv01.c | 129 ++++++++++++++++++ .../kernel/syscalls/futex/futex_waitv02.c | 104 ++++++++++++++ .../kernel/syscalls/futex/futex_waitv03.c | 112 +++++++++++++++ 5 files changed, 360 insertions(+), 2 deletions(-) create mode 100644 testcases/kernel/syscalls/futex/futex_waitv01.c create mode 100644 testcases/kernel/syscalls/futex/futex_waitv02.c create mode 100644 testcases/kernel/syscalls/futex/futex_waitv03.c