1/*
2 * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
3 *
4 * Licensed under the GNU GPLv2 or later.
5 * This program is free software;  you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program;  if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 /*
20  * Block several processes on a mutex, then wake them up.
21  */
22
23#include <errno.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26
27#include "test.h"
28#include "safe_macros.h"
29#include "futextest.h"
30#include "futex_common.h"
31
32const char *TCID="futex_wake03";
33const int TST_TOTAL=11;
34
35static void do_child(void)
36{
37	futex_wait(futex, *futex, NULL, 0);
38	exit(0);
39}
40
41static void do_wake(int nr_children)
42{
43	int res, i, cnt;
44
45	res = futex_wake(futex, nr_children, 0);
46
47	if (res != nr_children) {
48		tst_resm(TFAIL,
49		         "futex_wake() woken up %i children, expected %i",
50		         res, nr_children);
51		return;
52	}
53
54	for (cnt = 0, i = 0; i < 100000; i++) {
55		while (waitpid(-1, &res, WNOHANG) > 0)
56			cnt++;
57
58		if (cnt == nr_children)
59			break;
60
61		usleep(100);
62	}
63
64	if (cnt != nr_children) {
65		tst_resm(TFAIL, "reaped only %i childs, expected %i",
66		         cnt, nr_children);
67	} else {
68		tst_resm(TPASS, "futex_wake() woken up %i childs", cnt);
69	}
70}
71
72static void verify_futex_wake(void)
73{
74	int i, res;
75	pid_t pids[55];
76
77	for (i = 0; i < (int)ARRAY_SIZE(pids); i++) {
78		pids[i] = tst_fork();
79
80		switch (pids[i]) {
81		case -1:
82			tst_brkm(TBROK | TERRNO, NULL, "fork()");
83		case 0:
84			do_child();
85		default:
86		break;
87		}
88	}
89
90	for (i = 0; i < (int)ARRAY_SIZE(pids); i++)
91		tst_process_state_wait2(pids[i], 'S');
92
93	for (i = 1; i <= 10; i++)
94		do_wake(i);
95
96	res = futex_wake(futex, 1, 0);
97
98	if (res) {
99		tst_resm(TFAIL, "futex_wake() woken up %u, none were waiting",
100		         res);
101	} else {
102		tst_resm(TPASS, "futex_wake() woken up 0 children");
103	}
104}
105
106int main(int argc, char *argv[])
107{
108	int lc;
109
110	tst_parse_opts(argc, argv, NULL, NULL);
111
112	setup();
113
114	for (lc = 0; TEST_LOOPING(lc); lc++)
115		verify_futex_wake();
116
117	tst_exit();
118}
119