• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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