blob: 179dd947ee2f9cc2dc84903f7d5e3c3c81ded763 [file] [log] [blame]
fitzhardinge59cfddc2004-03-17 18:20:46 +00001/* JSGF: no idea what this is actually doing, but it really gives the
2 signals/sigaltstack/threads machinery a working out */
3/**
4 * Compile with:
5 * gcc -g -Wall -lpthread -o susphello susphello.c
6 *
7 * Author Magnus Ihse, ihse at bea.com
8 */
9
10#include <signal.h>
11
12
13#include <errno.h>
14#include <stddef.h>
15#include <pthread.h>
16#include <signal.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/resource.h>
20#include <unistd.h>
21#include <sys/syscall.h>
22#include <dlfcn.h>
23
24
25#include <pthread.h>
26#include <unistd.h>
27#include <string.h>
28#include <netdb.h>
29#include <stdio.h>
30#include <stdlib.h>
31
32#define THREAD_COUNT 10
33#define ITER_COUNT 200
34
35static volatile int finishedArray[THREAD_COUNT];
36static int pKey;
37
38static sigset_t srSigset;
39
40pthread_t main_thread;
41
42int srSignal = SIGUSR1;
43
44
45void
46ptiSrSigHandler(int sig, siginfo_t *sip, void *arg)
47{
48 //ucontext_t *ucontext = (ucontext_t *)arg;
49
50 int mypos = (int) pthread_getspecific(pKey);
51
52
53// int threadPos = (int)pthread_getspecific(srThreadKey);
54
55// thread->os_context = (OSContextP)&(ucontext->uc_mcontext);
56
57 // Notify suspender that we have been suspended
58 if (pthread_kill(main_thread, srSignal) == -1) {
59 perror("pthread_kill");
60 exit(1);
61 }
62
63 finishedArray[mypos]++;
64
65// printf("this is thread %d: i'm now suspended!\n", mypos);
66
67 // Wait until we are resumed
68 while (sigwaitinfo(&srSigset, NULL) == -1) {
69 // Interrupted by SIGSTOP in gdb
70 if(errno != EINTR) {
71 perror("sigwaitinfo");
72 exit(1);
73 }
74 }
75
76// printf("this is thread %d: i'm now resumed!\n", mypos);
77
78 //thread->os_context = NULL; // just for the sake of it...
79
80 // Notify resumer that we have been resumed
81 if (pthread_kill(main_thread, srSignal) == -1) {
82 perror("pthread_kill");
83 exit(1);
84 }
85// printf("this is thread %d: and I've told Master!!\n", mypos);
86
87}
88
89
90void
91suspendOrResume(pthread_t thread, int i)
92{
93 sigset_t oss;
94
95 // Mask out suspend/resume signal until we explicitly wait for it
96 sigprocmask(SIG_BLOCK, &srSigset, &oss);
97
98 // Send signal to suspend or resume the thread
99 if (pthread_kill(thread, srSignal) == -1) {
100 perror("pthread_kill");
101 exit(1);
102 }
103
104// printf("sent signal to %d...", i);
105 // Wait for notification from thread being suspended/resumed
106 while (sigwaitinfo(&srSigset, NULL) == -1) {
107 // Interrupted by SIGSTOP in gdb
108 if(errno != EINTR) {
109 perror("sigwaitinfo");
110 exit(1);
111 }
112 }
113
114 // Restore original signal mask
115 sigprocmask(SIG_SETMASK, &oss, NULL);
116
117// printf("... okay, %d suspended\n", i);
118}
119
120
121
122void
123initSignalling(void)
124{
125 struct sigaction sa;
126
127 // Signal mask for suspend/resume
128 sigemptyset(&srSigset);
129 sigaddset(&srSigset, srSignal);
130
131 // Set up signal handler for suspend/resume
132 sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
133 sa.sa_sigaction = ptiSrSigHandler;
134 sigfillset(&sa.sa_mask);
135 sigdelset(&sa.sa_mask, (__SIGRTMIN+1));
136 if (sigaction(srSignal, &sa, 0) == -1) {
137 perror("sigaction");
138 exit(1);
139 }
140
141 // Unblock suspend signal
142 sigprocmask(SIG_UNBLOCK, &srSigset, 0);
143
144 main_thread = pthread_self();
145}
146
147
148void* setup_altstack(void) {
149 stack_t ss;
150
151 ss.ss_sp = malloc(20*1024);
152 if (ss.ss_sp == 0) {
153 return NULL;
154 }
155 ss.ss_size = 20*1024;
156 ss.ss_flags = 0;
157
158 if (sigaltstack(&ss, NULL) == -1) {
159 perror("sigaltstack");
160 return NULL;
161 }
162 return ss.ss_sp;
163}
164
165void takedown_altstack(void* stack) {
166 struct sigaltstack ss;
167 int result;
168
169 ss.ss_flags = SS_DISABLE;
170 ss.ss_sp = (void*)47; // This value should be ignored when ss_flags is SS_DISABLE
171 ss.ss_size = 29; // This value should be ignored when ss_flags is SS_DISABLE
172
173 {
174 result = sigaltstack(&ss, NULL);
175 free(stack);
176 }
177}
178
179void *threadfunc(void *arg) {
180 int mypos = (int)arg;
181 int i;
182 long square = 1;
183 void* altstack = setup_altstack();
184
185 pthread_setspecific(pKey, arg);
186 for (i=0; i < 1000; i++) {
187 square = i*i + square*mypos;
188 }
189
190// wait for signal
191 while (finishedArray[mypos] == 0) {
192 struct timespec req, rem;
193
194 req.tv_sec = 0;
195 req.tv_nsec = 5 * 1000 * 1000;
196
197 nanosleep(&req, &rem);
198
199 };
200
201 finishedArray[mypos]++;
202
203 takedown_altstack(altstack);
204
205 return NULL;
206}
207
208
209int main(int argc, char ** argv) {
210 pthread_t threads[THREAD_COUNT];
211 pthread_attr_t attr;
212 int result;
213 int i;
214 int iteration;
215 int finished;
216
217 initSignalling();
218
219 pthread_attr_init(&attr);
220 pthread_attr_setstacksize(&attr, 128*1024);
221
222 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
223
224 pthread_key_create(&pKey, NULL);
225
226 for (iteration = 0; iteration < ITER_COUNT; iteration++) {
227#if 0
228 if ((iteration % 100) == 0) {
229 printf("\nStarting run series %i: ", iteration);
230 }
231
232 if ((iteration % 10) == 0) {
233 printf(".");
234 fflush(stdout);
235 }
236#endif
237
238 // Clear array
239 for (i = 0; i< THREAD_COUNT; i++) {
240 finishedArray[i] = 0;
241 }
242
243 // Start threads
244 for (i = 0; i< THREAD_COUNT; i++) {
245 result = pthread_create(&threads[i], &attr, threadfunc, (void*)i);
246 if (result != 0) {
247 perror("pthread_create");
248 exit(1);
249 }
250 }
251
252// printf("all threads started\n");
253 // suspend threads
254 for (i = 0; i< THREAD_COUNT; i++) {
255 suspendOrResume(threads[i], i);
256 }
257
258// printf("now all threads are suspended\n");
259
260 // resume threads
261 for (i = 0; i< THREAD_COUNT; i++) {
262 suspendOrResume(threads[i], i);
263 }
264
265
266 // Join threads
267/*
268 printf("about to join...");
269 for (i = 0; i< THREAD_COUNT; i++) {
270 result = pthread_join(threads[i], NULL);
271 if (result != 0) {
272 perror("pthread_join");
273 exit(1);
274 }
275 }
276
277 printf("...joined");
278*/
279// printf("Spin waiting for results\n");
280 finished = 1;
281 do {
282 struct timespec req, rem;
283
284 req.tv_sec = 0;
285 req.tv_nsec = 5 * 1000 * 1000;
286 finished = 1;
287
288 nanosleep(&req, &rem);
289
290// sleep(1);
291 for (i = 0; i< THREAD_COUNT; i++) {
292 if (finishedArray[i] < 2) {
293 finished = 0;
294// printf("no result at: %d, value: %d\n", i, finishedArray[i]);
295 break;
296 }
297 }
298// sleep(1);
299 } while (!finished);
300
301 }
302
303 printf("PASSED\n");
304 return 0;
305}