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