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
25 static char *str_loop;
26 static long loop = 2000000;
27 static char *str_timeout;
28 static int timeout = 240;
29
wait_for_pid(pid_t pid)30 static int wait_for_pid(pid_t pid)
31 {
32 int status, ret;
33
34 again:
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
setup(void)49 static 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
handler(int sig LTP_ATTRIBUTE_UNUSED)68 static void handler(int sig LTP_ATTRIBUTE_UNUSED)
69 {
70 if (loop > 0)
71 --loop;
72 }
73
child(void)74 static 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
do_test(void)84 static 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
103 static 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