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