1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4 */
5
6 /*\
7 * [Description]
8 *
9 * This test verifies futex_waitv syscall using shared data.
10 */
11
12 #define _GNU_SOURCE
13 #include <unistd.h>
14 #include <time.h>
15 #include <sys/shm.h>
16 #include "tst_test.h"
17 #include "lapi/futex.h"
18 #include "lapi/syscalls.h"
19 #include "futex2test.h"
20 #include "futex_utils.h"
21 #include "tst_safe_pthread.h"
22 #include "tst_safe_clocks.h"
23 #include "tst_safe_sysv_ipc.h"
24
25 static char *str_numfutex;
26 static int numfutex = 30;
27
28 static struct futex_waitv *waitv;
29 static unsigned int waitv_allocated;
30 static int *shmids;
31
setup(void)32 static void setup(void)
33 {
34 struct futex_test_variants tv = futex_variant();
35 int i;
36
37 tst_res(TINFO, "Testing variant: %s", tv.desc);
38 futex_supported_by_kernel(tv.fntype);
39
40 if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX))
41 tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex);
42
43 waitv = tst_alloc(sizeof(struct futex_waitv) * numfutex);
44 memset(waitv, 0, sizeof(struct futex_waitv) * numfutex);
45 shmids = tst_alloc(sizeof(int*) * numfutex);
46 memset(shmids, 0, sizeof(int*) * numfutex);
47
48 for (i = 0; i < numfutex; i++) {
49 shmids[i] = SAFE_SHMGET(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
50 waitv[i].uaddr = (uintptr_t)SAFE_SHMAT(shmids[i], NULL, 0);
51 waitv[i].flags = FUTEX_32;
52 waitv[i].val = 0;
53 }
54 waitv_allocated = tst_variant + 1;
55 }
56
cleanup(void)57 static void cleanup(void)
58 {
59 int i;
60
61 if (waitv_allocated != (tst_variant + 1))
62 return;
63
64 for (i = 0; i < numfutex; i++) {
65 if (!waitv[i].uaddr)
66 continue;
67
68 SAFE_SHMDT((void *)(uintptr_t)waitv[i].uaddr);
69 SAFE_SHMCTL(shmids[i], IPC_RMID, NULL);
70 }
71 }
72
threaded(LTP_ATTRIBUTE_UNUSED void * arg)73 static void *threaded(LTP_ATTRIBUTE_UNUSED void *arg)
74 {
75 struct futex_test_variants tv = futex_variant();
76
77 TST_RETRY_FUNC(futex_wake(tv.fntype,
78 (void *)(uintptr_t)waitv[numfutex - 1].uaddr,
79 1, 0), futex_waked_someone);
80
81 return NULL;
82 }
83
run(void)84 static void run(void)
85 {
86 struct timespec to;
87 pthread_t t;
88
89 SAFE_PTHREAD_CREATE(&t, NULL, threaded, NULL);
90
91 /* setting absolute timeout for futex2 */
92 SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &to);
93 to.tv_sec += 5;
94
95 TEST(futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC));
96 if (TST_RET < 0) {
97 tst_brk(TBROK | TTERRNO, "futex_waitv returned: %ld", TST_RET);
98 } else if (TST_RET != numfutex - 1) {
99 tst_res(TFAIL, "futex_waitv returned: %ld, expecting %d",
100 TST_RET, numfutex - 1);
101 }
102
103 SAFE_PTHREAD_JOIN(t, NULL);
104 tst_res(TPASS, "futex_waitv returned correctly");
105 }
106
107 static struct tst_test test = {
108 .test_all = run,
109 .setup = setup,
110 .cleanup = cleanup,
111 .min_kver = "5.16",
112 .test_variants = FUTEX_VARIANTS,
113 .options =
114 (struct tst_option[]){
115 { "n:", &str_numfutex, "Number of futex (default 30)" },
116 {},
117 },
118 };
119