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 private data.
10 */
11
12 #define _GNU_SOURCE
13 #include <unistd.h>
14 #include <time.h>
15 #include "tst_test.h"
16 #include "lapi/futex.h"
17 #include "lapi/syscalls.h"
18 #include "futex2test.h"
19 #include "futex_utils.h"
20 #include "tst_safe_pthread.h"
21 #include "tst_safe_clocks.h"
22
23 static char *str_numfutex;
24 static int numfutex = 30;
25
26 static uint32_t *futexes;
27 static struct futex_waitv *waitv;
28
setup(void)29 static void setup(void)
30 {
31 struct futex_test_variants tv = futex_variant();
32 int i;
33
34 tst_res(TINFO, "Testing variant: %s", tv.desc);
35 futex_supported_by_kernel(tv.fntype);
36
37 if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX))
38 tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex);
39
40 futexes = tst_alloc(sizeof(uint32_t) * numfutex);
41 memset(futexes, FUTEX_INITIALIZER, sizeof(uint32_t) * numfutex);
42
43 waitv = tst_alloc(sizeof(struct futex_waitv) * numfutex);
44 memset(waitv, 0, sizeof(struct futex_waitv) * numfutex);
45
46 for (i = 0; i < numfutex; i++) {
47 waitv[i].uaddr = (uintptr_t)&futexes[i];
48 waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG;
49 waitv[i].val = 0;
50 }
51 }
52
threaded(LTP_ATTRIBUTE_UNUSED void * arg)53 static void *threaded(LTP_ATTRIBUTE_UNUSED void *arg)
54 {
55 struct futex_test_variants tv = futex_variant();
56
57 TST_RETRY_FUNC(futex_wake(tv.fntype,
58 (void *)(uintptr_t)waitv[numfutex - 1].uaddr,
59 1, FUTEX_PRIVATE_FLAG), futex_waked_someone);
60
61 return NULL;
62 }
63
run(void)64 static void run(void)
65 {
66 struct timespec to;
67 pthread_t t;
68
69 SAFE_PTHREAD_CREATE(&t, NULL, threaded, NULL);
70
71 /* setting absolute timeout for futex2 */
72 SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &to);
73 to.tv_sec += 5;
74
75 TEST(futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC));
76 if (TST_RET < 0) {
77 tst_brk(TBROK | TTERRNO, "futex_waitv returned: %ld", TST_RET);
78 } else if (TST_RET != numfutex - 1) {
79 tst_res(TFAIL, "futex_waitv returned: %ld, expecting %d",
80 TST_RET, numfutex - 1);
81 }
82
83 SAFE_PTHREAD_JOIN(t, NULL);
84 tst_res(TPASS, "futex_waitv returned correctly");
85 }
86
87 static struct tst_test test = {
88 .test_all = run,
89 .setup = setup,
90 .min_kver = "5.16",
91 .test_variants = FUTEX_VARIANTS,
92 .options =
93 (struct tst_option[]){
94 { "n:", &str_numfutex, "Number of futex (default 30)" },
95 {},
96 },
97 };
98