1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Test Description:
7f08c3bdfSopenharmony_ci * This case is designed to test whether pipe can wakeup all readers
8f08c3bdfSopenharmony_ci * when last writer closes.
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * This is also a regression test for commit 6551d5c56eb0
11f08c3bdfSopenharmony_ci * ("pipe: make sure to wake up everybody when the last reader/writer closes").
12f08c3bdfSopenharmony_ci * This bug was introduced by commit 0ddad21d3e99 ("pipe: use exclusive
13f08c3bdfSopenharmony_ci * waits when reading or writing").
14f08c3bdfSopenharmony_ci */
15f08c3bdfSopenharmony_ci#include <unistd.h>
16f08c3bdfSopenharmony_ci#include <sys/types.h>
17f08c3bdfSopenharmony_ci#include <sys/wait.h>
18f08c3bdfSopenharmony_ci#include <stdlib.h>
19f08c3bdfSopenharmony_ci#include "tst_test.h"
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_cistatic unsigned int tcases[] = {
22f08c3bdfSopenharmony_ci	2,
23f08c3bdfSopenharmony_ci	10,
24f08c3bdfSopenharmony_ci	27,
25f08c3bdfSopenharmony_ci	100
26f08c3bdfSopenharmony_ci};
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic int fds[2];
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_cistatic void do_child(unsigned int i)
31f08c3bdfSopenharmony_ci{
32f08c3bdfSopenharmony_ci	char buf;
33f08c3bdfSopenharmony_ci
34f08c3bdfSopenharmony_ci	SAFE_CLOSE(fds[1]);
35f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAKE(i);
36f08c3bdfSopenharmony_ci	int ret = SAFE_READ(0, fds[0], &buf, 1);
37f08c3bdfSopenharmony_ci	if (ret != 0)
38f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Wrong return from read %i", ret);
39f08c3bdfSopenharmony_ci	exit(0);
40f08c3bdfSopenharmony_ci}
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_cistatic void verify_pipe(unsigned int n)
43f08c3bdfSopenharmony_ci{
44f08c3bdfSopenharmony_ci	int ret;
45f08c3bdfSopenharmony_ci	unsigned int i, cnt = 0, sleep_us = 1, fail = 0;
46f08c3bdfSopenharmony_ci	unsigned int child_num = tcases[n];
47f08c3bdfSopenharmony_ci	int pid[child_num];
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci	SAFE_PIPE(fds);
50f08c3bdfSopenharmony_ci	tst_res(TINFO, "Creating %d child processes", child_num);
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci	for (i = 0; i < child_num; i++) {
53f08c3bdfSopenharmony_ci		pid[i] = SAFE_FORK();
54f08c3bdfSopenharmony_ci		if (pid[i] == 0)
55f08c3bdfSopenharmony_ci			do_child(i);
56f08c3bdfSopenharmony_ci		TST_CHECKPOINT_WAIT(i);
57f08c3bdfSopenharmony_ci		TST_PROCESS_STATE_WAIT(pid[i], 'S', 0);
58f08c3bdfSopenharmony_ci	}
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	SAFE_CLOSE(fds[0]);
61f08c3bdfSopenharmony_ci	SAFE_CLOSE(fds[1]);
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	while (cnt < child_num && sleep_us < 1000000) {
64f08c3bdfSopenharmony_ci		ret = waitpid(-1, NULL, WNOHANG);
65f08c3bdfSopenharmony_ci		if (ret < 0)
66f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "waitpid()");
67f08c3bdfSopenharmony_ci		if (ret > 0) {
68f08c3bdfSopenharmony_ci			cnt++;
69f08c3bdfSopenharmony_ci			for (i = 0; i < child_num; i++) {
70f08c3bdfSopenharmony_ci				if (pid[i] == ret)
71f08c3bdfSopenharmony_ci					pid[i] = 0;
72f08c3bdfSopenharmony_ci			}
73f08c3bdfSopenharmony_ci			continue;
74f08c3bdfSopenharmony_ci		}
75f08c3bdfSopenharmony_ci		usleep(sleep_us);
76f08c3bdfSopenharmony_ci		sleep_us *= 2;
77f08c3bdfSopenharmony_ci	}
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci	for (i = 0; i < child_num; i++) {
80f08c3bdfSopenharmony_ci		if (pid[i]) {
81f08c3bdfSopenharmony_ci			tst_res(TINFO, "pid %i still sleeps", pid[i]);
82f08c3bdfSopenharmony_ci			fail = 1;
83f08c3bdfSopenharmony_ci			SAFE_KILL(pid[i], SIGKILL);
84f08c3bdfSopenharmony_ci			SAFE_WAIT(NULL);
85f08c3bdfSopenharmony_ci		}
86f08c3bdfSopenharmony_ci	}
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci	if (fail)
89f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Closed pipe didn't wake up everyone");
90f08c3bdfSopenharmony_ci	else
91f08c3bdfSopenharmony_ci		tst_res(TPASS, "Closed pipe waked up everyone");
92f08c3bdfSopenharmony_ci}
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_cistatic struct tst_test test = {
95f08c3bdfSopenharmony_ci	.test = verify_pipe,
96f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
97f08c3bdfSopenharmony_ci	.forks_child = 1,
98f08c3bdfSopenharmony_ci	.needs_checkpoints = 1,
99f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
100f08c3bdfSopenharmony_ci		{"linux-git", "6551d5c56eb"},
101f08c3bdfSopenharmony_ci		{}
102f08c3bdfSopenharmony_ci	}
103f08c3bdfSopenharmony_ci};
104