1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29: # if defined(GC_IRIX_THREADS) || defined(GC_AIX_THREADS)
30:
31: # include "private/gc_priv.h"
32: # include <pthread.h>
33: # include <assert.h>
34: # include <semaphore.h>
35: # include <time.h>
36: # include <errno.h>
37: # include <unistd.h>
38: # include <sys/mman.h>
39: # include <sys/time.h>
40:
41: #undef pthread_create
42: #undef pthread_sigmask
43: #undef pthread_join
44:
45: #if defined(GC_IRIX_THREADS) && !defined(MUTEX_RECURSIVE_NP)
46: #define MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
47: #endif
48:
49: void GC_thr_init();
50:
51: #if 0
52: void GC_print_sig_mask()
53: {
54: sigset_t blocked;
55: int i;
56:
57: if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
58: ABORT("pthread_sigmask");
59: GC_printf0("Blocked: ");
60: for (i = 1; i <= MAXSIG; i++) {
61: if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
62: }
63: GC_printf0("\n");
64: }
65: #endif
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76: typedef struct GC_Thread_Rep {
77: struct GC_Thread_Rep * next;
78:
79:
80:
81:
82: pthread_t id;
83: word stop;
84: # define NOT_STOPPED 0
85: # define PLEASE_STOP 1
86: # define STOPPED 2
87: word flags;
88: # define FINISHED 1
89: # define DETACHED 2
90: ptr_t stack_cold;
91: ptr_t stack_hot;
92:
93:
94: void * status;
95:
96:
97: } * GC_thread;
98:
99: GC_thread GC_lookup_thread(pthread_t id);
100:
101:
102:
103:
104:
105:
106: #if 0
107: # if defined(GC_AIX_THREADS)
108: # define SIG_SUSPEND SIGUSR1
109: # else
110: # define SIG_SUSPEND (SIGRTMIN + 6)
111: # endif
112: #endif
113:
114: pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
115:
116: pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;
117: pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;
118:
119: void GC_suspend_handler(int sig)
120: {
121: int dummy;
122: GC_thread me;
123: sigset_t all_sigs;
124: sigset_t old_sigs;
125: int i;
126:
127: if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
128: me = GC_lookup_thread(pthread_self());
129:
130:
131:
132:
133: if (PLEASE_STOP != me -> stop) {
134:
135: pthread_mutex_unlock(&GC_suspend_lock);
136: return;
137: }
138: pthread_mutex_lock(&GC_suspend_lock);
139: me -> stack_hot = (ptr_t)(&dummy);
140: me -> stop = STOPPED;
141: pthread_cond_signal(&GC_suspend_ack_cv);
142: pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);
143: pthread_mutex_unlock(&GC_suspend_lock);
144:
145: }
146:
147:
148: GC_bool GC_thr_initialized = FALSE;
149:
150:
151: # define THREAD_TABLE_SZ 128
152: volatile GC_thread GC_threads[THREAD_TABLE_SZ];
153:
154: void GC_push_thread_structures GC_PROTO((void))
155: {
156: GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
157: }
158:
159:
160:
161: GC_thread GC_new_thread(pthread_t id)
162: {
163: int hv = ((word)id) % THREAD_TABLE_SZ;
164: GC_thread result;
165: static struct GC_Thread_Rep first_thread;
166: static GC_bool first_thread_used = FALSE;
167:
168: GC_ASSERT(I_HOLD_LOCK());
169: if (!first_thread_used) {
170: result = &first_thread;
171: first_thread_used = TRUE;
172:
173: } else {
174: result = (struct GC_Thread_Rep *)
175: GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
176: }
177: if (result == 0) return(0);
178: result -> id = id;
179: result -> next = GC_threads[hv];
180: GC_threads[hv] = result;
181:
182:
183: return(result);
184: }
185:
186:
187:
188:
189:
190:
191:
192:
193:
194: void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
195: {
196: int hv = ((word)id) % THREAD_TABLE_SZ;
197: register GC_thread p = GC_threads[hv];
198: register GC_thread prev = 0;
199:
200: GC_ASSERT(I_HOLD_LOCK());
201: while (p != gc_id) {
202: prev = p;
203: p = p -> next;
204: }
205: if (prev == 0) {
206: GC_threads[hv] = p -> next;
207: } else {
208: prev -> next = p -> next;
209: }
210: }
211:
212:
213:
214:
215:
216:
217:
218: GC_thread GC_lookup_thread(pthread_t id)
219: {
220: int hv = ((word)id) % THREAD_TABLE_SZ;
221: register GC_thread p = GC_threads[hv];
222:
223:
224:
225: #if defined(GC_AIX_THREADS)
226: GC_ASSERT(I_HOLD_LOCK());
227: #endif
228: while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
229: return(p);
230: }
231:
232: #if defined(GC_AIX_THREADS)
233: void GC_stop_world()
234: {
235: pthread_t my_thread = pthread_self();
236: register int i;
237: register GC_thread p;
238: register int result;
239: struct timespec timeout;
240:
241: GC_ASSERT(I_HOLD_LOCK());
242: for (i = 0; i < THREAD_TABLE_SZ; i++) {
243: for (p = GC_threads[i]; p != 0; p = p -> next) {
244: if (p -> id != my_thread) {
245: pthread_suspend_np(p->id);
246: }
247: }
248: }
249:
250: }
251:
252: void GC_start_world()
253: {
254: GC_thread p;
255: unsigned i;
256: pthread_t my_thread = pthread_self();
257:
258:
259: GC_ASSERT(I_HOLD_LOCK());
260: for (i = 0; i < THREAD_TABLE_SZ; i++) {
261: for (p = GC_threads[i]; p != 0; p = p -> next) {
262: if (p -> id != my_thread) {
263: pthread_continue_np(p->id);
264: }
265: }
266: }
267: }
268:
269: #else
270:
271:
272: void GC_stop_world()
273: {
274: pthread_t my_thread = pthread_self();
275: register int i;
276: register GC_thread p;
277: register int result;
278: struct timespec timeout;
279:
280: GC_ASSERT(I_HOLD_LOCK());
281: for (i = 0; i < THREAD_TABLE_SZ; i++) {
282: for (p = GC_threads[i]; p != 0; p = p -> next) {
283: if (p -> id != my_thread) {
284: if (p -> flags & FINISHED) {
285: p -> stop = STOPPED;
286: continue;
287: }
288: p -> stop = PLEASE_STOP;
289: result = pthread_kill(p -> id, SIG_SUSPEND);
290:
291: switch(result) {
292: case ESRCH:
293:
294: p -> stop = STOPPED;
295: break;
296: case 0:
297: break;
298: default:
299: ABORT("pthread_kill failed");
300: }
301: }
302: }
303: }
304: pthread_mutex_lock(&GC_suspend_lock);
305: for (i = 0; i < THREAD_TABLE_SZ; i++) {
306: for (p = GC_threads[i]; p != 0; p = p -> next) {
307: while (p -> id != my_thread && p -> stop != STOPPED) {
308: clock_gettime(CLOCK_REALTIME, &timeout);
309: timeout.tv_nsec += 50000000;
310: if (timeout.tv_nsec >= 1000000000) {
311: timeout.tv_nsec -= 1000000000;
312: ++timeout.tv_sec;
313: }
314: result = pthread_cond_timedwait(&GC_suspend_ack_cv,
315: &GC_suspend_lock,
316: &timeout);
317: if (result == ETIMEDOUT) {
318:
319:
320: result = pthread_kill(p -> id, SIG_SUSPEND);
321: }
322: }
323: }
324: }
325: pthread_mutex_unlock(&GC_suspend_lock);
326:
327: }
328:
329:
330: void GC_start_world()
331: {
332: GC_thread p;
333: unsigned i;
334:
335:
336: GC_ASSERT(I_HOLD_LOCK());
337: for (i = 0; i < THREAD_TABLE_SZ; i++) {
338: for (p = GC_threads[i]; p != 0; p = p -> next) {
339: p -> stop = NOT_STOPPED;
340: }
341: }
342: pthread_mutex_lock(&GC_suspend_lock);
343:
344:
345: pthread_mutex_unlock(&GC_suspend_lock);
346: pthread_cond_broadcast(&GC_continue_cv);
347: }
348:
349: #endif
350:
351:
352:
353:
354: void GC_push_all_stacks()
355: {
356: register int i;
357: register GC_thread p;
358: register ptr_t hot, cold;
359: pthread_t me = pthread_self();
360:
361:
362:
363:
364: GC_ASSERT(GC_thr_initialized);
365:
366:
367: GC_ASSERT(I_HOLD_LOCK());
368: for (i = 0; i < THREAD_TABLE_SZ; i++) {
369: for (p = GC_threads[i]; p != 0; p = p -> next) {
370: if (p -> flags & FINISHED) continue;
371: cold = p->stack_cold;
372: if (!cold) cold=GC_stackbottom;
373: if (pthread_equal(p -> id, me)) {
374: hot = GC_approx_sp();
375: } else {
376: # ifdef GC_AIX_THREADS
377:
378:
379:
380: pthread_t id = p -> id;
381: struct __pthrdsinfo pinfo;
382: int regbuf[64];
383: int val = sizeof(regbuf);
384: int retval = pthread_getthrds_np(&id, PTHRDSINFO_QUERY_ALL, &pinfo,
385: sizeof(pinfo), regbuf, &val);
386: if (retval != 0) {
387: printf("ERROR: pthread_getthrds_np() failed in GC\n");
388: abort();
389: }
390:
391:
392:
393:
394:
395:
396:
397: hot = (ptr_t)(unsigned long)pinfo.__pi_ustk-288;
398: cold = (ptr_t)pinfo.__pi_stackend;
399:
400: GC_push_all_eager((ptr_t)&pinfo.__pi_context,
401: (ptr_t)((&pinfo.__pi_context)+1));
402: GC_push_all_eager((ptr_t)regbuf, ((ptr_t)regbuf)+val);
403: # else
404: hot = p -> stack_hot;
405: # endif
406: }
407: # ifdef STACK_GROWS_UP
408: GC_push_all_stack(cold, hot);
409: # else
410:
411: GC_push_all_stack(hot, cold);
412: # endif
413: }
414: }
415: }
416:
417:
418:
419: void GC_thr_init()
420: {
421: GC_thread t;
422: struct sigaction act;
423:
424: if (GC_thr_initialized) return;
425: GC_ASSERT(I_HOLD_LOCK());
426: GC_thr_initialized = TRUE;
427: #ifndef GC_AIX_THREADS
428: (void) sigaction(SIG_SUSPEND, 0, &act);
429: if (act.sa_handler != SIG_DFL)
430: ABORT("Previously installed SIG_SUSPEND handler");
431:
432: act.sa_handler = GC_suspend_handler;
433: act.sa_flags = SA_RESTART;
434: (void) sigemptyset(&act.sa_mask);
435: if (0 != sigaction(SIG_SUSPEND, &act, 0))
436: ABORT("Failed to install SIG_SUSPEND handler");
437: #endif
438:
439: t = GC_new_thread(pthread_self());
440:
441:
442: t -> stack_cold = 0;
443: t -> stack_hot = (ptr_t)(&t);
444: t -> flags = DETACHED;
445: }
446:
447: int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
448: {
449: sigset_t fudged_set;
450:
451: #ifdef GC_AIX_THREADS
452: return(pthread_sigmask(how, set, oset));
453: #endif
454:
455: if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
456: fudged_set = *set;
457: sigdelset(&fudged_set, SIG_SUSPEND);
458: set = &fudged_set;
459: }
460: return(pthread_sigmask(how, set, oset));
461: }
462:
463: struct start_info {
464: void *(*start_routine)(void *);
465: void *arg;
466: word flags;
467: pthread_mutex_t registeredlock;
468: pthread_cond_t registered;
469: int volatile registereddone;
470: };
471:
472: void GC_thread_exit_proc(void *arg)
473: {
474: GC_thread me;
475:
476: LOCK();
477: me = GC_lookup_thread(pthread_self());
478: me -> flags |= FINISHED;
479:
480: if (me -> flags & DETACHED) {
481: GC_delete_gc_thread(pthread_self(), me);
482: }
483: UNLOCK();
484: }
485:
486: int GC_pthread_join(pthread_t thread, void **retval)
487: {
488: int result;
489: GC_thread thread_gc_id;
490:
491: LOCK();
492: thread_gc_id = GC_lookup_thread(thread);
493:
494:
495: UNLOCK();
496: GC_ASSERT(!(thread_gc_id->flags & DETACHED));
497: result = pthread_join(thread, retval);
498:
499:
500: if (EINTR == result) result = 0;
501: GC_ASSERT(thread_gc_id->flags & FINISHED);
502: LOCK();
503:
504: GC_delete_gc_thread(thread, thread_gc_id);
505: UNLOCK();
506: return result;
507: }
508:
509: void * GC_start_routine(void * arg)
510: {
511: int dummy;
512: struct start_info * si = arg;
513: void * result;
514: GC_thread me;
515: pthread_t my_pthread;
516: void *(*start)(void *);
517: void *start_arg;
518:
519: my_pthread = pthread_self();
520:
521:
522:
523:
524: LOCK();
525:
526:
527:
528:
529:
530:
531:
532: me = GC_new_thread(my_pthread);
533: me -> flags = si -> flags;
534: me -> stack_cold = (ptr_t) &dummy;
535: me -> stack_hot = me->stack_cold;
536: UNLOCK();
537: start = si -> start_routine;
538: start_arg = si -> arg;
539:
540: pthread_mutex_lock(&(si->registeredlock));
541: si->registereddone = 1;
542: pthread_cond_signal(&(si->registered));
543: pthread_mutex_unlock(&(si->registeredlock));
544:
545:
546: pthread_cleanup_push(GC_thread_exit_proc, 0);
547: result = (*start)(start_arg);
548: me