xref: /openbsd-src/regress/sys/kern/signal/sig-stop2/sig-stop2.c (revision d68b1cefd50125f3ecf3e4b0e833f068c90b6ed0)
1*d68b1cefSclaudio /*	$OpenBSD: sig-stop2.c,v 1.1 2024/10/07 14:01:12 claudio Exp $	*/
2*d68b1cefSclaudio /*
3*d68b1cefSclaudio  *	Written by Artur Grabowski <art@openbsd.org> 2007 Public Domain.
4*d68b1cefSclaudio  *	Written by Claudio Jeker <claudio@openbsd.org> 2024 Public Domain.
5*d68b1cefSclaudio  */
6*d68b1cefSclaudio #include <sys/types.h>
7*d68b1cefSclaudio #include <sys/time.h>
8*d68b1cefSclaudio #include <sys/wait.h>
9*d68b1cefSclaudio 
10*d68b1cefSclaudio #include <err.h>
11*d68b1cefSclaudio #include <stdlib.h>
12*d68b1cefSclaudio #include <stdio.h>
13*d68b1cefSclaudio #include <unistd.h>
14*d68b1cefSclaudio #include <time.h>
15*d68b1cefSclaudio #include <err.h>
16*d68b1cefSclaudio #include <signal.h>
17*d68b1cefSclaudio #include <pthread.h>
18*d68b1cefSclaudio 
19*d68b1cefSclaudio #define	THREAD_COUNT	4
20*d68b1cefSclaudio 
21*d68b1cefSclaudio volatile sig_atomic_t tstp_count, cont_count;
22*d68b1cefSclaudio pid_t child;
23*d68b1cefSclaudio 
24*d68b1cefSclaudio static void
25*d68b1cefSclaudio tstp_handler(int sig)
26*d68b1cefSclaudio {
27*d68b1cefSclaudio 	tstp_count++;
28*d68b1cefSclaudio 	dprintf(STDERR_FILENO, "SIGTSTP\n");
29*d68b1cefSclaudio 	kill(getpid(), SIGSTOP);
30*d68b1cefSclaudio }
31*d68b1cefSclaudio 
32*d68b1cefSclaudio static void
33*d68b1cefSclaudio cont_handler(int sig)
34*d68b1cefSclaudio {
35*d68b1cefSclaudio 	dprintf(STDERR_FILENO, "SIGCONT\n");
36*d68b1cefSclaudio 	cont_count++;
37*d68b1cefSclaudio }
38*d68b1cefSclaudio 
39*d68b1cefSclaudio static void
40*d68b1cefSclaudio alrm_handler(int sig)
41*d68b1cefSclaudio {
42*d68b1cefSclaudio 	kill(child, SIGKILL);
43*d68b1cefSclaudio 	dprintf(STDERR_FILENO, "timeout\n");
44*d68b1cefSclaudio 	_exit(2);
45*d68b1cefSclaudio }
46*d68b1cefSclaudio 
47*d68b1cefSclaudio 
48*d68b1cefSclaudio static void *
49*d68b1cefSclaudio thread(void *arg)
50*d68b1cefSclaudio {
51*d68b1cefSclaudio 	struct timespec ts = { .tv_sec = 2 };
52*d68b1cefSclaudio 
53*d68b1cefSclaudio 	while (nanosleep(&ts, &ts) != 0)
54*d68b1cefSclaudio 		;
55*d68b1cefSclaudio 
56*d68b1cefSclaudio 	return NULL;
57*d68b1cefSclaudio }
58*d68b1cefSclaudio 
59*d68b1cefSclaudio static int
60*d68b1cefSclaudio child_main(void)
61*d68b1cefSclaudio {
62*d68b1cefSclaudio 	pthread_t self, pthread[THREAD_COUNT];
63*d68b1cefSclaudio 	sigset_t set;
64*d68b1cefSclaudio 	int i, r;
65*d68b1cefSclaudio 
66*d68b1cefSclaudio 	signal(SIGTSTP, tstp_handler);
67*d68b1cefSclaudio 	signal(SIGCONT, cont_handler);
68*d68b1cefSclaudio 
69*d68b1cefSclaudio 	sigemptyset(&set);
70*d68b1cefSclaudio 	sigaddset(&set, SIGTSTP);
71*d68b1cefSclaudio 	sigaddset(&set, SIGCONT);
72*d68b1cefSclaudio 
73*d68b1cefSclaudio 	self = pthread_self();
74*d68b1cefSclaudio 	for (i = 0; i < THREAD_COUNT; i++) {
75*d68b1cefSclaudio 		if ((r = pthread_create(&pthread[i], NULL, thread, NULL))) {
76*d68b1cefSclaudio 			warnc(r, "could not create thread");
77*d68b1cefSclaudio 			pthread[i] = self;
78*d68b1cefSclaudio 		}
79*d68b1cefSclaudio 	}
80*d68b1cefSclaudio 
81*d68b1cefSclaudio 	sigprocmask(SIG_BLOCK, &set, NULL);
82*d68b1cefSclaudio 
83*d68b1cefSclaudio 	for (i = 0; i < THREAD_COUNT; i++) {
84*d68b1cefSclaudio 		if (!pthread_equal(pthread[i], self) &&
85*d68b1cefSclaudio 		    (r = pthread_join(pthread[i], NULL)))
86*d68b1cefSclaudio 			warnc(r, "could not join thread");
87*d68b1cefSclaudio 	}
88*d68b1cefSclaudio 
89*d68b1cefSclaudio 	printf("#tstp = %d #cont = %d\n", tstp_count, cont_count);
90*d68b1cefSclaudio 
91*d68b1cefSclaudio 	return !(tstp_count == 1 && cont_count == 1);
92*d68b1cefSclaudio }
93*d68b1cefSclaudio 
94*d68b1cefSclaudio int
95*d68b1cefSclaudio main(int argc, char **argv)
96*d68b1cefSclaudio {
97*d68b1cefSclaudio 	struct timespec ts = { .tv_nsec = 200 * 1000 * 1000 };
98*d68b1cefSclaudio 	int status;
99*d68b1cefSclaudio 
100*d68b1cefSclaudio 	switch((child = fork())) {
101*d68b1cefSclaudio 	case -1:
102*d68b1cefSclaudio 		err(1, "fork");
103*d68b1cefSclaudio 	case 0:
104*d68b1cefSclaudio 		exit(child_main());
105*d68b1cefSclaudio 	default:
106*d68b1cefSclaudio 		break;
107*d68b1cefSclaudio 	}
108*d68b1cefSclaudio 
109*d68b1cefSclaudio 	signal(SIGALRM, alrm_handler);
110*d68b1cefSclaudio 	alarm(5);
111*d68b1cefSclaudio 
112*d68b1cefSclaudio 	nanosleep(&ts, NULL);
113*d68b1cefSclaudio 
114*d68b1cefSclaudio 	if (kill(child, SIGTSTP) == -1)
115*d68b1cefSclaudio 		err(1, "kill");
116*d68b1cefSclaudio 
117*d68b1cefSclaudio 	if (waitpid(child, &status, WCONTINUED|WUNTRACED) <= 0)
118*d68b1cefSclaudio 		err(1, "waitpid");
119*d68b1cefSclaudio 
120*d68b1cefSclaudio 	nanosleep(&ts, NULL);
121*d68b1cefSclaudio 
122*d68b1cefSclaudio 	if (kill(child, SIGCONT) == -1)
123*d68b1cefSclaudio 		err(1, "kill");
124*d68b1cefSclaudio 
125*d68b1cefSclaudio 	if (waitpid(child, &status, WCONTINUED|WUNTRACED) <= 0)
126*d68b1cefSclaudio 		err(1, "waitpid");
127*d68b1cefSclaudio 
128*d68b1cefSclaudio 	nanosleep(&ts, NULL);
129*d68b1cefSclaudio 
130*d68b1cefSclaudio 	if (waitpid(child, &status, 0) <= 0)
131*d68b1cefSclaudio 		err(1, "waitpid");
132*d68b1cefSclaudio 
133*d68b1cefSclaudio 	if (!WIFEXITED(status))
134*d68b1cefSclaudio 		err(1, "bad status: %d", status);
135*d68b1cefSclaudio 
136*d68b1cefSclaudio 	return WEXITSTATUS(status);
137*d68b1cefSclaudio }
138