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
11static pthread_attr_t attributes;
12static int id[4] = {0, 1, 2, 3};
13static pthread_t tid[4];
14static bool	state[4];
15static bool blocking[4];
16static pthread_key_t self;
17
18
19static void
20suspendLoop(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
39static void
40suspendHandler(int sig) {
41	int *i = (int*)pthread_getspecific(self);
42	suspendLoop(i);
43}
44
45
46static void
47initialiseSignals()
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
65static void
66self_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
86void *
87threadStart(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
108suspendAllThreads()
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
125void
126resumeAllThreads()
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
146int
147main(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