192e68ec1SJérôme Duval #include <pthread.h>
292e68ec1SJérôme Duval #include <sched.h>
392e68ec1SJérôme Duval #include <setjmp.h>
492e68ec1SJérôme Duval #include <signal.h>
592e68ec1SJérôme Duval #include <stdio.h>
692e68ec1SJérôme Duval #include <stdlib.h>
792e68ec1SJérôme Duval #include <string.h>
892e68ec1SJérôme Duval #include <unistd.h>
992e68ec1SJérôme Duval
1092e68ec1SJérôme Duval
1192e68ec1SJérôme Duval static pthread_attr_t attributes;
12*921aaaa1SJérôme Duval static int id[4] = {0, 1, 2, 3};
1392e68ec1SJérôme Duval static pthread_t tid[4];
1492e68ec1SJérôme Duval static bool state[4];
1592e68ec1SJérôme Duval static bool blocking[4];
1692e68ec1SJérôme Duval static pthread_key_t self;
1792e68ec1SJérôme Duval
1892e68ec1SJérôme Duval
19d13211acSJérôme Duval static void
suspendLoop(int * i)20d13211acSJérôme Duval suspendLoop(int *i) {
2192e68ec1SJérôme Duval sigjmp_buf env;
2292e68ec1SJérôme Duval sigset_t mask;
2392e68ec1SJérôme Duval
2492e68ec1SJérôme Duval sigsetjmp(env, false);
2592e68ec1SJérôme Duval
2692e68ec1SJérôme Duval state[*i] = false;
2792e68ec1SJérôme Duval
2892e68ec1SJérôme Duval sigfillset(&mask);
2992e68ec1SJérôme Duval sigdelset(&mask, SIGUSR1);
3092e68ec1SJérôme Duval sigdelset(&mask, SIGTERM);
3192e68ec1SJérôme Duval
3292e68ec1SJérôme Duval while (state[*i] == false && blocking[*i] == false)
3392e68ec1SJérôme Duval sigsuspend(&mask);
3492e68ec1SJérôme Duval
3592e68ec1SJérôme Duval state[*i] = true;
3692e68ec1SJérôme Duval }
3792e68ec1SJérôme Duval
3892e68ec1SJérôme Duval
39d13211acSJérôme Duval static void
suspendHandler(int sig)40d13211acSJérôme Duval suspendHandler(int sig) {
4192e68ec1SJérôme Duval int *i = (int*)pthread_getspecific(self);
4292e68ec1SJérôme Duval suspendLoop(i);
4392e68ec1SJérôme Duval }
4492e68ec1SJérôme Duval
45d13211acSJérôme Duval
46d13211acSJérôme Duval static void
initialiseSignals()47d13211acSJérôme Duval initialiseSignals()
4892e68ec1SJérôme Duval {
4992e68ec1SJérôme Duval struct sigaction act;
5092e68ec1SJérôme Duval sigset_t mask;
5192e68ec1SJérôme Duval
5292e68ec1SJérôme Duval act.sa_handler = suspendHandler;
5392e68ec1SJérôme Duval sigemptyset(&act.sa_mask);
5492e68ec1SJérôme Duval act.sa_flags = 0;
5592e68ec1SJérôme Duval sigaction(SIGUSR1, &act, NULL);
5692e68ec1SJérôme Duval
5792e68ec1SJérôme Duval sigemptyset(&mask);
5892e68ec1SJérôme Duval sigaddset(&mask, SIGQUIT);
5992e68ec1SJérôme Duval sigaddset(&mask, SIGINT);
6092e68ec1SJérôme Duval sigaddset(&mask, SIGPIPE);
6192e68ec1SJérôme Duval sigprocmask(SIG_BLOCK, &mask, NULL);
6292e68ec1SJérôme Duval }
6392e68ec1SJérôme Duval
6492e68ec1SJérôme Duval
65d13211acSJérôme Duval static void
self_suspend(int * i)66d13211acSJérôme Duval self_suspend(int* i)
6792e68ec1SJérôme Duval {
6892e68ec1SJérôme Duval sigset_t mask;
6992e68ec1SJérôme Duval
7092e68ec1SJérôme Duval blocking[*i] = false;
7192e68ec1SJérôme Duval
7292e68ec1SJérôme Duval sigemptyset(&mask);
7392e68ec1SJérôme Duval sigaddset(&mask, SIGUSR1);
7492e68ec1SJérôme Duval pthread_sigmask(SIG_BLOCK, &mask, NULL);
7592e68ec1SJérôme Duval
7692e68ec1SJérôme Duval printf("thread %d suspending\n", *i);
7792e68ec1SJérôme Duval
7892e68ec1SJérôme Duval suspendLoop(i);
7992e68ec1SJérôme Duval
8092e68ec1SJérôme Duval printf("thread %d suspend ended\n", *i);
8192e68ec1SJérôme Duval
8292e68ec1SJérôme Duval pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
8392e68ec1SJérôme Duval }
8492e68ec1SJérôme Duval
8592e68ec1SJérôme Duval
86d13211acSJérôme Duval void *
threadStart(void * arg)87d13211acSJérôme Duval threadStart(void *arg)
88d13211acSJérôme Duval {
89*921aaaa1SJérôme Duval int i = *(int*)arg;
90*921aaaa1SJérôme Duval pthread_setspecific(self, &i);
9192e68ec1SJérôme Duval
92*921aaaa1SJérôme Duval state[i] = true;
93*921aaaa1SJérôme Duval blocking[i] = true;
94*921aaaa1SJérôme Duval
95*921aaaa1SJérôme Duval printf("threadStart(%d)\n", i);
9692e68ec1SJérôme Duval
9792e68ec1SJérôme Duval for (int j = 0; j < 10; j++) {
98*921aaaa1SJérôme Duval usleep(1000000);
99*921aaaa1SJérôme Duval self_suspend(&i);
10092e68ec1SJérôme Duval }
10192e68ec1SJérôme Duval
102*921aaaa1SJérôme Duval printf("quitting %d\n", i);
10392e68ec1SJérôme Duval return NULL;
10492e68ec1SJérôme Duval }
10592e68ec1SJérôme Duval
10692e68ec1SJérôme Duval
107d13211acSJérôme Duval /*void
108d13211acSJérôme Duval suspendAllThreads()
10992e68ec1SJérôme Duval {
11092e68ec1SJérôme Duval for (int i = 0; i < 4; i++) {
11192e68ec1SJérôme Duval blocking[i] = false;
11292e68ec1SJérôme Duval if (state[i] == true)
11392e68ec1SJérôme Duval pthread_kill(tid[i], SIGUSR1);
11492e68ec1SJérôme Duval }
11592e68ec1SJérôme Duval
11692e68ec1SJérôme Duval for (int i = 0; i < 4; i++) {
11792e68ec1SJérôme Duval while(state[i] == true) {
11892e68ec1SJérôme Duval sched_yield();
11992e68ec1SJérôme Duval }
12092e68ec1SJérôme Duval }
12192e68ec1SJérôme Duval }*/
12292e68ec1SJérôme Duval
12392e68ec1SJérôme Duval
12492e68ec1SJérôme Duval
125d13211acSJérôme Duval void
resumeAllThreads()126d13211acSJérôme Duval resumeAllThreads()
12792e68ec1SJérôme Duval {
12892e68ec1SJérôme Duval for (int i = 0; i < 4; i++) {
12992e68ec1SJérôme Duval blocking[i] = true;
13092e68ec1SJérôme Duval if (state[i] == false) {
13192e68ec1SJérôme Duval printf("thread %d signaled for resume\n", i);
13292e68ec1SJérôme Duval pthread_kill(tid[i], SIGUSR1);
13392e68ec1SJérôme Duval }
13492e68ec1SJérôme Duval }
13592e68ec1SJérôme Duval
136*921aaaa1SJérôme Duval int t = 50;
13792e68ec1SJérôme Duval for (int i = 0; i < 4; i++) {
138*921aaaa1SJérôme Duval while(state[i] == false && t-- > 0) {
13992e68ec1SJérôme Duval printf("thread %d still suspended, yielding\n", i);
14092e68ec1SJérôme Duval sched_yield();
14192e68ec1SJérôme Duval }
14292e68ec1SJérôme Duval }
14392e68ec1SJérôme Duval }
14492e68ec1SJérôme Duval
14592e68ec1SJérôme Duval
146d13211acSJérôme Duval int
main(int argc,char ** argv)147d13211acSJérôme Duval main(int argc, char **argv)
14892e68ec1SJérôme Duval {
14992e68ec1SJérôme Duval initialiseSignals();
15092e68ec1SJérôme Duval
15192e68ec1SJérôme Duval pthread_key_create(&self, NULL);
15292e68ec1SJérôme Duval
15392e68ec1SJérôme Duval pthread_attr_init(&attributes);
15492e68ec1SJérôme Duval pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
15592e68ec1SJérôme Duval
15692e68ec1SJérôme Duval for (int i = 0; i < 4; i++) {
157*921aaaa1SJérôme Duval if (pthread_create(&tid[i], &attributes, threadStart, &id[i]) != 0)
15892e68ec1SJérôme Duval fprintf(stderr, "couldn't create thread %d\n", i);
15992e68ec1SJérôme Duval printf("thread %d created\n", i);
16092e68ec1SJérôme Duval }
16192e68ec1SJérôme Duval
16292e68ec1SJérôme Duval /*suspendAllThreads();*/
16392e68ec1SJérôme Duval printf("snoozing\n");
164*921aaaa1SJérôme Duval usleep(3000000);
16592e68ec1SJérôme Duval printf("resuming all threads\n");
16692e68ec1SJérôme Duval resumeAllThreads();
16792e68ec1SJérôme Duval printf("resuming all threads done\n");
16892e68ec1SJérôme Duval }
169d13211acSJérôme Duval
170