1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Copyright 2023 Mike Galbraith <efault-AT-gmx.de> */
3/* Copyright 2023 Wei Gao <wegao@suse.com> */
4/*\
5 *
6 * [Description]
7 *
8 * Thread starvation test. On fauluty kernel the test timeouts.
9 *
10 * Original reproducer taken from:
11 * https://lore.kernel.org/lkml/9fd2c37a05713c206dcbd5866f67ce779f315e9e.camel@gmx.de/
12 */
13
14#define _GNU_SOURCE
15#include <stdio.h>
16#include <signal.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20#include <stdlib.h>
21#include <sched.h>
22
23#include "tst_test.h"
24
25static char *str_loop;
26static long loop = 2000000;
27static char *str_timeout;
28static int timeout = 240;
29
30static int wait_for_pid(pid_t pid)
31{
32	int status, ret;
33
34again:
35	ret = waitpid(pid, &status, 0);
36	if (ret == -1) {
37		if (errno == EINTR)
38			goto again;
39
40		return -1;
41	}
42
43	if (WIFSIGNALED(status))
44		return 0;
45
46	return -1;
47}
48
49static void setup(void)
50{
51	cpu_set_t mask;
52
53	CPU_ZERO(&mask);
54
55	CPU_SET(0, &mask);
56
57	TST_EXP_POSITIVE(sched_setaffinity(0, sizeof(mask), &mask));
58
59	if (tst_parse_long(str_loop, &loop, 1, LONG_MAX))
60		tst_brk(TBROK, "Invalid number of loop number '%s'", str_loop);
61
62	if (tst_parse_int(str_timeout, &timeout, 1, INT_MAX))
63		tst_brk(TBROK, "Invalid number of timeout '%s'", str_timeout);
64
65	tst_set_max_runtime(timeout);
66}
67
68static void handler(int sig LTP_ATTRIBUTE_UNUSED)
69{
70	if (loop > 0)
71		--loop;
72}
73
74static void child(void)
75{
76	pid_t ppid = getppid();
77
78	TST_CHECKPOINT_WAIT(0);
79
80	while (1)
81		SAFE_KILL(ppid, SIGUSR1);
82}
83
84static void do_test(void)
85{
86	pid_t child_pid;
87
88	child_pid = SAFE_FORK();
89
90	if (!child_pid)
91		child();
92
93	SAFE_SIGNAL(SIGUSR1, handler);
94	TST_CHECKPOINT_WAKE(0);
95
96	while (loop)
97		sleep(1);
98
99	SAFE_KILL(child_pid, SIGTERM);
100	TST_EXP_PASS(wait_for_pid(child_pid));
101}
102
103static struct tst_test test = {
104	.test_all = do_test,
105	.setup = setup,
106	.forks_child = 1,
107	.options = (struct tst_option[]) {
108		{"l:", &str_loop, "Number of loops (default 2000000)"},
109		{"t:", &str_timeout, "Max timeout (default 240s)"},
110		{}
111	},
112	.needs_checkpoints = 1,
113};
114