1 #include <pthread.h> 2 #include <sched.h> 3 #include <setjmp.h> 4 #include <signal.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <unistd.h> 9 10 11 static pthread_attr_t attributes; 12 static int id[4] = {0, 1, 2, 3}; 13 static pthread_t tid[4]; 14 static bool state[4]; 15 static bool blocking[4]; 16 static pthread_key_t self; 17 18 19 static void 20 suspendLoop(int *i) { 21 sigjmp_buf env; 22 sigset_t mask; 23 24 sigsetjmp(env, false); 25 26 state[*i] = false; 27 28 sigfillset(&mask); 29 sigdelset(&mask, SIGUSR1); 30 sigdelset(&mask, SIGTERM); 31 32 while (state[*i] == false && blocking[*i] == false) 33 sigsuspend(&mask); 34 35 state[*i] = true; 36 } 37 38 39 static void 40 suspendHandler(int sig) { 41 int *i = (int*)pthread_getspecific(self); 42 suspendLoop(i); 43 } 44 45 46 static void 47 initialiseSignals() 48 { 49 struct sigaction act; 50 sigset_t mask; 51 52 act.sa_handler = suspendHandler; 53 sigemptyset(&act.sa_mask); 54 act.sa_flags = 0; 55 sigaction(SIGUSR1, &act, NULL); 56 57 sigemptyset(&mask); 58 sigaddset(&mask, SIGQUIT); 59 sigaddset(&mask, SIGINT); 60 sigaddset(&mask, SIGPIPE); 61 sigprocmask(SIG_BLOCK, &mask, NULL); 62 } 63 64 65 static void 66 self_suspend(int* i) 67 { 68 sigset_t mask; 69 70 blocking[*i] = false; 71 72 sigemptyset(&mask); 73 sigaddset(&mask, SIGUSR1); 74 pthread_sigmask(SIG_BLOCK, &mask, NULL); 75 76 printf("thread %d suspending\n", *i); 77 78 suspendLoop(i); 79 80 printf("thread %d suspend ended\n", *i); 81 82 pthread_sigmask(SIG_UNBLOCK, &mask, NULL); 83 } 84 85 86 void * 87 threadStart(void *arg) 88 { 89 int i = *(int*)arg; 90 pthread_setspecific(self, &i); 91 92 state[i] = true; 93 blocking[i] = true; 94 95 printf("threadStart(%d)\n", i); 96 97 for (int j = 0; j < 10; j++) { 98 usleep(1000000); 99 self_suspend(&i); 100 } 101 102 printf("quitting %d\n", i); 103 return NULL; 104 } 105 106 107 /*void 108 suspendAllThreads() 109 { 110 for (int i = 0; i < 4; i++) { 111 blocking[i] = false; 112 if (state[i] == true) 113 pthread_kill(tid[i], SIGUSR1); 114 } 115 116 for (int i = 0; i < 4; i++) { 117 while(state[i] == true) { 118 sched_yield(); 119 } 120 } 121 }*/ 122 123 124 125 void 126 resumeAllThreads() 127 { 128 for (int i = 0; i < 4; i++) { 129 blocking[i] = true; 130 if (state[i] == false) { 131 printf("thread %d signaled for resume\n", i); 132 pthread_kill(tid[i], SIGUSR1); 133 } 134 } 135 136 int t = 50; 137 for (int i = 0; i < 4; i++) { 138 while(state[i] == false && t-- > 0) { 139 printf("thread %d still suspended, yielding\n", i); 140 sched_yield(); 141 } 142 } 143 } 144 145 146 int 147 main(int argc, char **argv) 148 { 149 initialiseSignals(); 150 151 pthread_key_create(&self, NULL); 152 153 pthread_attr_init(&attributes); 154 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); 155 156 for (int i = 0; i < 4; i++) { 157 if (pthread_create(&tid[i], &attributes, threadStart, &id[i]) != 0) 158 fprintf(stderr, "couldn't create thread %d\n", i); 159 printf("thread %d created\n", i); 160 } 161 162 /*suspendAllThreads();*/ 163 printf("snoozing\n"); 164 usleep(3000000); 165 printf("resuming all threads\n"); 166 resumeAllThreads(); 167 printf("resuming all threads done\n"); 168 } 169 170