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