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