Annotation of OpenXM_contrib2/asir2000/gc/linux_threads.c, Revision 1.6
1.1 noro 1: /*
2: * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
3: * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
4: * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
1.4 noro 5: * Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
1.1 noro 6: *
7: * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8: * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9: *
10: * Permission is hereby granted to use or copy this program
11: * for any purpose, provided the above notices are retained on all copies.
12: * Permission to modify the code and to distribute modified code is granted,
13: * provided the above notices are retained, and a notice that the code was
14: * modified is included with the above copyright notice.
15: */
16: /*
17: * Support code for LinuxThreads, the clone()-based kernel
18: * thread package for Linux which is included in libc6.
19: *
20: * This code relies on implementation details of LinuxThreads,
1.4 noro 21: * (i.e. properties not guaranteed by the Pthread standard),
22: * though this version now does less of that than the other Pthreads
23: * support code.
1.1 noro 24: *
1.4 noro 25: * Note that there is a lot of code duplication between linux_threads.c
26: * and thread support for some of the other Posix platforms; any changes
27: * made here may need to be reflected there too.
28: */
1.6 ! noro 29: /* DG/UX ix86 support <takis@xfree86.org> */
1.4 noro 30: /*
31: * Linux_threads.c now also includes some code to support HPUX and
32: * OSF1 (Compaq Tru64 Unix, really). The OSF1 support is not yet
33: * functional. The OSF1 code is based on Eric Benson's
34: * patch, though that was originally against hpux_irix_threads. The code
35: * here is completely untested. With 0.0000001% probability, it might
36: * actually work.
1.1 noro 37: *
1.4 noro 38: * Eric also suggested an alternate basis for a lock implementation in
39: * his code:
40: * + #elif defined(OSF1)
41: * + unsigned long GC_allocate_lock = 0;
42: * + msemaphore GC_allocate_semaphore;
43: * + # define GC_TRY_LOCK() \
44: * + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
45: * + ? (GC_allocate_lock = 1) \
46: * + : 0)
47: * + # define GC_LOCK_TAKEN GC_allocate_lock
1.1 noro 48: */
49:
50: /* #define DEBUG_THREADS 1 */
51:
52: /* ANSI C requires that a compilation unit contains something */
53:
1.6 ! noro 54: # include "gc.h"
! 55:
! 56: # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
! 57: && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
1.4 noro 58:
59: # include "private/gc_priv.h"
1.6 ! noro 60:
! 61: # if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
! 62: && !defined(USE_HPUX_TLS)
! 63: # define USE_HPUX_TLS
! 64: # endif
! 65:
! 66: # if defined(GC_DGUX386_THREADS) && !defined(USE_PTHREAD_SPECIFIC)
! 67: # define USE_PTHREAD_SPECIFIC
! 68: # endif
! 69:
! 70: # if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
! 71: # define _POSIX4A_DRAFT10_SOURCE 1
! 72: # endif
! 73:
! 74: # if defined(GC_DGUX386_THREADS) && !defined(_USING_POSIX4A_DRAFT10)
! 75: # define _USING_POSIX4A_DRAFT10 1
! 76: # endif
! 77:
1.4 noro 78: # ifdef THREAD_LOCAL_ALLOC
79: # if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS)
80: # include "private/specific.h"
81: # endif
82: # if defined(USE_PTHREAD_SPECIFIC)
83: # define GC_getspecific pthread_getspecific
84: # define GC_setspecific pthread_setspecific
85: # define GC_key_create pthread_key_create
86: typedef pthread_key_t GC_key_t;
87: # endif
88: # if defined(USE_HPUX_TLS)
89: # define GC_getspecific(x) (x)
90: # define GC_setspecific(key, v) ((key) = (v), 0)
91: # define GC_key_create(key, d) 0
92: typedef void * GC_key_t;
93: # endif
94: # endif
95: # include <stdlib.h>
1.1 noro 96: # include <pthread.h>
1.3 noro 97: # include <sched.h>
1.1 noro 98: # include <time.h>
99: # include <errno.h>
100: # include <unistd.h>
101: # include <sys/mman.h>
102: # include <sys/time.h>
103: # include <semaphore.h>
1.3 noro 104: # include <signal.h>
1.4 noro 105: # include <sys/types.h>
106: # include <sys/stat.h>
107: # include <fcntl.h>
1.3 noro 108:
1.6 ! noro 109: #if defined(GC_DGUX386_THREADS)
! 110: # include <sys/dg_sys_info.h>
! 111: # include <sys/_int_psem.h>
! 112: /* sem_t is an uint in DG/UX */
! 113: typedef unsigned int sem_t;
! 114: #endif /* GC_DGUX386_THREADS */
! 115:
1.4 noro 116: #ifndef __GNUC__
117: # define __inline__
118: #endif
119:
120: #ifdef GC_USE_LD_WRAP
1.3 noro 121: # define WRAP_FUNC(f) __wrap_##f
122: # define REAL_FUNC(f) __real_##f
123: #else
124: # define WRAP_FUNC(f) GC_##f
1.6 ! noro 125: # if !defined(GC_DGUX386_THREADS)
! 126: # define REAL_FUNC(f) f
! 127: # else /* GC_DGUX386_THREADS */
! 128: # define REAL_FUNC(f) __d10_##f
! 129: # endif /* GC_DGUX386_THREADS */
1.3 noro 130: # undef pthread_create
131: # undef pthread_sigmask
132: # undef pthread_join
1.4 noro 133: # undef pthread_detach
1.3 noro 134: #endif
1.1 noro 135:
136:
137: void GC_thr_init();
138:
139: #if 0
140: void GC_print_sig_mask()
141: {
142: sigset_t blocked;
143: int i;
144:
145: if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
146: ABORT("pthread_sigmask");
147: GC_printf0("Blocked: ");
148: for (i = 1; i <= MAXSIG; i++) {
149: if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
150: }
151: GC_printf0("\n");
152: }
153: #endif
154:
1.4 noro 155:
1.1 noro 156: /* We use the allocation lock to protect thread-related data structures. */
157:
158: /* The set of all known threads. We intercept thread creation and */
1.4 noro 159: /* joins. */
160: /* Protected by allocation/GC lock. */
161: /* Some of this should be declared volatile, but that's inconsistent */
1.1 noro 162: /* with some library routine declarations. */
163: typedef struct GC_Thread_Rep {
164: struct GC_Thread_Rep * next; /* More recently allocated threads */
165: /* with a given pthread id come */
166: /* first. (All but the first are */
167: /* guaranteed to be dead, but we may */
168: /* not yet have registered the join.) */
169: pthread_t id;
1.4 noro 170: short flags;
1.1 noro 171: # define FINISHED 1 /* Thread has exited. */
172: # define DETACHED 2 /* Thread is intended to be detached. */
173: # define MAIN_THREAD 4 /* True for the original thread only. */
1.4 noro 174: short thread_blocked; /* Protected by GC lock. */
175: /* Treated as a boolean value. If set, */
176: /* thread will acquire GC lock before */
177: /* doing any pointer manipulations, and */
178: /* has set its sp value. Thus it does */
179: /* not need to be sent a signal to stop */
180: /* it. */
1.3 noro 181: ptr_t stack_end; /* Cold end of the stack. */
182: ptr_t stack_ptr; /* Valid only when stopped. */
183: # ifdef IA64
184: ptr_t backing_store_end;
185: ptr_t backing_store_ptr;
186: # endif
1.1 noro 187: int signal;
188: void * status; /* The value returned from the thread. */
189: /* Used only to avoid premature */
190: /* reclamation of any data it might */
191: /* reference. */
1.4 noro 192: # ifdef THREAD_LOCAL_ALLOC
193: # if CPP_WORDSZ == 64 && defined(ALIGN_DOUBLE)
194: # define GRANULARITY 16
1.6 ! noro 195: # define NFREELISTS 49
1.4 noro 196: # else
197: # define GRANULARITY 8
1.6 ! noro 198: # define NFREELISTS 65
1.4 noro 199: # endif
1.6 ! noro 200: /* The ith free list corresponds to size i*GRANULARITY */
! 201: # define INDEX_FROM_BYTES(n) ((ADD_SLOP(n) + GRANULARITY - 1)/GRANULARITY)
! 202: # define BYTES_FROM_INDEX(i) ((i) * GRANULARITY - EXTRA_BYTES)
! 203: # define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= \
! 204: (NFREELISTS-1)*GRANULARITY)
1.4 noro 205: ptr_t ptrfree_freelists[NFREELISTS];
206: ptr_t normal_freelists[NFREELISTS];
207: # ifdef GC_GCJ_SUPPORT
208: ptr_t gcj_freelists[NFREELISTS];
209: # endif
210: /* Free lists contain either a pointer or a small count */
211: /* reflecting the number of granules allocated at that */
212: /* size. */
213: /* 0 ==> thread-local allocation in use, free list */
214: /* empty. */
215: /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
216: /* too few objects of this size have been */
217: /* allocated by this thread. */
218: /* >= HBLKSIZE => pointer to nonempty free list. */
219: /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
220: /* local alloc, equivalent to 0. */
221: # define DIRECT_GRANULES (HBLKSIZE/GRANULARITY)
222: /* Don't use local free lists for up to this much */
223: /* allocation. */
224: # endif
1.1 noro 225: } * GC_thread;
226:
227: GC_thread GC_lookup_thread(pthread_t id);
228:
1.6 ! noro 229: static GC_bool parallel_initialized = FALSE;
1.4 noro 230:
1.6 ! noro 231: void GC_init_parallel();
1.4 noro 232:
233: # if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
234:
235: /* We don't really support thread-local allocation with DBG_HDRS_ALL */
236:
237: #ifdef USE_HPUX_TLS
238: __thread
239: #endif
240: GC_key_t GC_thread_key;
241:
242: static GC_bool keys_initialized;
243:
244: /* Recover the contents of the freelist array fl into the global one gfl.*/
245: /* Note that the indexing scheme differs, in that gfl has finer size */
246: /* resolution, even if not all entries are used. */
247: /* We hold the allocator lock. */
248: static void return_freelists(ptr_t *fl, ptr_t *gfl)
249: {
250: int i;
251: ptr_t q, *qptr;
252: size_t nwords;
253:
1.6 ! noro 254: for (i = 1; i < NFREELISTS; ++i) {
! 255: nwords = i * (GRANULARITY/sizeof(word));
1.4 noro 256: qptr = fl + i;
257: q = *qptr;
1.6 ! noro 258: if ((word)q >= HBLKSIZE) {
! 259: if (gfl[nwords] == 0) {
1.4 noro 260: gfl[nwords] = q;
1.6 ! noro 261: } else {
1.4 noro 262: /* Concatenate: */
263: for (; (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
264: GC_ASSERT(0 == q);
265: *qptr = gfl[nwords];
266: gfl[nwords] = fl[i];
1.6 ! noro 267: }
1.4 noro 268: }
269: /* Clear fl[i], since the thread structure may hang around. */
270: /* Do it in a way that is likely to trap if we access it. */
271: fl[i] = (ptr_t)HBLKSIZE;
272: }
273: }
274:
1.6 ! noro 275: /* We statically allocate a single "size 0" object. It is linked to */
! 276: /* itself, and is thus repeatedly reused for all size 0 allocation */
! 277: /* requests. (Size 0 gcj allocation requests are incorrect, and */
! 278: /* we arrange for those to fault asap.) */
! 279: static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
! 280:
1.4 noro 281: /* Each thread structure must be initialized. */
282: /* This call must be made from the new thread. */
283: /* Caller holds allocation lock. */
284: void GC_init_thread_local(GC_thread p)
285: {
286: int i;
287:
288: if (!keys_initialized) {
289: if (0 != GC_key_create(&GC_thread_key, 0)) {
290: ABORT("Failed to create key for local allocator");
291: }
292: keys_initialized = TRUE;
293: }
294: if (0 != GC_setspecific(GC_thread_key, p)) {
295: ABORT("Failed to set thread specific allocation pointers");
296: }
1.6 ! noro 297: for (i = 1; i < NFREELISTS; ++i) {
1.4 noro 298: p -> ptrfree_freelists[i] = (ptr_t)1;
299: p -> normal_freelists[i] = (ptr_t)1;
300: # ifdef GC_GCJ_SUPPORT
301: p -> gcj_freelists[i] = (ptr_t)1;
302: # endif
303: }
1.6 ! noro 304: /* Set up the size 0 free lists. */
! 305: p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object);
! 306: p -> normal_freelists[0] = (ptr_t)(&size_zero_object);
! 307: # ifdef GC_GCJ_SUPPORT
! 308: p -> gcj_freelists[0] = (ptr_t)(-1);
! 309: # endif
1.4 noro 310: }
311:
312: #ifdef GC_GCJ_SUPPORT
313: extern ptr_t * GC_gcjobjfreelist;
314: #endif
315:
316: /* We hold the allocator lock. */
317: void GC_destroy_thread_local(GC_thread p)
318: {
1.6 ! noro 319: /* We currently only do this from the thread itself or from */
! 320: /* the fork handler for a child process. */
! 321: # ifndef HANDLE_FORK
! 322: GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
! 323: # endif
1.4 noro 324: return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
325: return_freelists(p -> normal_freelists, GC_objfreelist);
326: # ifdef GC_GCJ_SUPPORT
327: return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
328: # endif
329: }
330:
331: extern GC_PTR GC_generic_malloc_many();
332:
333: GC_PTR GC_local_malloc(size_t bytes)
334: {
335: if (EXPECT(!SMALL_ENOUGH(bytes),0)) {
336: return(GC_malloc(bytes));
337: } else {
338: int index = INDEX_FROM_BYTES(bytes);
339: ptr_t * my_fl;
340: ptr_t my_entry;
341: GC_key_t k = GC_thread_key;
342: void * tsd;
343:
1.6 ! noro 344: # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
1.4 noro 345: if (EXPECT(0 == k, 0)) {
346: /* This can happen if we get called when the world is */
347: /* being initialized. Whether we can actually complete */
348: /* the initialization then is unclear. */
1.6 ! noro 349: GC_init_parallel();
1.4 noro 350: k = GC_thread_key;
351: }
352: # endif
353: tsd = GC_getspecific(GC_thread_key);
354: # ifdef GC_ASSERTIONS
355: LOCK();
356: GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self()));
357: UNLOCK();
358: # endif
359: my_fl = ((GC_thread)tsd) -> normal_freelists + index;
360: my_entry = *my_fl;
361: if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
362: ptr_t next = obj_link(my_entry);
363: GC_PTR result = (GC_PTR)my_entry;
364: *my_fl = next;
365: obj_link(my_entry) = 0;
366: PREFETCH_FOR_WRITE(next);
367: return result;
368: } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
369: *my_fl = my_entry + index + 1;
370: return GC_malloc(bytes);
371: } else {
1.6 ! noro 372: GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl);
! 373: if (*my_fl == 0) return GC_oom_fn(bytes);
1.4 noro 374: return GC_local_malloc(bytes);
375: }
376: }
377: }
378:
379: GC_PTR GC_local_malloc_atomic(size_t bytes)
380: {
381: if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
382: return(GC_malloc_atomic(bytes));
383: } else {
384: int index = INDEX_FROM_BYTES(bytes);
385: ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
386: -> ptrfree_freelists + index;
387: ptr_t my_entry = *my_fl;
388: if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
389: GC_PTR result = (GC_PTR)my_entry;
390: *my_fl = obj_link(my_entry);
391: return result;
392: } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
393: *my_fl = my_entry + index + 1;
394: return GC_malloc_atomic(bytes);
395: } else {
1.6 ! noro 396: GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl);
! 397: /* *my_fl is updated while the collector is excluded; */
! 398: /* the free list is always visible to the collector as */
! 399: /* such. */
! 400: if (*my_fl == 0) return GC_oom_fn(bytes);
1.4 noro 401: return GC_local_malloc_atomic(bytes);
402: }
403: }
404: }
405:
406: #ifdef GC_GCJ_SUPPORT
407:
408: #include "include/gc_gcj.h"
409:
410: #ifdef GC_ASSERTIONS
411: extern GC_bool GC_gcj_malloc_initialized;
412: #endif
413:
414: extern int GC_gcj_kind;
415:
416: GC_PTR GC_local_gcj_malloc(size_t bytes,
417: void * ptr_to_struct_containing_descr)
418: {
419: GC_ASSERT(GC_gcj_malloc_initialized);
420: if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
421: return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
422: } else {
423: int index = INDEX_FROM_BYTES(bytes);
424: ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
425: -> gcj_freelists + index;
426: ptr_t my_entry = *my_fl;
427: if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
428: GC_PTR result = (GC_PTR)my_entry;
429: GC_ASSERT(!GC_incremental);
430: /* We assert that any concurrent marker will stop us. */
431: /* Thus it is impossible for a mark procedure to see the */
432: /* allocation of the next object, but to see this object */
433: /* still containing a free list pointer. Otherwise the */
434: /* marker might find a random "mark descriptor". */
1.6 ! noro 435: *(volatile ptr_t *)my_fl = obj_link(my_entry);
! 436: /* We must update the freelist before we store the pointer. */
! 437: /* Otherwise a GC at this point would see a corrupted */
! 438: /* free list. */
! 439: /* A memory barrier is probably never needed, since the */
! 440: /* action of stopping this thread will cause prior writes */
! 441: /* to complete. */
! 442: GC_ASSERT(((void * volatile *)result)[1] == 0);
! 443: *(void * volatile *)result = ptr_to_struct_containing_descr;
1.4 noro 444: return result;
445: } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
1.6 ! noro 446: if (!GC_incremental) *my_fl = my_entry + index + 1;
! 447: /* In the incremental case, we always have to take this */
! 448: /* path. Thus we leave the counter alone. */
1.4 noro 449: return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
450: } else {
1.6 ! noro 451: GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl);
! 452: if (*my_fl == 0) return GC_oom_fn(bytes);
! 453: return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr);
1.4 noro 454: }
455: }
456: }
457:
458: #endif /* GC_GCJ_SUPPORT */
459:
460: # else /* !THREAD_LOCAL_ALLOC && !DBG_HDRS_ALL */
461:
462: # define GC_destroy_thread_local(t)
463:
464: # endif /* !THREAD_LOCAL_ALLOC */
465:
1.1 noro 466: /*
1.6 ! noro 467: * We use signals to stop threads during GC.
! 468: *
! 469: * Suspended threads wait in signal handler for SIG_THR_RESTART.
! 470: * That's more portable than semaphores or condition variables.
! 471: * (We do use sem_post from a signal handler, but that should be portable.)
! 472: *
! 473: * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
! 474: * Note that we can't just stop a thread; we need it to save its stack
! 475: * pointer(s) and acknowledge.
1.1 noro 476: */
477:
1.4 noro 478: #ifndef SIG_THR_RESTART
1.6 ! noro 479: # if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
1.4 noro 480: # define SIG_THR_RESTART _SIGRTMIN + 5
481: # else
482: # define SIG_THR_RESTART SIGXCPU
483: # endif
484: #endif
485:
1.1 noro 486: sem_t GC_suspend_ack_sem;
487:
1.6 ! noro 488: #if 0
1.1 noro 489: /*
490: To make sure that we're using LinuxThreads and not some other thread
1.2 noro 491: package, we generate a dummy reference to `pthread_kill_other_threads_np'
1.1 noro 492: (was `__pthread_initial_thread_bos' but that disappeared),
493: which is a symbol defined in LinuxThreads, but (hopefully) not in other
494: thread packages.
1.6 ! noro 495:
! 496: We no longer do this, since this code is now portable enough that it might
! 497: actually work for something else.
1.1 noro 498: */
1.2 noro 499: void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
1.6 ! noro 500: #endif /* 0 */
1.4 noro 501:
502: #if defined(SPARC) || defined(IA64)
503: extern word GC_save_regs_in_stack();
504: #endif
505:
506: long GC_nprocs = 1; /* Number of processors. We may not have */
507: /* access to all of them, but this is as good */
508: /* a guess as any ... */
509:
510: #ifdef PARALLEL_MARK
511:
512: # ifndef MAX_MARKERS
513: # define MAX_MARKERS 16
514: # endif
515:
516: static ptr_t marker_sp[MAX_MARKERS] = {0};
517:
518: void * GC_mark_thread(void * id)
519: {
520: word my_mark_no = 0;
521:
522: marker_sp[(word)id] = GC_approx_sp();
523: for (;; ++my_mark_no) {
524: /* GC_mark_no is passed only to allow GC_help_marker to terminate */
525: /* promptly. This is important if it were called from the signal */
526: /* handler or from the GC lock acquisition code. Under Linux, it's */
527: /* not safe to call it from a signal handler, since it uses mutexes */
528: /* and condition variables. Since it is called only here, the */
529: /* argument is unnecessary. */
530: if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
531: /* resynchronize if we get far off, e.g. because GC_mark_no */
532: /* wrapped. */
533: my_mark_no = GC_mark_no;
534: }
535: # ifdef DEBUG_THREADS
536: GC_printf1("Starting mark helper for mark number %ld\n", my_mark_no);
537: # endif
538: GC_help_marker(my_mark_no);
539: }
540: }
541:
542: extern long GC_markers; /* Number of mark threads we would */
543: /* like to have. Includes the */
544: /* initiating thread. */
545:
546: pthread_t GC_mark_threads[MAX_MARKERS];
547:
548: #define PTHREAD_CREATE REAL_FUNC(pthread_create)
549:
550: static void start_mark_threads()
551: {
552: unsigned i;
553: pthread_attr_t attr;
554:
555: if (GC_markers > MAX_MARKERS) {
556: WARN("Limiting number of mark threads\n", 0);
557: GC_markers = MAX_MARKERS;
558: }
559: if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
560:
561: if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
562: ABORT("pthread_attr_setdetachstate failed");
1.6 ! noro 563:
! 564: # if defined(HPUX) || defined(GC_DGUX386_THREADS)
! 565: /* Default stack size is usually too small: fix it. */
! 566: /* Otherwise marker threads or GC may run out of */
! 567: /* space. */
! 568: # define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
! 569: {
! 570: size_t old_size;
! 571: int code;
! 572:
! 573: if (pthread_attr_getstacksize(&attr, &old_size) != 0)
! 574: ABORT("pthread_attr_getstacksize failed\n");
! 575: if (old_size < MIN_STACK_SIZE) {
! 576: if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
! 577: ABORT("pthread_attr_setstacksize failed\n");
! 578: }
! 579: }
! 580: # endif /* HPUX || GC_DGUX386_THREADS */
1.4 noro 581: # ifdef CONDPRINT
582: if (GC_print_stats) {
583: GC_printf1("Starting %ld marker threads\n", GC_markers - 1);
584: }
585: # endif
586: for (i = 0; i < GC_markers - 1; ++i) {
587: if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
588: GC_mark_thread, (void *)(word)i)) {
589: WARN("Marker thread creation failed, errno = %ld.\n", errno);
590: }
591: }
592: }
1.1 noro 593:
1.4 noro 594: #else /* !PARALLEL_MARK */
1.1 noro 595:
1.4 noro 596: static __inline__ void start_mark_threads()
1.1 noro 597: {
598: }
599:
1.4 noro 600: #endif /* !PARALLEL_MARK */
1.3 noro 601:
1.1 noro 602: void GC_suspend_handler(int sig)
603: {
604: int dummy;
605: pthread_t my_thread = pthread_self();
606: GC_thread me;
607: sigset_t all_sigs;
608: sigset_t old_sigs;
609: int i;
610: sigset_t mask;
1.4 noro 611: # ifdef PARALLEL_MARK
612: word my_mark_no = GC_mark_no;
613: /* Marker can't proceed until we acknowledge. Thus this is */
614: /* guaranteed to be the mark_no correspending to our */
615: /* suspension, i.e. the marker can't have incremented it yet. */
616: # endif
1.1 noro 617:
618: if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
619:
620: #if DEBUG_THREADS
621: GC_printf1("Suspending 0x%x\n", my_thread);
622: #endif
623:
624: me = GC_lookup_thread(my_thread);
625: /* The lookup here is safe, since I'm doing this on behalf */
626: /* of a thread which holds the allocation lock in order */
627: /* to stop the world. Thus concurrent modification of the */
628: /* data structure is impossible. */
1.4 noro 629: # ifdef SPARC
630: me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
631: # else
632: me -> stack_ptr = (ptr_t)(&dummy);
633: # endif
1.3 noro 634: # ifdef IA64
635: me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
636: # endif
1.1 noro 637:
638: /* Tell the thread that wants to stop the world that this */
639: /* thread has been stopped. Note that sem_post() is */
640: /* the only async-signal-safe primitive in LinuxThreads. */
641: sem_post(&GC_suspend_ack_sem);
642:
643: /* Wait until that thread tells us to restart by sending */
1.4 noro 644: /* this thread a SIG_THR_RESTART signal. */
645: /* SIG_THR_RESTART should be masked at this point. Thus there */
1.1 noro 646: /* is no race. */
647: if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");
1.4 noro 648: if (sigdelset(&mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed");
1.3 noro 649: # ifdef NO_SIGNALS
650: if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed");
651: if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed");
652: if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed");
1.4 noro 653: if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed");
1.3 noro 654: # endif
1.1 noro 655: do {
656: me->signal = 0;
657: sigsuspend(&mask); /* Wait for signal */
1.4 noro 658: } while (me->signal != SIG_THR_RESTART);
1.1 noro 659:
660: #if DEBUG_THREADS
661: GC_printf1("Continuing 0x%x\n", my_thread);
662: #endif
663: }
664:
665: void GC_restart_handler(int sig)
666: {
667: GC_thread me;
668:
1.4 noro 669: if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
1.1 noro 670:
1.4 noro 671: /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
1.1 noro 672: /* The lookup here is safe, since I'm doing this on behalf */
673: /* of a thread which holds the allocation lock in order */
674: /* to stop the world. Thus concurrent modification of the */
675: /* data structure is impossible. */
676: me = GC_lookup_thread(pthread_self());
1.4 noro 677: me->signal = SIG_THR_RESTART;
1.1 noro 678:
679: /*
680: ** Note: even if we didn't do anything useful here,
681: ** it would still be necessary to have a signal handler,
682: ** rather than ignoring the signals, otherwise
683: ** the signals will not be delivered at all, and
684: ** will thus not interrupt the sigsuspend() above.
685: */
686:
687: #if DEBUG_THREADS
688: GC_printf1("In GC_restart_handler for 0x%x\n", pthread_self());
689: #endif
690: }
691:
1.4 noro 692: /* Defining INSTALL_LOOPING_SEGV_HANDLER causes SIGSEGV and SIGBUS to */
693: /* result in an infinite loop in a signal handler. This can be very */
694: /* useful for debugging, since (as of RH7) gdb still seems to have */
695: /* serious problems with threads. */
696: #ifdef INSTALL_LOOPING_SEGV_HANDLER
697: void GC_looping_handler(int sig)
698: {
699: GC_printf3("Signal %ld in thread %lx, pid %ld\n",
700: sig, pthread_self(), getpid());
701: for (;;);
702: }
703: #endif
704:
1.1 noro 705: GC_bool GC_thr_initialized = FALSE;
706:
707: # define THREAD_TABLE_SZ 128 /* Must be power of 2 */
708: volatile GC_thread GC_threads[THREAD_TABLE_SZ];
709:
1.4 noro 710: void GC_push_thread_structures GC_PROTO((void))
711: {
712: GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
713: }
714:
1.6 ! noro 715: #ifdef THREAD_LOCAL_ALLOC
! 716: /* We must explicitly mark ptrfree and gcj free lists, since the free */
! 717: /* list links wouldn't otherwise be found. We also set them in the */
! 718: /* normal free lists, since that involves touching less memory than if */
! 719: /* we scanned them normally. */
! 720: void GC_mark_thread_local_free_lists(void)
! 721: {
! 722: int i, j;
! 723: GC_thread p;
! 724: ptr_t q;
! 725:
! 726: for (i = 0; i < THREAD_TABLE_SZ; ++i) {
! 727: for (p = GC_threads[i]; 0 != p; p = p -> next) {
! 728: for (j = 1; j < NFREELISTS; ++j) {
! 729: q = p -> ptrfree_freelists[j];
! 730: if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
! 731: q = p -> normal_freelists[j];
! 732: if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
! 733: # ifdef GC_GCJ_SUPPORT
! 734: q = p -> gcj_freelists[j];
! 735: if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
! 736: # endif /* GC_GCJ_SUPPORT */
! 737: }
! 738: }
! 739: }
! 740: }
! 741: #endif /* THREAD_LOCAL_ALLOC */
! 742:
! 743: static struct GC_Thread_Rep first_thread;
! 744:
1.1 noro 745: /* Add a thread to GC_threads. We assume it wasn't already there. */
746: /* Caller holds allocation lock. */
747: GC_thread GC_new_thread(pthread_t id)
748: {
749: int hv = ((word)id) % THREAD_TABLE_SZ;
750: GC_thread result;
751: static GC_bool first_thread_used = FALSE;
752:
753: if (!first_thread_used) {
754: result = &first_thread;
755: first_thread_used = TRUE;
756: } else {
757: result = (struct GC_Thread_Rep *)
1.4 noro 758: GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
1.1 noro 759: }
760: if (result == 0) return(0);
761: result -> id = id;
762: result -> next = GC_threads[hv];
763: GC_threads[hv] = result;
1.4 noro 764: GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
1.1 noro 765: return(result);
766: }
767:
768: /* Delete a thread from GC_threads. We assume it is there. */
769: /* (The code intentionally traps if it wasn't.) */
770: /* Caller holds allocation lock. */
771: void GC_delete_thread(pthread_t id)
772: {
773: int hv = ((word)id) % THREAD_TABLE_SZ;
774: register GC_thread p = GC_threads[hv];
775: register GC_thread prev = 0;
776:
777: while (!pthread_equal(p -> id, id)) {
778: prev = p;
779: p = p -> next;
780: }
781: if (prev == 0) {
782: GC_threads[hv] = p -> next;
783: } else {
784: prev -> next = p -> next;
785: }
1.4 noro 786: GC_INTERNAL_FREE(p);
1.1 noro 787: }
788:
789: /* If a thread has been joined, but we have not yet */
790: /* been notified, then there may be more than one thread */
791: /* in the table with the same pthread id. */
792: /* This is OK, but we need a way to delete a specific one. */
793: void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
794: {
795: int hv = ((word)id) % THREAD_TABLE_SZ;
796: register GC_thread p = GC_threads[hv];
797: register GC_thread prev = 0;
798:
799: while (p != gc_id) {
800: prev = p;
801: p = p -> next;
802: }
803: if (prev == 0) {
804: GC_threads[hv] = p -> next;
805: } else {
806: prev -> next = p -> next;
807: }
1.4 noro 808: GC_INTERNAL_FREE(p);
1.1 noro 809: }
810:
811: /* Return a GC_thread corresponding to a given thread_t. */
812: /* Returns 0 if it's not there. */
813: /* Caller holds allocation lock or otherwise inhibits */
814: /* updates. */
815: /* If there is more than one thread with the given id we */
816: /* return the most recent one. */
817: GC_thread GC_lookup_thread(pthread_t id)
818: {
819: int hv = ((word)id) % THREAD_TABLE_SZ;
820: register GC_thread p = GC_threads[hv];
821:
822: while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
823: return(p);
824: }
825:
1.6 ! noro 826: #ifdef HANDLE_FORK
! 827: /* Remove all entries from the GC_threads table, except the */
! 828: /* one for the current thread. We need to do this in the child */
! 829: /* process after a fork(), since only the current thread */
! 830: /* survives in the child. */
! 831: void GC_remove_all_threads_but_me(void)
! 832: {
! 833: pthread_t self = pthread_self();
! 834: int hv;
! 835: GC_thread p, next, me;
! 836:
! 837: for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
! 838: me = 0;
! 839: for (p = GC_threads[hv]; 0 != p; p = next) {
! 840: next = p -> next;
! 841: if (p -> id == self) {
! 842: me = p;
! 843: p -> next = 0;
! 844: } else {
! 845: # ifdef THREAD_LOCAL_ALLOC
! 846: if (!(p -> flags & FINISHED)) {
! 847: GC_destroy_thread_local(p);
! 848: }
! 849: # endif /* THREAD_LOCAL_ALLOC */
! 850: if (p != &first_thread) GC_INTERNAL_FREE(p);
! 851: }
! 852: }
! 853: GC_threads[hv] = me;
! 854: }
! 855: }
! 856: #endif /* HANDLE_FORK */
! 857:
! 858: /* There seems to be a very rare thread stopping problem. To help us */
! 859: /* debug that, we save the ids of the stopping thread. */
! 860: pthread_t GC_stopping_thread;
! 861: int GC_stopping_pid;
! 862:
1.1 noro 863: /* Caller holds allocation lock. */
864: void GC_stop_world()
865: {
866: pthread_t my_thread = pthread_self();
867: register int i;
868: register GC_thread p;
869: register int n_live_threads = 0;
870: register int result;
871:
1.6 ! noro 872: GC_stopping_thread = my_thread; /* debugging only. */
! 873: GC_stopping_pid = getpid(); /* debugging only. */
1.4 noro 874: /* Make sure all free list construction has stopped before we start. */
875: /* No new construction can start, since free list construction is */
876: /* required to acquire and release the GC lock before it starts, */
877: /* and we have the lock. */
878: # ifdef PARALLEL_MARK
879: GC_acquire_mark_lock();
880: GC_ASSERT(GC_fl_builder_count == 0);
881: /* We should have previously waited for it to become zero. */
882: # endif /* PARALLEL_MARK */
1.1 noro 883: for (i = 0; i < THREAD_TABLE_SZ; i++) {
884: for (p = GC_threads[i]; p != 0; p = p -> next) {
885: if (p -> id != my_thread) {
886: if (p -> flags & FINISHED) continue;
1.4 noro 887: if (p -> thread_blocked) /* Will wait */ continue;
1.1 noro 888: n_live_threads++;
889: #if DEBUG_THREADS
890: GC_printf1("Sending suspend signal to 0x%x\n", p -> id);
891: #endif
892: result = pthread_kill(p -> id, SIG_SUSPEND);
893: switch(result) {
894: case ESRCH:
895: /* Not really there anymore. Possible? */
896: n_live_threads--;
897: break;
898: case 0:
899: break;
900: default:
901: ABORT("pthread_kill failed");
902: }
903: }
904: }
905: }
906: for (i = 0; i < n_live_threads; i++) {
1.4 noro 907: if (0 != sem_wait(&GC_suspend_ack_sem))
908: ABORT("sem_wait in handler failed");
1.1 noro 909: }
1.4 noro 910: # ifdef PARALLEL_MARK
911: GC_release_mark_lock();
912: # endif
1.1 noro 913: #if DEBUG_THREADS
1.4 noro 914: GC_printf1("World stopped 0x%x\n", pthread_self());
1.1 noro 915: #endif
1.6 ! noro 916: GC_stopping_thread = 0; /* debugging only */
1.1 noro 917: }
918:
1.4 noro 919: /* Caller holds allocation lock, and has held it continuously since */
920: /* the world stopped. */
1.1 noro 921: void GC_start_world()
922: {
923: pthread_t my_thread = pthread_self();
924: register int i;
925: register GC_thread p;
926: register int n_live_threads = 0;
927: register int result;
928:
929: # if DEBUG_THREADS
930: GC_printf0("World starting\n");
931: # endif
932:
933: for (i = 0; i < THREAD_TABLE_SZ; i++) {
934: for (p = GC_threads[i]; p != 0; p = p -> next) {
935: if (p -> id != my_thread) {
936: if (p -> flags & FINISHED) continue;
1.4 noro 937: if (p -> thread_blocked) continue;
1.1 noro 938: n_live_threads++;
939: #if DEBUG_THREADS
940: GC_printf1("Sending restart signal to 0x%x\n", p -> id);
941: #endif
1.4 noro 942: result = pthread_kill(p -> id, SIG_THR_RESTART);
1.1 noro 943: switch(result) {
944: case ESRCH:
945: /* Not really there anymore. Possible? */
946: n_live_threads--;
947: break;
948: case 0:
949: break;
950: default:
951: ABORT("pthread_kill failed");
952: }
953: }
954: }
955: }
956: #if DEBUG_THREADS
957: GC_printf0("World started\n");
958: #endif
959: }
960:
1.3 noro 961: # ifdef IA64
962: # define IF_IA64(x) x
963: # else
964: # define IF_IA64(x)
965: # endif
966: /* We hold allocation lock. Should do exactly the right thing if the */
967: /* world is stopped. Should not fail if it isn't. */
1.1 noro 968: void GC_push_all_stacks()
969: {
1.3 noro 970: int i;
971: GC_thread p;
972: ptr_t sp = GC_approx_sp();
973: ptr_t lo, hi;
974: /* On IA64, we also need to scan the register backing store. */
975: IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
1.1 noro 976: pthread_t me = pthread_self();
977:
978: if (!GC_thr_initialized) GC_thr_init();
979: #if DEBUG_THREADS
980: GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
981: #endif
982: for (i = 0; i < THREAD_TABLE_SZ; i++) {
983: for (p = GC_threads[i]; p != 0; p = p -> next) {
984: if (p -> flags & FINISHED) continue;
985: if (pthread_equal(p -> id, me)) {
1.4 noro 986: # ifdef SPARC
987: lo = (ptr_t)GC_save_regs_in_stack();
988: # else
989: lo = GC_approx_sp();
990: # endif
1.3 noro 991: IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
1.1 noro 992: } else {
993: lo = p -> stack_ptr;
1.3 noro 994: IF_IA64(bs_hi = p -> backing_store_ptr;)
1.1 noro 995: }
996: if ((p -> flags & MAIN_THREAD) == 0) {
1.3 noro 997: hi = p -> stack_end;
998: IF_IA64(bs_lo = p -> backing_store_end);
1.1 noro 999: } else {
1000: /* The original stack. */
1001: hi = GC_stackbottom;
1.3 noro 1002: IF_IA64(bs_lo = BACKING_STORE_BASE;)
1.1 noro 1003: }
1004: #if DEBUG_THREADS
1005: GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
1006: (unsigned long) p -> id,
1007: (unsigned long) lo, (unsigned long) hi);
1008: #endif
1.3 noro 1009: if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
1.4 noro 1010: # ifdef STACK_GROWS_UP
1011: /* We got them backwards! */
1012: GC_push_all_stack(hi, lo);
1013: # else
1014: GC_push_all_stack(lo, hi);
1015: # endif
1.3 noro 1016: # ifdef IA64
1017: if (pthread_equal(p -> id, me)) {
1018: GC_push_all_eager(bs_lo, bs_hi);
1019: } else {
1020: GC_push_all_stack(bs_lo, bs_hi);
1021: }
1022: # endif
1.1 noro 1023: }
1024: }
1025: }
1026:
1.4 noro 1027: #ifdef USE_PROC_FOR_LIBRARIES
1028: int GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
1029: {
1030: int i;
1031: GC_thread p;
1032:
1033: # ifdef PARALLEL_MARK
1034: for (i = 0; i < GC_markers; ++i) {
1035: if (marker_sp[i] > lo & marker_sp[i] < hi) return 1;
1036: }
1037: # endif
1038: for (i = 0; i < THREAD_TABLE_SZ; i++) {
1039: for (p = GC_threads[i]; p != 0; p = p -> next) {
1040: if (0 != p -> stack_end) {
1041: # ifdef STACK_GROWS_UP
1042: if (p -> stack_end >= lo && p -> stack_end < hi) return 1;
1043: # else /* STACK_GROWS_DOWN */
1044: if (p -> stack_end > lo && p -> stack_end <= hi) return 1;
1045: # endif
1046: }
1047: }
1048: }
1049: return 0;
1050: }
1051: #endif /* USE_PROC_FOR_LIBRARIES */
1052:
1.6 ! noro 1053: #ifdef GC_LINUX_THREADS
1.4 noro 1054: /* Return the number of processors, or i<= 0 if it can't be determined. */
1055: int GC_get_nprocs()
1056: {
1057: /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
1058: /* appears to be buggy in many cases. */
1059: /* We look for lines "cpu<n>" in /proc/stat. */
1060: # define STAT_BUF_SIZE 4096
1061: # if defined(GC_USE_LD_WRAP)
1062: # define STAT_READ __real_read
1063: # else
1064: # define STAT_READ read
1065: # endif
1066: char stat_buf[STAT_BUF_SIZE];
1067: int f;
1068: char c;
1069: word result = 1;
1070: /* Some old kernels only have a single "cpu nnnn ..." */
1071: /* entry in /proc/stat. We identify those as */
1072: /* uniprocessors. */
1073: size_t i, len = 0;
1074:
1075: f = open("/proc/stat", O_RDONLY);
1076: if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
1077: WARN("Couldn't read /proc/stat\n", 0);
1078: return -1;
1079: }
1080: for (i = 0; i < len - 100; ++i) {
1081: if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
1082: && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
1083: int cpu_no = atoi(stat_buf + i + 4);
1084: if (cpu_no >= result) result = cpu_no + 1;
1085: }
1086: }
1.6 ! noro 1087: close(f);
1.4 noro 1088: return result;
1089: }
1.6 ! noro 1090: #endif /* GC_LINUX_THREADS */
! 1091:
! 1092: /* We hold the GC lock. Wait until an in-progress GC has finished. */
! 1093: /* Repeatedly RELEASES GC LOCK in order to wait. */
! 1094: /* If wait_for_all is true, then we exit with the GC lock held and no */
! 1095: /* collection in progress; otherwise we just wait for the current GC */
! 1096: /* to finish. */
! 1097: void GC_wait_for_gc_completion(GC_bool wait_for_all)
! 1098: {
! 1099: if (GC_incremental && GC_collection_in_progress()) {
! 1100: int old_gc_no = GC_gc_no;
! 1101:
! 1102: /* Make sure that no part of our stack is still on the mark stack, */
! 1103: /* since it's about to be unmapped. */
! 1104: while (GC_incremental && GC_collection_in_progress()
! 1105: && (wait_for_all || old_gc_no == GC_gc_no)) {
! 1106: ENTER_GC();
! 1107: GC_collect_a_little_inner(1);
! 1108: EXIT_GC();
! 1109: UNLOCK();
! 1110: sched_yield();
! 1111: LOCK();
! 1112: }
! 1113: }
! 1114: }
! 1115:
! 1116: #ifdef HANDLE_FORK
! 1117: /* Procedures called before and after a fork. The goal here is to make */
! 1118: /* it safe to call GC_malloc() in a forked child. It's unclear that is */
! 1119: /* attainable, since the single UNIX spec seems to imply that one */
! 1120: /* should only call async-signal-safe functions, and we probably can't */
! 1121: /* quite guarantee that. But we give it our best shot. (That same */
! 1122: /* spec also implies that it's not safe to call the system malloc */
! 1123: /* between fork() and exec(). Thus we're doing no worse than it. */
! 1124:
! 1125: /* Called before a fork() */
! 1126: void GC_fork_prepare_proc(void)
! 1127: {
! 1128: /* Acquire all relevant locks, so that after releasing the locks */
! 1129: /* the child will see a consistent state in which monitor */
! 1130: /* invariants hold. Unfortunately, we can't acquire libc locks */
! 1131: /* we might need, and there seems to be no guarantee that libc */
! 1132: /* must install a suitable fork handler. */
! 1133: /* Wait for an ongoing GC to finish, since we can't finish it in */
! 1134: /* the (one remaining thread in) the child. */
! 1135: LOCK();
! 1136: # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
! 1137: GC_wait_for_reclaim();
! 1138: # endif
! 1139: GC_wait_for_gc_completion(TRUE);
! 1140: # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
! 1141: GC_acquire_mark_lock();
! 1142: # endif
! 1143: }
! 1144:
! 1145: /* Called in parent after a fork() */
! 1146: void GC_fork_parent_proc(void)
! 1147: {
! 1148: # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
! 1149: GC_release_mark_lock();
! 1150: # endif
! 1151: UNLOCK();
! 1152: }
! 1153:
! 1154: /* Called in child after a fork() */
! 1155: void GC_fork_child_proc(void)
! 1156: {
! 1157: /* Clean up the thread table, so that just our thread is left. */
! 1158: # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
! 1159: GC_release_mark_lock();
! 1160: # endif
! 1161: GC_remove_all_threads_but_me();
! 1162: # ifdef PARALLEL_MARK
! 1163: /* Turn off parallel marking in the child, since we are probably */
! 1164: /* just going to exec, and we would have to restart mark threads. */
! 1165: GC_markers = 1;
! 1166: GC_parallel = FALSE;
! 1167: # endif /* PARALLEL_MARK */
! 1168: UNLOCK();
! 1169: }
! 1170: #endif /* HANDLE_FORK */
! 1171:
! 1172: #if defined(GC_DGUX386_THREADS)
! 1173: /* Return the number of processors, or i<= 0 if it can't be determined. */
! 1174: int GC_get_nprocs()
! 1175: {
! 1176: /* <takis@XFree86.Org> */
! 1177: int numCpus;
! 1178: struct dg_sys_info_pm_info pm_sysinfo;
! 1179: int status =0;
! 1180:
! 1181: status = dg_sys_info((long int *) &pm_sysinfo,
! 1182: DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
! 1183: if (status < 0)
! 1184: /* set -1 for error */
! 1185: numCpus = -1;
! 1186: else
! 1187: /* Active CPUs */
! 1188: numCpus = pm_sysinfo.idle_vp_count;
! 1189:
! 1190: # ifdef DEBUG_THREADS
! 1191: GC_printf1("Number of active CPUs in this system: %d\n", numCpus);
! 1192: # endif
! 1193: return(numCpus);
! 1194: }
! 1195: #endif /* GC_DGUX386_THREADS */
1.1 noro 1196:
1197: /* We hold the allocation lock. */
1198: void GC_thr_init()
1199: {
1.3 noro 1200: int dummy;
1.1 noro 1201: GC_thread t;
1202: struct sigaction act;
1203:
1204: if (GC_thr_initialized) return;
1205: GC_thr_initialized = TRUE;
1206:
1207: if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
1208: ABORT("sem_init failed");
1209:
1210: act.sa_flags = SA_RESTART;
1211: if (sigfillset(&act.sa_mask) != 0) {
1212: ABORT("sigfillset() failed");
1213: }
1.3 noro 1214: # ifdef NO_SIGNALS
1215: if (sigdelset(&act.sa_mask, SIGINT) != 0
1216: || sigdelset(&act.sa_mask, SIGQUIT != 0)
1.4 noro 1217: || sigdelset(&act.sa_mask, SIGABRT != 0)
1.3 noro 1218: || sigdelset(&act.sa_mask, SIGTERM != 0)) {
1219: ABORT("sigdelset() failed");
1220: }
1221: # endif
1222:
1.4 noro 1223: /* SIG_THR_RESTART is unmasked by the handler when necessary. */
1.1 noro 1224: act.sa_handler = GC_suspend_handler;
1225: if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
1226: ABORT("Cannot set SIG_SUSPEND handler");
1227: }
1228:
1229: act.sa_handler = GC_restart_handler;
1.4 noro 1230: if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
1231: ABORT("Cannot set SIG_THR_RESTART handler");
1.1 noro 1232: }
1.6 ! noro 1233: # ifdef HANDLE_FORK
! 1234: /* Prepare for a possible fork. */
! 1235: pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
! 1236: GC_fork_child_proc);
! 1237: # endif /* HANDLE_FORK */
1.1 noro 1238: /* Add the initial thread, so we can stop it. */
1239: t = GC_new_thread(pthread_self());
1.3 noro 1240: t -> stack_ptr = (ptr_t)(&dummy);
1.1 noro 1241: t -> flags = DETACHED | MAIN_THREAD;
1.4 noro 1242:
1243: /* Set GC_nprocs. */
1244: {
1245: char * nprocs_string = GETENV("GC_NPROCS");
1246: GC_nprocs = -1;
1247: if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
1248: }
1249: if (GC_nprocs <= 0) {
1.6 ! noro 1250: # if defined(GC_HPUX_THREADS)
1.4 noro 1251: GC_nprocs = pthread_num_processors_np();
1252: # endif
1.6 ! noro 1253: # if defined(GC_OSF1_THREADS) || defined(GC_FREEBSD_THREADS)
1.4 noro 1254: GC_nprocs = 1;
1255: # endif
1.6 ! noro 1256: # if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
1.4 noro 1257: GC_nprocs = GC_get_nprocs();
1258: # endif
1259: }
1260: if (GC_nprocs <= 0) {
1261: WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
1262: GC_nprocs = 2;
1263: # ifdef PARALLEL_MARK
1264: GC_markers = 1;
1265: # endif
1266: } else {
1267: # ifdef PARALLEL_MARK
1.6 ! noro 1268: {
! 1269: char * markers_string = GETENV("GC_MARKERS");
! 1270: if (markers_string != NULL) {
! 1271: GC_markers = atoi(markers_string);
! 1272: } else {
! 1273: GC_markers = GC_nprocs;
! 1274: }
! 1275: }
1.4 noro 1276: # endif
1277: }
1278: # ifdef PARALLEL_MARK
1279: # ifdef CONDPRINT
1280: if (GC_print_stats) {
1281: GC_printf2("Number of processors = %ld, "
1282: "number of marker threads = %ld\n", GC_nprocs, GC_markers);
1283: }
1284: # endif
1285: if (GC_markers == 1) {
1286: GC_parallel = FALSE;
1287: # ifdef CONDPRINT
1288: if (GC_print_stats) {
1289: GC_printf0("Single marker thread, turning off parallel marking\n");
1290: }
1291: # endif
1292: } else {
1293: GC_parallel = TRUE;
1.6 ! noro 1294: /* Disable true incremental collection, but generational is OK. */
! 1295: GC_time_limit = GC_TIME_UNLIMITED;
1.4 noro 1296: }
1297: # endif
1.1 noro 1298: }
1299:
1.4 noro 1300:
1301: /* Perform all initializations, including those that */
1302: /* may require allocation. */
1.6 ! noro 1303: /* Called without allocation lock. */
1.4 noro 1304: /* Must be called before a second thread is created. */
1.6 ! noro 1305: /* Called without allocation lock. */
! 1306: void GC_init_parallel()
1.4 noro 1307: {
1.6 ! noro 1308: if (parallel_initialized) return;
! 1309: parallel_initialized = TRUE;
! 1310: /* GC_init() calls us back, so set flag first. */
1.4 noro 1311: if (!GC_is_initialized) GC_init();
1312: /* If we are using a parallel marker, start the helper threads. */
1313: # ifdef PARALLEL_MARK
1314: if (GC_parallel) start_mark_threads();
1315: # endif
1316: /* Initialize thread local free lists if used. */
1317: # if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
1318: LOCK();
1319: GC_init_thread_local(GC_lookup_thread(pthread_self()));
1320: UNLOCK();
1321: # endif
1322: }
1323:
1324:
1.3 noro 1325: int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
1.1 noro 1326: {
1327: sigset_t fudged_set;
1328:
1329: if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
1330: fudged_set = *set;
1331: sigdelset(&fudged_set, SIG_SUSPEND);
1332: set = &fudged_set;
1333: }
1.3 noro 1334: return(REAL_FUNC(pthread_sigmask)(how, set, oset));
1.1 noro 1335: }
1336:
1.4 noro 1337: /* Wrappers for functions that are likely to block for an appreciable */
1338: /* length of time. Must be called in pairs, if at all. */
1339: /* Nothing much beyond the system call itself should be executed */
1340: /* between these. */
1341:
1342: void GC_start_blocking(void) {
1343: # define SP_SLOP 128
1344: GC_thread me;
1345: LOCK();
1346: me = GC_lookup_thread(pthread_self());
1347: GC_ASSERT(!(me -> thread_blocked));
1348: # ifdef SPARC
1349: me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
1350: # else
1351: me -> stack_ptr = (ptr_t)GC_approx_sp();
1352: # endif
1353: # ifdef IA64
1354: me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;
1355: # endif
1356: /* Add some slop to the stack pointer, since the wrapped call may */
1357: /* end up pushing more callee-save registers. */
1358: # ifdef STACK_GROWS_UP
1359: me -> stack_ptr += SP_SLOP;
1360: # else
1361: me -> stack_ptr -= SP_SLOP;
1362: # endif
1363: me -> thread_blocked = TRUE;
1364: UNLOCK();
1365: }
1366:
1367: GC_end_blocking(void) {
1368: GC_thread me;
1369: LOCK(); /* This will block if the world is stopped. */
1370: me = GC_lookup_thread(pthread_self());
1371: GC_ASSERT(me -> thread_blocked);
1372: me -> thread_blocked = FALSE;
1373: UNLOCK();
1374: }
1375:
1.6 ! noro 1376: #if defined(GC_DGUX386_THREADS)
! 1377: #define __d10_sleep sleep
! 1378: #endif /* GC_DGUX386_THREADS */
! 1379:
1.4 noro 1380: /* A wrapper for the standard C sleep function */
1381: int WRAP_FUNC(sleep) (unsigned int seconds)
1382: {
1383: int result;
1384:
1385: GC_start_blocking();
1386: result = REAL_FUNC(sleep)(seconds);
1387: GC_end_blocking();
1388: return result;
1389: }
1390:
1.1 noro 1391: struct start_info {
1392: void *(*start_routine)(void *);
1393: void *arg;
1394: word flags;
1395: sem_t registered; /* 1 ==> in our thread table, but */
1396: /* parent hasn't yet noticed. */
1397: };
1398:
1.4 noro 1399: /* Called at thread exit. */
1400: /* Never called for main thread. That's OK, since it */
1401: /* results in at most a tiny one-time leak. And */
1402: /* linuxthreads doesn't reclaim the main threads */
1403: /* resources or id anyway. */
1.1 noro 1404: void GC_thread_exit_proc(void *arg)
1405: {
1406: GC_thread me;
1407:
1408: LOCK();
1409: me = GC_lookup_thread(pthread_self());
1.4 noro 1410: GC_destroy_thread_local(me);
1.1 noro 1411: if (me -> flags & DETACHED) {
1412: GC_delete_thread(pthread_self());
1413: } else {
1414: me -> flags |= FINISHED;
1415: }
1.4 noro 1416: # if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
1417: && !defined(USE_HPUX_TLS) && !defined(DBG_HDRS_ALL)
1418: GC_remove_specific(GC_thread_key);
1419: # endif
1.6 ! noro 1420: GC_wait_for_gc_completion(FALSE);
1.1 noro 1421: UNLOCK();
1422: }
1423:
1.3 noro 1424: int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
1.1 noro 1425: {
1426: int result;
1427: GC_thread thread_gc_id;
1428:
1429: LOCK();
1430: thread_gc_id = GC_lookup_thread(thread);
1431: /* This is guaranteed to be the intended one, since the thread id */
1432: /* cant have been recycled by pthreads. */
1433: UNLOCK();
1.3 noro 1434: result = REAL_FUNC(pthread_join)(thread, retval);
1.6 ! noro 1435: # if defined (GC_FREEBSD_THREADS)
! 1436: /* On FreeBSD, the wrapped pthread_join() sometimes returns (what
! 1437: appears to be) a spurious EINTR which caused the test and real code
! 1438: to gratuitously fail. Having looked at system pthread library source
! 1439: code, I see how this return code may be generated. In one path of
! 1440: code, pthread_join() just returns the errno setting of the thread
! 1441: being joined. This does not match the POSIX specification or the
! 1442: local man pages thus I have taken the liberty to catch this one
! 1443: spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
! 1444: if (result == EINTR) result = 0;
! 1445: # endif
1.4 noro 1446: if (result == 0) {
1447: LOCK();
1448: /* Here the pthread thread id may have been recycled. */
1449: GC_delete_gc_thread(thread, thread_gc_id);
1450: UNLOCK();
1451: }
1452: return result;
1453: }
1454:
1455: int
1456: WRAP_FUNC(pthread_detach)(pthread_t thread)
1457: {
1458: int result;
1459: GC_thread thread_gc_id;
1460:
1.1 noro 1461: LOCK();
1.4 noro 1462: thread_gc_id = GC_lookup_thread(thread);
1.1 noro 1463: UNLOCK();
1.4 noro 1464: result = REAL_FUNC(pthread_detach)(thread);
1465: if (result == 0) {
1466: LOCK();
1467: thread_gc_id -> flags |= DETACHED;
1468: /* Here the pthread thread id may have been recycled. */
1469: if (thread_gc_id -> flags & FINISHED) {
1470: GC_delete_gc_thread(thread, thread_gc_id);
1471: }
1472: UNLOCK();
1473: }
1.1 noro 1474: return result;
1475: }
1476:
1477: void * GC_start_routine(void * arg)
1478: {
1.3 noro 1479: int dummy;
1.1 noro 1480: struct start_info * si = arg;
1481: void * result;
1482: GC_thread me;
1483: pthread_t my_pthread;
1484: void *(*start)(void *);
1485: void *start_arg;
1486:
1487: my_pthread = pthread_self();
1.3 noro 1488: # ifdef DEBUG_THREADS
1489: GC_printf1("Starting thread 0x%lx\n", my_pthread);
1490: GC_printf1("pid = %ld\n", (long) getpid());
1491: GC_printf1("sp = 0x%lx\n", (long) &arg);
1492: # endif
1.1 noro 1493: LOCK();
1494: me = GC_new_thread(my_pthread);
1495: me -> flags = si -> flags;
1496: me -> stack_ptr = 0;
1.3 noro 1497: /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99) */
1498: /* doesn't work because the stack base in /proc/self/stat is the */
1499: /* one for the main thread. There is a strong argument that that's */
1500: /* a kernel bug, but a pervasive one. */
1501: # ifdef STACK_GROWS_DOWN
1502: me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
1503: & ~(GC_page_size - 1));
1504: me -> stack_ptr = me -> stack_end - 0x10;
1505: /* Needs to be plausible, since an asynchronous stack mark */
1506: /* should not crash. */
1507: # else
1.4 noro 1508: me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1));
1.3 noro 1509: me -> stack_ptr = me -> stack_end + 0x10;
1510: # endif
1511: /* This is dubious, since we may be more than a page into the stack, */
1512: /* and hence skip some of it, though it's not clear that matters. */
1513: # ifdef IA64
1514: me -> backing_store_end = (ptr_t)
1515: (GC_save_regs_in_stack() & ~(GC_page_size - 1));
1516: /* This is also < 100% convincing. We should also read this */
1517: /* from /proc, but the hook to do so isn't there yet. */
1518: # endif /* IA64 */
1.1 noro 1519: UNLOCK();
1520: start = si -> start_routine;
1.3 noro 1521: # ifdef DEBUG_THREADS
1522: GC_printf1("start_routine = 0x%lx\n", start);
1523: # endif
1.1 noro 1524: start_arg = si -> arg;
1.4 noro 1525: sem_post(&(si -> registered)); /* Last action on si. */
1526: /* OK to deallocate. */
1527: pthread_cleanup_push(GC_thread_exit_proc, 0);
1528: # if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
1529: LOCK();
1530: GC_init_thread_local(me);
1531: UNLOCK();
1532: # endif
1.1 noro 1533: result = (*start)(start_arg);
1534: #if DEBUG_THREADS
1535: GC_printf1("Finishing thread 0x%x\n", pthread_self());
1536: #endif
1537: me -> status = result;
1538: me -> flags |= FINISHED;
1539: pthread_cleanup_pop(1);
1540: /* Cleanup acquires lock, ensuring that we can't exit */
1541: /* while a collection that thinks we're alive is trying to stop */
1542: /* us. */
1543: return(result);
1544: }
1545:
1546: int
1.3 noro 1547: WRAP_FUNC(pthread_create)(pthread_t *new_thread,
1.1 noro 1548: const pthread_attr_t *attr,
1549: void *(*start_routine)(void *), void *arg)
1550: {
1551: int result;
1552: GC_thread t;
1553: pthread_t my_new_thread;
1554: int detachstate;
1555: word my_flags = 0;
1.4 noro 1556: struct start_info * si;
1.1 noro 1557: /* This is otherwise saved only in an area mmapped by the thread */
1558: /* library, which isn't visible to the collector. */
1.4 noro 1559:
1.6 ! noro 1560: /* We resist the temptation to muck with the stack size here, */
! 1561: /* even if the default is unreasonably small. That's the client's */
! 1562: /* responsibility. */
! 1563:
1.4 noro 1564: LOCK();
1.6 ! noro 1565: si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
! 1566: NORMAL);
1.4 noro 1567: UNLOCK();
1.6 ! noro 1568: if (!parallel_initialized) GC_init_parallel();
1.1 noro 1569: if (0 == si) return(ENOMEM);
1570: sem_init(&(si -> registered), 0, 0);
1571: si -> start_routine = start_routine;
1572: si -> arg = arg;
1573: LOCK();
1574: if (!GC_thr_initialized) GC_thr_init();
1575: if (NULL == attr) {
1.4 noro 1576: detachstate = PTHREAD_CREATE_JOINABLE;
1.6 ! noro 1577: } else {
1.4 noro 1578: pthread_attr_getdetachstate(attr, &detachstate);
1.1 noro 1579: }
1580: if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
1581: si -> flags = my_flags;
1582: UNLOCK();
1.3 noro 1583: # ifdef DEBUG_THREADS
1584: GC_printf1("About to start new thread from thread 0x%X\n",
1585: pthread_self());
1586: # endif
1.6 ! noro 1587:
1.4 noro 1588: result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
1.3 noro 1589: # ifdef DEBUG_THREADS
1590: GC_printf1("Started thread 0x%X\n", *new_thread);
1591: # endif
1.1 noro 1592: /* Wait until child has been added to the thread table. */
1593: /* This also ensures that we hold onto si until the child is done */
1594: /* with it. Thus it doesn't matter whether it is otherwise */
1595: /* visible to the collector. */
1.4 noro 1596: while (0 != sem_wait(&(si -> registered))) {
1597: if (EINTR != errno) ABORT("sem_wait failed");
1598: }
1.1 noro 1599: sem_destroy(&(si -> registered));
1.4 noro 1600: LOCK();
1601: GC_INTERNAL_FREE(si);
1602: UNLOCK();
1.6 ! noro 1603:
1.1 noro 1604: return(result);
1605: }
1606:
1.4 noro 1607: #ifdef GENERIC_COMPARE_AND_SWAP
1608: pthread_mutex_t GC_compare_and_swap_lock = PTHREAD_MUTEX_INITIALIZER;
1609:
1610: GC_bool GC_compare_and_exchange(volatile GC_word *addr,
1611: GC_word old, GC_word new_val)
1612: {
1613: GC_bool result;
1614: pthread_mutex_lock(&GC_compare_and_swap_lock);
1615: if (*addr == old) {
1616: *addr = new_val;
1617: result = TRUE;
1618: } else {
1619: result = FALSE;
1620: }
1621: pthread_mutex_unlock(&GC_compare_and_swap_lock);
1622: return result;
1623: }
1624:
1625: GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much)
1626: {
1627: GC_word old;
1628: pthread_mutex_lock(&GC_compare_and_swap_lock);
1629: old = *addr;
1630: *addr = old + how_much;
1631: pthread_mutex_unlock(&GC_compare_and_swap_lock);
1632: return old;
1633: }
1634:
1635: #endif /* GENERIC_COMPARE_AND_SWAP */
1636: /* Spend a few cycles in a way that can't introduce contention with */
1637: /* othre threads. */
1638: void GC_pause()
1639: {
1640: int i;
1641: volatile word dummy = 0;
1642:
1643: for (i = 0; i < 10; ++i) {
1644: # ifdef __GNUC__
1645: __asm__ __volatile__ (" " : : : "memory");
1646: # else
1647: /* Something that's unlikely to be optimized away. */
1648: GC_noop(++dummy);
1649: # endif
1650: }
1651: }
1652:
1653: #define SPIN_MAX 1024 /* Maximum number of calls to GC_pause before */
1654: /* give up. */
1.3 noro 1655:
1656: VOLATILE GC_bool GC_collecting = 0;
1.1 noro 1657: /* A hint that we're in the collector and */
1658: /* holding the allocation lock for an */
1659: /* extended period. */
1660:
1.4 noro 1661: #if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK)
1662: /* If we don't want to use the below spinlock implementation, either */
1663: /* because we don't have a GC_test_and_set implementation, or because */
1664: /* we don't want to risk sleeping, we can still try spinning on */
1665: /* pthread_mutex_trylock for a while. This appears to be very */
1666: /* beneficial in many cases. */
1667: /* I suspect that under high contention this is nearly always better */
1668: /* than the spin lock. But it's a bit slower on a uniprocessor. */
1669: /* Hence we still default to the spin lock. */
1670: /* This is also used to acquire the mark lock for the parallel */
1671: /* marker. */
1672:
1673: /* Here we use a strict exponential backoff scheme. I don't know */
1674: /* whether that's better or worse than the above. We eventually */
1675: /* yield by calling pthread_mutex_lock(); it never makes sense to */
1676: /* explicitly sleep. */
1677:
1678: void GC_generic_lock(pthread_mutex_t * lock)
1679: {
1680: unsigned pause_length = 1;
1681: unsigned i;
1682:
1683: if (0 == pthread_mutex_trylock(lock)) return;
1684: for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
1685: for (i = 0; i < pause_length; ++i) {
1686: GC_pause();
1687: }
1688: switch(pthread_mutex_trylock(lock)) {
1689: case 0:
1690: return;
1691: case EBUSY:
1692: break;
1693: default:
1694: ABORT("Unexpected error from pthread_mutex_trylock");
1695: }
1696: }
1697: pthread_mutex_lock(lock);
1698: }
1699:
1700: #endif /* !USE_SPIN_LOCK || PARALLEL_MARK */
1701:
1702: #if defined(USE_SPIN_LOCK)
1703:
1.1 noro 1704: /* Reasonably fast spin locks. Basically the same implementation */
1705: /* as STL alloc.h. This isn't really the right way to do this. */
1706: /* but until the POSIX scheduling mess gets straightened out ... */
1707:
1708: volatile unsigned int GC_allocate_lock = 0;
1709:
1710:
1711: void GC_lock()
1712: {
1713: # define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
1.4 noro 1714: # define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
1.1 noro 1715: static unsigned spin_max = low_spin_max;
1716: unsigned my_spin_max;
1717: static unsigned last_spins = 0;
1718: unsigned my_last_spins;
1719: int i;
1720:
1721: if (!GC_test_and_set(&GC_allocate_lock)) {
1722: return;
1723: }
1724: my_spin_max = spin_max;
1725: my_last_spins = last_spins;
1726: for (i = 0; i < my_spin_max; i++) {
1.4 noro 1727: if (GC_collecting || GC_nprocs == 1) goto yield;
1.1 noro 1728: if (i < my_last_spins/2 || GC_allocate_lock) {
1.4 noro 1729: GC_pause();
1.1 noro 1730: continue;
1731: }
1732: if (!GC_test_and_set(&GC_allocate_lock)) {
1733: /*
1734: * got it!
1735: * Spinning worked. Thus we're probably not being scheduled
1736: * against the other process with which we were contending.
1737: * Thus it makes sense to spin longer the next time.
1738: */
1739: last_spins = i;
1740: spin_max = high_spin_max;
1741: return;
1742: }
1743: }
1744: /* We are probably being scheduled against the other process. Sleep. */
1745: spin_max = low_spin_max;
1746: yield:
1747: for (i = 0;; ++i) {
1748: if (!GC_test_and_set(&GC_allocate_lock)) {
1749: return;
1750: }
1751: # define SLEEP_THRESHOLD 12
1752: /* nanosleep(<= 2ms) just spins under Linux. We */
1753: /* want to be careful to avoid that behavior. */
1754: if (i < SLEEP_THRESHOLD) {
1755: sched_yield();
1756: } else {
1757: struct timespec ts;
1758:
1.4 noro 1759: if (i > 24) i = 24;
1760: /* Don't wait for more than about 15msecs, even */
1.1 noro 1761: /* under extreme contention. */
1762: ts.tv_sec = 0;
1763: ts.tv_nsec = 1 << i;
1764: nanosleep(&ts, 0);
1765: }
1766: }
1767: }
1.3 noro 1768:
1.4 noro 1769: #else /* !USE_SPINLOCK */
1770:
1771: void GC_lock()
1772: {
1773: if (1 == GC_nprocs || GC_collecting) {
1774: pthread_mutex_lock(&GC_allocate_ml);
1775: } else {
1776: GC_generic_lock(&GC_allocate_ml);
1777: }
1778: }
1779:
1780: #endif /* !USE_SPINLOCK */
1781:
1.6 ! noro 1782: #if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
1.4 noro 1783:
1784: #ifdef GC_ASSERTIONS
1785: pthread_t GC_mark_lock_holder = NO_THREAD;
1786: #endif
1787:
1.6 ! noro 1788: #if 0
1.4 noro 1789: /* Ugly workaround for a linux threads bug in the final versions */
1790: /* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
1791: /* field even when it fails to acquire the mutex. This causes */
1792: /* pthread_cond_wait to die. Remove for glibc2.2. */
1793: /* According to the man page, we should use */
1794: /* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
1795: /* defined. */
1796: static pthread_mutex_t mark_mutex =
1797: {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
1798: #else
1799: static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
1800: #endif
1801:
1802: static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
1803:
1804: void GC_acquire_mark_lock()
1805: {
1806: /*
1807: if (pthread_mutex_lock(&mark_mutex) != 0) {
1808: ABORT("pthread_mutex_lock failed");
1809: }
1810: */
1811: GC_generic_lock(&mark_mutex);
1812: # ifdef GC_ASSERTIONS
1813: GC_mark_lock_holder = pthread_self();
1814: # endif
1815: }
1816:
1817: void GC_release_mark_lock()
1818: {
1819: GC_ASSERT(GC_mark_lock_holder == pthread_self());
1820: # ifdef GC_ASSERTIONS
1821: GC_mark_lock_holder = NO_THREAD;
1822: # endif
1823: if (pthread_mutex_unlock(&mark_mutex) != 0) {
1824: ABORT("pthread_mutex_unlock failed");
1825: }
1826: }
1827:
1.6 ! noro 1828: /* Collector must wait for a freelist builders for 2 reasons: */
! 1829: /* 1) Mark bits may still be getting examined without lock. */
! 1830: /* 2) Partial free lists referenced only by locals may not be scanned */
! 1831: /* correctly, e.g. if they contain "pointer-free" objects, since the */
! 1832: /* free-list link may be ignored. */
! 1833: void GC_wait_builder()
1.4 noro 1834: {
1835: GC_ASSERT(GC_mark_lock_holder == pthread_self());
1836: # ifdef GC_ASSERTIONS
1837: GC_mark_lock_holder = NO_THREAD;
1838: # endif
1.6 ! noro 1839: if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
1.4 noro 1840: ABORT("pthread_cond_wait failed");
1841: }
1842: GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
1843: # ifdef GC_ASSERTIONS
1844: GC_mark_lock_holder = pthread_self();
1845: # endif
1846: }
1847:
1.6 ! noro 1848: void GC_wait_for_reclaim()
! 1849: {
! 1850: GC_acquire_mark_lock();
! 1851: while (GC_fl_builder_count > 0) {
! 1852: GC_wait_builder();
! 1853: }
! 1854: GC_release_mark_lock();
! 1855: }
! 1856:
! 1857: void GC_notify_all_builder()
! 1858: {
! 1859: GC_ASSERT(GC_mark_lock_holder == pthread_self());
! 1860: if (pthread_cond_broadcast(&builder_cv) != 0) {
! 1861: ABORT("pthread_cond_broadcast failed");
! 1862: }
! 1863: }
! 1864:
! 1865: #endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
! 1866:
! 1867: #ifdef PARALLEL_MARK
! 1868:
! 1869: static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
! 1870:
! 1871: void GC_wait_marker()
1.4 noro 1872: {
1873: GC_ASSERT(GC_mark_lock_holder == pthread_self());
1874: # ifdef GC_ASSERTIONS
1875: GC_mark_lock_holder = NO_THREAD;
1876: # endif
1.6 ! noro 1877: if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
1.4 noro 1878: ABORT("pthread_cond_wait failed");
1879: }
1880: GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
1881: # ifdef GC_ASSERTIONS
1882: GC_mark_lock_holder = pthread_self();
1883: # endif
1884: }
1885:
1886: void GC_notify_all_marker()
1887: {
1888: if (pthread_cond_broadcast(&mark_cv) != 0) {
1889: ABORT("pthread_cond_broadcast failed");
1890: }
1891: }
1892:
1893: #endif /* PARALLEL_MARK */
1.1 noro 1894:
1.6 ! noro 1895: # endif /* GC_LINUX_THREADS and friends */
1.1 noro 1896:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>