1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
4 *
5 * Block several processes on a mutex, then wake them up.
6 */
7
8 #include <sys/types.h>
9 #include <sys/wait.h>
10
11 #include "futextest.h"
12 #include "futex_utils.h"
13
14 static futex_t *futex;
15
16 static struct futex_test_variants variants[] = {
17 #if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
18 { .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
19 #endif
20
21 #if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
22 { .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
23 #endif
24 };
25
do_child(void)26 static void do_child(void)
27 {
28 struct futex_test_variants *tv = &variants[tst_variant];
29
30 futex_wait(tv->fntype, futex, *futex, NULL, 0);
31 exit(0);
32 }
33
do_wake(int nr_children)34 static void do_wake(int nr_children)
35 {
36 struct futex_test_variants *tv = &variants[tst_variant];
37 int res, i, cnt;
38
39 TEST(futex_wake(tv->fntype, futex, nr_children, 0));
40 if (TST_RET != nr_children) {
41 tst_res(TFAIL | TTERRNO,
42 "futex_wake() woken up %li children, expected %i",
43 TST_RET, nr_children);
44 return;
45 }
46
47 for (cnt = 0, i = 0; i < 100000; i++) {
48 while (waitpid(-1, &res, WNOHANG) > 0)
49 cnt++;
50
51 if (cnt == nr_children)
52 break;
53
54 usleep(100);
55 }
56
57 if (cnt != nr_children) {
58 tst_res(TFAIL, "reaped only %i childs, expected %i",
59 cnt, nr_children);
60 } else {
61 tst_res(TPASS, "futex_wake() woken up %i childs", cnt);
62 }
63 }
64
run(void)65 static void run(void)
66 {
67 struct futex_test_variants *tv = &variants[tst_variant];
68 pid_t pids[55];
69 unsigned int i;
70
71 for (i = 0; i < ARRAY_SIZE(pids); i++) {
72 pids[i] = SAFE_FORK();
73 if (!pids[i])
74 do_child();
75 }
76
77 for (i = 0; i < ARRAY_SIZE(pids); i++)
78 TST_PROCESS_STATE_WAIT(pids[i], 'S', 0);
79
80 for (i = 1; i <= 10; i++)
81 do_wake(i);
82
83 TEST(futex_wake(tv->fntype, futex, 1, 0));
84 if (TST_RET) {
85 tst_res(TFAIL | TTERRNO,
86 "futex_wake() woken up %li, none were waiting",
87 TST_RET);
88 } else {
89 tst_res(TPASS, "futex_wake() woken up 0 children");
90 }
91 }
92
setup(void)93 static void setup(void)
94 {
95 struct futex_test_variants *tv = &variants[tst_variant];
96
97 tst_res(TINFO, "Testing variant: %s", tv->desc);
98 futex_supported_by_kernel(tv->fntype);
99
100 futex = SAFE_MMAP(NULL, sizeof(*futex), PROT_READ | PROT_WRITE,
101 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
102
103 *futex = FUTEX_INITIALIZER;
104 }
105
106 static struct tst_test test = {
107 .setup = setup,
108 .test_all = run,
109 .test_variants = ARRAY_SIZE(variants),
110 .forks_child = 1,
111 };
112