xref: /haiku/src/tests/system/libroot/posix/pthread_signal_test.cpp (revision 921aaaa1edaf41421398a3c0f1340902755fa3ff)
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
suspendLoop(int * i)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
suspendHandler(int sig)40 suspendHandler(int sig) {
41 	int *i = (int*)pthread_getspecific(self);
42 	suspendLoop(i);
43 }
44 
45 
46 static void
initialiseSignals()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
self_suspend(int * i)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 *
threadStart(void * arg)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
resumeAllThreads()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
main(int argc,char ** argv)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