]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/src/engine/boehm_gc/pthread_support.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / tools / build / src / engine / boehm_gc / pthread_support.c
CommitLineData
7c673cae
FG
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-2005 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 originally for LinuxThreads, the clone()-based kernel
18 * thread package for Linux which is included in libc6.
19 *
20 * This code no doubt makes some assumptions beyond what is
21 * guaranteed by the pthread standard, though it now does
22 * very little of that. It now also supports NPTL, and many
23 * other Posix thread implementations. We are trying to merge
24 * all flavors of pthread dupport code into this file.
25 */
26 /* DG/UX ix86 support <takis@xfree86.org> */
27/*
28 * Linux_threads.c now also includes some code to support HPUX and
29 * OSF1 (Compaq Tru64 Unix, really). The OSF1 support is based on Eric Benson's
30 * patch.
31 *
32 * Eric also suggested an alternate basis for a lock implementation in
33 * his code:
34 * + #elif defined(OSF1)
35 * + unsigned long GC_allocate_lock = 0;
36 * + msemaphore GC_allocate_semaphore;
37 * + # define GC_TRY_LOCK() \
38 * + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
39 * + ? (GC_allocate_lock = 1) \
40 * + : 0)
41 * + # define GC_LOCK_TAKEN GC_allocate_lock
42 */
43
44/*#define DEBUG_THREADS 1*/
45
46# include "private/pthread_support.h"
47
48# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
49
50# if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
51# define _POSIX4A_DRAFT10_SOURCE 1
52# endif
53
54# if defined(GC_DGUX386_THREADS) && !defined(_USING_POSIX4A_DRAFT10)
55# define _USING_POSIX4A_DRAFT10 1
56# endif
57
58# include <stdlib.h>
59# include <pthread.h>
60# include <sched.h>
61# include <time.h>
62# include <errno.h>
63# include <unistd.h>
64# include <sys/mman.h>
65# include <sys/time.h>
66# include <sys/types.h>
67# include <sys/stat.h>
68# include <fcntl.h>
69# include <signal.h>
70
71# include "gc_inline.h"
72
73#if defined(GC_DARWIN_THREADS)
74# include "private/darwin_semaphore.h"
75#else
76# include <semaphore.h>
77#endif /* !GC_DARWIN_THREADS */
78
79#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
80# include <sys/sysctl.h>
81#endif /* GC_DARWIN_THREADS */
82
83#if defined(GC_NETBSD_THREADS)
84# include <sys/param.h>
85# include <sys/sysctl.h>
86#endif /* GC_NETBSD_THREADS */
87
88/* Allocator lock definitions. */
89#if !defined(USE_SPIN_LOCK)
90 pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
91#endif
92unsigned long GC_lock_holder = NO_THREAD;
93 /* Used only for assertions, and to prevent */
94 /* recursive reentry in the system call wrapper. */
95
96#if defined(GC_DGUX386_THREADS)
97# include <sys/dg_sys_info.h>
98# include <sys/_int_psem.h>
99 /* sem_t is an uint in DG/UX */
100 typedef unsigned int sem_t;
101#endif /* GC_DGUX386_THREADS */
102
103#ifndef __GNUC__
104# define __inline__
105#endif
106
107/* Undefine macros used to redirect pthread primitives. */
108# undef pthread_create
109# if !defined(GC_DARWIN_THREADS)
110# undef pthread_sigmask
111# endif
112# undef pthread_join
113# undef pthread_detach
114# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
115 && !defined(_PTHREAD_USE_PTDNAM_)
116 /* Restore the original mangled names on Tru64 UNIX. */
117# define pthread_create __pthread_create
118# define pthread_join __pthread_join
119# define pthread_detach __pthread_detach
120# endif
121
122#ifdef GC_USE_LD_WRAP
123# define WRAP_FUNC(f) __wrap_##f
124# define REAL_FUNC(f) __real_##f
125#else
126# ifdef GC_USE_DLOPEN_WRAP
127# include <dlfcn.h>
128# define WRAP_FUNC(f) f
129# define REAL_FUNC(f) GC_real_##f
130 /* We define both GC_f and plain f to be the wrapped function. */
131 /* In that way plain calls work, as do calls from files that */
132 /* included gc.h, wich redefined f to GC_f. */
133 /* FIXME: Needs work for DARWIN and True64 (OSF1) */
134 typedef int (* GC_pthread_create_t)(pthread_t *, const pthread_attr_t *,
135 void * (*)(void *), void *);
136 static GC_pthread_create_t GC_real_pthread_create;
137 typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *, sigset_t *);
138 static GC_pthread_sigmask_t GC_real_pthread_sigmask;
139 typedef int (* GC_pthread_join_t)(pthread_t, void **);
140 static GC_pthread_join_t GC_real_pthread_join;
141 typedef int (* GC_pthread_detach_t)(pthread_t);
142 static GC_pthread_detach_t GC_real_pthread_detach;
143# else
144# define WRAP_FUNC(f) GC_##f
145# if !defined(GC_DGUX386_THREADS)
146# define REAL_FUNC(f) f
147# else /* GC_DGUX386_THREADS */
148# define REAL_FUNC(f) __d10_##f
149# endif /* GC_DGUX386_THREADS */
150# endif
151#endif
152
153#if defined(GC_USE_DL_WRAP) || defined(GC_USE_DLOPEN_WRAP)
154/* Define GC_ functions as aliases for the plain ones, which will */
155/* be intercepted. This allows files which include gc.h, and hence */
156/* generate referemces to the GC_ symbols, to see the right symbols. */
157 int GC_pthread_create(pthread_t * t, const pthread_attr_t * a,
158 void * (* fn)(void *), void * arg) {
159 return pthread_create(t, a, fn, arg);
160 }
161 int GC_pthread_sigmask(int how, const sigset_t *mask, sigset_t *old) {
162 return pthread_sigmask(how, mask, old);
163 }
164 int GC_pthread_join(pthread_t t, void **res) {
165 return pthread_join(t, res);
166 }
167 int GC_pthread_detach(pthread_t t) {
168 return pthread_detach(t);
169 }
170#endif /* Linker-based interception. */
171
172#ifdef GC_USE_DLOPEN_WRAP
173 static GC_bool GC_syms_initialized = FALSE;
174
175 void GC_init_real_syms(void)
176 {
177 void *dl_handle;
178# define LIBPTHREAD_NAME "libpthread.so.0"
179# define LIBPTHREAD_NAME_LEN 16 /* incl. trailing 0 */
180 size_t len = LIBPTHREAD_NAME_LEN - 1;
181 char namebuf[LIBPTHREAD_NAME_LEN];
182 static char *libpthread_name = LIBPTHREAD_NAME;
183
184 if (GC_syms_initialized) return;
185# ifdef RTLD_NEXT
186 dl_handle = RTLD_NEXT;
187# else
188 dl_handle = dlopen(libpthread_name, RTLD_LAZY);
189 if (NULL == dl_handle) {
190 while (isdigit(libpthread_name[len-1])) --len;
191 if (libpthread_name[len-1] == '.') --len;
192 memcpy(namebuf, libpthread_name, len);
193 namebuf[len] = '\0';
194 dl_handle = dlopen(namebuf, RTLD_LAZY);
195 }
196 if (NULL == dl_handle) ABORT("Couldn't open libpthread\n");
197# endif
198 GC_real_pthread_create = (GC_pthread_create_t)
199 dlsym(dl_handle, "pthread_create");
200 GC_real_pthread_sigmask = (GC_pthread_sigmask_t)
201 dlsym(dl_handle, "pthread_sigmask");
202 GC_real_pthread_join = (GC_pthread_join_t)
203 dlsym(dl_handle, "pthread_join");
204 GC_real_pthread_detach = (GC_pthread_detach_t)
205 dlsym(dl_handle, "pthread_detach");
206 GC_syms_initialized = TRUE;
207 }
208
209# define INIT_REAL_SYMS() if (!GC_syms_initialized) GC_init_real_syms();
210#else
211# define INIT_REAL_SYMS()
212#endif
213
214void GC_thr_init(void);
215
216static GC_bool parallel_initialized = FALSE;
217
218GC_bool GC_need_to_lock = FALSE;
219
220void GC_init_parallel(void);
221
222long GC_nprocs = 1; /* Number of processors. We may not have */
223 /* access to all of them, but this is as good */
224 /* a guess as any ... */
225
226#ifdef THREAD_LOCAL_ALLOC
227/* We must explicitly mark ptrfree and gcj free lists, since the free */
228/* list links wouldn't otherwise be found. We also set them in the */
229/* normal free lists, since that involves touching less memory than if */
230/* we scanned them normally. */
231void GC_mark_thread_local_free_lists(void)
232{
233 int i;
234 GC_thread p;
235
236 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
237 for (p = GC_threads[i]; 0 != p; p = p -> next) {
238 GC_mark_thread_local_fls_for(&(p->tlfs));
239 }
240 }
241}
242
243#if defined(GC_ASSERTIONS)
244 /* Check that all thread-local free-lists are completely marked. */
245 /* also check that thread-specific-data structures are marked. */
246 void GC_check_tls(void) {
247 int i;
248 GC_thread p;
249
250 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
251 for (p = GC_threads[i]; 0 != p; p = p -> next) {
252 GC_check_tls_for(&(p->tlfs));
253 }
254 }
255# if defined(USE_CUSTOM_SPECIFIC)
256 if (GC_thread_key != 0)
257 GC_check_tsd_marks(GC_thread_key);
258# endif
259 }
260#endif /* GC_ASSERTIONS */
261
262#endif /* Thread_local_alloc */
263
264#ifdef PARALLEL_MARK
265
266# ifndef MAX_MARKERS
267# define MAX_MARKERS 16
268# endif
269
270static ptr_t marker_sp[MAX_MARKERS] = {0};
271#ifdef IA64
272 static ptr_t marker_bsp[MAX_MARKERS] = {0};
273#endif
274
275void * GC_mark_thread(void * id)
276{
277 word my_mark_no = 0;
278
279 marker_sp[(word)id] = GC_approx_sp();
280# ifdef IA64
281 marker_bsp[(word)id] = GC_save_regs_in_stack();
282# endif
283 for (;; ++my_mark_no) {
284 /* GC_mark_no is passed only to allow GC_help_marker to terminate */
285 /* promptly. This is important if it were called from the signal */
286 /* handler or from the GC lock acquisition code. Under Linux, it's */
287 /* not safe to call it from a signal handler, since it uses mutexes */
288 /* and condition variables. Since it is called only here, the */
289 /* argument is unnecessary. */
290 if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
291 /* resynchronize if we get far off, e.g. because GC_mark_no */
292 /* wrapped. */
293 my_mark_no = GC_mark_no;
294 }
295# ifdef DEBUG_THREADS
296 GC_printf("Starting mark helper for mark number %lu\n", my_mark_no);
297# endif
298 GC_help_marker(my_mark_no);
299 }
300}
301
302extern long GC_markers; /* Number of mark threads we would */
303 /* like to have. Includes the */
304 /* initiating thread. */
305
306pthread_t GC_mark_threads[MAX_MARKERS];
307
308#define PTHREAD_CREATE REAL_FUNC(pthread_create)
309
310static void start_mark_threads(void)
311{
312 unsigned i;
313 pthread_attr_t attr;
314
315 if (GC_markers > MAX_MARKERS) {
316 WARN("Limiting number of mark threads\n", 0);
317 GC_markers = MAX_MARKERS;
318 }
319 if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
320
321 if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
322 ABORT("pthread_attr_setdetachstate failed");
323
324# if defined(HPUX) || defined(GC_DGUX386_THREADS)
325 /* Default stack size is usually too small: fix it. */
326 /* Otherwise marker threads or GC may run out of */
327 /* space. */
328# define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
329 {
330 size_t old_size;
331 int code;
332
333 if (pthread_attr_getstacksize(&attr, &old_size) != 0)
334 ABORT("pthread_attr_getstacksize failed\n");
335 if (old_size < MIN_STACK_SIZE) {
336 if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
337 ABORT("pthread_attr_setstacksize failed\n");
338 }
339 }
340# endif /* HPUX || GC_DGUX386_THREADS */
341 if (GC_print_stats) {
342 GC_log_printf("Starting %ld marker threads\n", GC_markers - 1);
343 }
344 for (i = 0; i < GC_markers - 1; ++i) {
345 if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
346 GC_mark_thread, (void *)(word)i)) {
347 WARN("Marker thread creation failed, errno = %ld.\n", errno);
348 }
349 }
350}
351
352#endif /* PARALLEL_MARK */
353
354GC_bool GC_thr_initialized = FALSE;
355
356volatile GC_thread GC_threads[THREAD_TABLE_SZ];
357
358void GC_push_thread_structures(void)
359{
360 GC_ASSERT(I_HOLD_LOCK());
361 GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
362# if defined(THREAD_LOCAL_ALLOC)
363 GC_push_all((ptr_t)(&GC_thread_key),
364 (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
365# endif
366}
367
368/* It may not be safe to allocate when we register the first thread. */
369static struct GC_Thread_Rep first_thread;
370
371/* Add a thread to GC_threads. We assume it wasn't already there. */
372/* Caller holds allocation lock. */
373GC_thread GC_new_thread(pthread_t id)
374{
375 int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
376 GC_thread result;
377 static GC_bool first_thread_used = FALSE;
378
379 GC_ASSERT(I_HOLD_LOCK());
380 if (!first_thread_used) {
381 result = &first_thread;
382 first_thread_used = TRUE;
383 } else {
384 result = (struct GC_Thread_Rep *)
385 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
386 GC_ASSERT(result -> flags == 0);
387 }
388 if (result == 0) return(0);
389 result -> id = id;
390 result -> next = GC_threads[hv];
391 GC_threads[hv] = result;
392 GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
393 return(result);
394}
395
396/* Delete a thread from GC_threads. We assume it is there. */
397/* (The code intentionally traps if it wasn't.) */
398void GC_delete_thread(pthread_t id)
399{
400 int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
401 register GC_thread p = GC_threads[hv];
402 register GC_thread prev = 0;
403
404 GC_ASSERT(I_HOLD_LOCK());
405 while (!THREAD_EQUAL(p -> id, id)) {
406 prev = p;
407 p = p -> next;
408 }
409 if (prev == 0) {
410 GC_threads[hv] = p -> next;
411 } else {
412 prev -> next = p -> next;
413 }
414# ifdef GC_DARWIN_THREADS
415 mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
416# endif
417 GC_INTERNAL_FREE(p);
418}
419
420/* If a thread has been joined, but we have not yet */
421/* been notified, then there may be more than one thread */
422/* in the table with the same pthread id. */
423/* This is OK, but we need a way to delete a specific one. */
424void GC_delete_gc_thread(GC_thread gc_id)
425{
426 pthread_t id = gc_id -> id;
427 int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
428 register GC_thread p = GC_threads[hv];
429 register GC_thread prev = 0;
430
431 GC_ASSERT(I_HOLD_LOCK());
432 while (p != gc_id) {
433 prev = p;
434 p = p -> next;
435 }
436 if (prev == 0) {
437 GC_threads[hv] = p -> next;
438 } else {
439 prev -> next = p -> next;
440 }
441# ifdef GC_DARWIN_THREADS
442 mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
443# endif
444 GC_INTERNAL_FREE(p);
445}
446
447/* Return a GC_thread corresponding to a given pthread_t. */
448/* Returns 0 if it's not there. */
449/* Caller holds allocation lock or otherwise inhibits */
450/* updates. */
451/* If there is more than one thread with the given id we */
452/* return the most recent one. */
453GC_thread GC_lookup_thread(pthread_t id)
454{
455 int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
456 register GC_thread p = GC_threads[hv];
457
458 while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;
459 return(p);
460}
461
462#ifdef HANDLE_FORK
463/* Remove all entries from the GC_threads table, except the */
464/* one for the current thread. We need to do this in the child */
465/* process after a fork(), since only the current thread */
466/* survives in the child. */
467void GC_remove_all_threads_but_me(void)
468{
469 pthread_t self = pthread_self();
470 int hv;
471 GC_thread p, next, me;
472
473 for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
474 me = 0;
475 for (p = GC_threads[hv]; 0 != p; p = next) {
476 next = p -> next;
477 if (THREAD_EQUAL(p -> id, self)) {
478 me = p;
479 p -> next = 0;
480 } else {
481# ifdef THREAD_LOCAL_ALLOC
482 if (!(p -> flags & FINISHED)) {
483 GC_destroy_thread_local(&(p->tlfs));
484 }
485# endif /* THREAD_LOCAL_ALLOC */
486 if (p != &first_thread) GC_INTERNAL_FREE(p);
487 }
488 }
489 GC_threads[hv] = me;
490 }
491}
492#endif /* HANDLE_FORK */
493
494#ifdef USE_PROC_FOR_LIBRARIES
495GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
496{
497 int i;
498 GC_thread p;
499
500 GC_ASSERT(I_HOLD_LOCK());
501# ifdef PARALLEL_MARK
502 for (i = 0; i < GC_markers; ++i) {
503 if (marker_sp[i] > lo & marker_sp[i] < hi) return TRUE;
504# ifdef IA64
505 if (marker_bsp[i] > lo & marker_bsp[i] < hi) return TRUE;
506# endif
507 }
508# endif
509 for (i = 0; i < THREAD_TABLE_SZ; i++) {
510 for (p = GC_threads[i]; p != 0; p = p -> next) {
511 if (0 != p -> stack_end) {
512# ifdef STACK_GROWS_UP
513 if (p -> stack_end >= lo && p -> stack_end < hi) return TRUE;
514# else /* STACK_GROWS_DOWN */
515 if (p -> stack_end > lo && p -> stack_end <= hi) return TRUE;
516# endif
517 }
518 }
519 }
520 return FALSE;
521}
522#endif /* USE_PROC_FOR_LIBRARIES */
523
524#ifdef IA64
525/* Find the largest stack_base smaller than bound. May be used */
526/* to find the boundary between a register stack and adjacent */
527/* immediately preceding memory stack. */
528ptr_t GC_greatest_stack_base_below(ptr_t bound)
529{
530 int i;
531 GC_thread p;
532 ptr_t result = 0;
533
534 GC_ASSERT(I_HOLD_LOCK());
535# ifdef PARALLEL_MARK
536 for (i = 0; i < GC_markers; ++i) {
537 if (marker_sp[i] > result && marker_sp[i] < bound)
538 result = marker_sp[i];
539 }
540# endif
541 for (i = 0; i < THREAD_TABLE_SZ; i++) {
542 for (p = GC_threads[i]; p != 0; p = p -> next) {
543 if (p -> stack_end > result && p -> stack_end < bound) {
544 result = p -> stack_end;
545 }
546 }
547 }
548 return result;
549}
550#endif /* IA64 */
551
552#ifdef GC_LINUX_THREADS
553/* Return the number of processors, or i<= 0 if it can't be determined. */
554int GC_get_nprocs(void)
555{
556 /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
557 /* appears to be buggy in many cases. */
558 /* We look for lines "cpu<n>" in /proc/stat. */
559# define STAT_BUF_SIZE 4096
560# define STAT_READ read
561 /* If read is wrapped, this may need to be redefined to call */
562 /* the real one. */
563 char stat_buf[STAT_BUF_SIZE];
564 int f;
565 word result = 1;
566 /* Some old kernels only have a single "cpu nnnn ..." */
567 /* entry in /proc/stat. We identify those as */
568 /* uniprocessors. */
569 size_t i, len = 0;
570
571 f = open("/proc/stat", O_RDONLY);
572 if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
573 WARN("Couldn't read /proc/stat\n", 0);
574 return -1;
575 }
576 for (i = 0; i < len - 100; ++i) {
577 if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
578 && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
579 int cpu_no = atoi(stat_buf + i + 4);
580 if (cpu_no >= result) result = cpu_no + 1;
581 }
582 }
583 close(f);
584 return result;
585}
586#endif /* GC_LINUX_THREADS */
587
588/* We hold the GC lock. Wait until an in-progress GC has finished. */
589/* Repeatedly RELEASES GC LOCK in order to wait. */
590/* If wait_for_all is true, then we exit with the GC lock held and no */
591/* collection in progress; otherwise we just wait for the current GC */
592/* to finish. */
593extern GC_bool GC_collection_in_progress(void);
594void GC_wait_for_gc_completion(GC_bool wait_for_all)
595{
596 GC_ASSERT(I_HOLD_LOCK());
597 if (GC_incremental && GC_collection_in_progress()) {
598 int old_gc_no = GC_gc_no;
599
600 /* Make sure that no part of our stack is still on the mark stack, */
601 /* since it's about to be unmapped. */
602 while (GC_incremental && GC_collection_in_progress()
603 && (wait_for_all || old_gc_no == GC_gc_no)) {
604 ENTER_GC();
605 GC_in_thread_creation = TRUE;
606 GC_collect_a_little_inner(1);
607 GC_in_thread_creation = FALSE;
608 EXIT_GC();
609 UNLOCK();
610 sched_yield();
611 LOCK();
612 }
613 }
614}
615
616#ifdef HANDLE_FORK
617/* Procedures called before and after a fork. The goal here is to make */
618/* it safe to call GC_malloc() in a forked child. It's unclear that is */
619/* attainable, since the single UNIX spec seems to imply that one */
620/* should only call async-signal-safe functions, and we probably can't */
621/* quite guarantee that. But we give it our best shot. (That same */
622/* spec also implies that it's not safe to call the system malloc */
623/* between fork() and exec(). Thus we're doing no worse than it. */
624
625/* Called before a fork() */
626void GC_fork_prepare_proc(void)
627{
628 /* Acquire all relevant locks, so that after releasing the locks */
629 /* the child will see a consistent state in which monitor */
630 /* invariants hold. Unfortunately, we can't acquire libc locks */
631 /* we might need, and there seems to be no guarantee that libc */
632 /* must install a suitable fork handler. */
633 /* Wait for an ongoing GC to finish, since we can't finish it in */
634 /* the (one remaining thread in) the child. */
635 LOCK();
636# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
637 GC_wait_for_reclaim();
638# endif
639 GC_wait_for_gc_completion(TRUE);
640# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
641 GC_acquire_mark_lock();
642# endif
643}
644
645/* Called in parent after a fork() */
646void GC_fork_parent_proc(void)
647{
648# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
649 GC_release_mark_lock();
650# endif
651 UNLOCK();
652}
653
654/* Called in child after a fork() */
655void GC_fork_child_proc(void)
656{
657 /* Clean up the thread table, so that just our thread is left. */
658# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
659 GC_release_mark_lock();
660# endif
661 GC_remove_all_threads_but_me();
662# ifdef PARALLEL_MARK
663 /* Turn off parallel marking in the child, since we are probably */
664 /* just going to exec, and we would have to restart mark threads. */
665 GC_markers = 1;
666 GC_parallel = FALSE;
667# endif /* PARALLEL_MARK */
668 UNLOCK();
669}
670#endif /* HANDLE_FORK */
671
672#if defined(GC_DGUX386_THREADS)
673/* Return the number of processors, or i<= 0 if it can't be determined. */
674int GC_get_nprocs(void)
675{
676 /* <takis@XFree86.Org> */
677 int numCpus;
678 struct dg_sys_info_pm_info pm_sysinfo;
679 int status =0;
680
681 status = dg_sys_info((long int *) &pm_sysinfo,
682 DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
683 if (status < 0)
684 /* set -1 for error */
685 numCpus = -1;
686 else
687 /* Active CPUs */
688 numCpus = pm_sysinfo.idle_vp_count;
689
690# ifdef DEBUG_THREADS
691 GC_printf("Number of active CPUs in this system: %d\n", numCpus);
692# endif
693 return(numCpus);
694}
695#endif /* GC_DGUX386_THREADS */
696
697#if defined(GC_NETBSD_THREADS)
698static int get_ncpu(void)
699{
700 int mib[] = {CTL_HW,HW_NCPU};
701 int res;
702 size_t len = sizeof(res);
703
704 sysctl(mib, sizeof(mib)/sizeof(int), &res, &len, NULL, 0);
705 return res;
706}
707#endif /* GC_NETBSD_THREADS */
708
709# if defined(GC_LINUX_THREADS) && defined(INCLUDE_LINUX_THREAD_DESCR)
710__thread int dummy_thread_local;
711# endif
712
713/* We hold the allocation lock. */
714void GC_thr_init(void)
715{
716# ifndef GC_DARWIN_THREADS
717 int dummy;
718# endif
719 GC_thread t;
720
721 if (GC_thr_initialized) return;
722 GC_thr_initialized = TRUE;
723
724# ifdef HANDLE_FORK
725 /* Prepare for a possible fork. */
726 pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
727 GC_fork_child_proc);
728# endif /* HANDLE_FORK */
729# if defined(INCLUDE_LINUX_THREAD_DESCR)
730 /* Explicitly register the region including the address */
731 /* of a thread local variable. This should included thread */
732 /* locals for the main thread, except for those allocated */
733 /* in response to dlopen calls. */
734 {
735 ptr_t thread_local_addr = (ptr_t)(&dummy_thread_local);
736 ptr_t main_thread_start, main_thread_end;
737 if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
738 &main_thread_end)) {
739 ABORT("Failed to find mapping for main thread thread locals");
740 }
741 GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
742 }
743# endif
744 /* Add the initial thread, so we can stop it. */
745 t = GC_new_thread(pthread_self());
746# ifdef GC_DARWIN_THREADS
747 t -> stop_info.mach_thread = mach_thread_self();
748# else
749 t -> stop_info.stack_ptr = (ptr_t)(&dummy);
750# endif
751 t -> flags = DETACHED | MAIN_THREAD;
752
753 GC_stop_init();
754
755 /* Set GC_nprocs. */
756 {
757 char * nprocs_string = GETENV("GC_NPROCS");
758 GC_nprocs = -1;
759 if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
760 }
761 if (GC_nprocs <= 0) {
762# if defined(GC_HPUX_THREADS)
763 GC_nprocs = pthread_num_processors_np();
764# endif
765# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
766 || defined(GC_SOLARIS_THREADS)
767 GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
768 if (GC_nprocs <= 0) GC_nprocs = 1;
769# endif
770# if defined(GC_IRIX_THREADS)
771 GC_nprocs = sysconf(_SC_NPROC_ONLN);
772 if (GC_nprocs <= 0) GC_nprocs = 1;
773# endif
774# if defined(GC_NETBSD_THREADS)
775 GC_nprocs = get_ncpu();
776# endif
777# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
778 int ncpus = 1;
779 size_t len = sizeof(ncpus);
780 sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
781 GC_nprocs = ncpus;
782# endif
783# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
784 GC_nprocs = GC_get_nprocs();
785# endif
786# if defined(GC_GNU_THREADS)
787 if (GC_nprocs <= 0) GC_nprocs = 1;
788# endif
789 }
790 if (GC_nprocs <= 0) {
791 WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
792 GC_nprocs = 2;
793# ifdef PARALLEL_MARK
794 GC_markers = 1;
795# endif
796 } else {
797# ifdef PARALLEL_MARK
798 {
799 char * markers_string = GETENV("GC_MARKERS");
800 if (markers_string != NULL) {
801 GC_markers = atoi(markers_string);
802 } else {
803 GC_markers = GC_nprocs;
804 }
805 }
806# endif
807 }
808# ifdef PARALLEL_MARK
809 if (GC_print_stats) {
810 GC_log_printf("Number of processors = %ld, "
811 "number of marker threads = %ld\n", GC_nprocs, GC_markers);
812 }
813 if (GC_markers == 1) {
814 GC_parallel = FALSE;
815 if (GC_print_stats) {
816 GC_log_printf(
817 "Single marker thread, turning off parallel marking\n");
818 }
819 } else {
820 GC_parallel = TRUE;
821 /* Disable true incremental collection, but generational is OK. */
822 GC_time_limit = GC_TIME_UNLIMITED;
823 }
824 /* If we are using a parallel marker, actually start helper threads. */
825 if (GC_parallel) start_mark_threads();
826# endif
827}
828
829
830/* Perform all initializations, including those that */
831/* may require allocation. */
832/* Called without allocation lock. */
833/* Must be called before a second thread is created. */
834/* Did we say it's called without the allocation lock? */
835void GC_init_parallel(void)
836{
837 if (parallel_initialized) return;
838 parallel_initialized = TRUE;
839
840 /* GC_init() calls us back, so set flag first. */
841 if (!GC_is_initialized) GC_init();
842 /* Initialize thread local free lists if used. */
843# if defined(THREAD_LOCAL_ALLOC)
844 LOCK();
845 GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
846 UNLOCK();
847# endif
848}
849
850
851#if !defined(GC_DARWIN_THREADS)
852int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
853{
854 sigset_t fudged_set;
855
856 INIT_REAL_SYMS();
857 if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
858 fudged_set = *set;
859 sigdelset(&fudged_set, SIG_SUSPEND);
860 set = &fudged_set;
861 }
862 return(REAL_FUNC(pthread_sigmask)(how, set, oset));
863}
864#endif /* !GC_DARWIN_THREADS */
865
866/* Wrapper for functions that are likely to block for an appreciable */
867/* length of time. */
868
869struct blocking_data {
870 void (*fn)(void *);
871 void *arg;
872};
873
874static void GC_do_blocking_inner(ptr_t data, void * context) {
875 struct blocking_data * d = (struct blocking_data *) data;
876 GC_thread me;
877 LOCK();
878 me = GC_lookup_thread(pthread_self());
879 GC_ASSERT(!(me -> thread_blocked));
880# ifdef SPARC
881 me -> stop_info.stack_ptr = GC_save_regs_in_stack();
882# elif !defined(GC_DARWIN_THREADS)
883 me -> stop_info.stack_ptr = GC_approx_sp();
884# endif
885# ifdef IA64
886 me -> backing_store_ptr = GC_save_regs_in_stack();
887# endif
888 me -> thread_blocked = TRUE;
889 /* Save context here if we want to support precise stack marking */
890 UNLOCK();
891 (d -> fn)(d -> arg);
892 LOCK(); /* This will block if the world is stopped. */
893 me -> thread_blocked = FALSE;
894 UNLOCK();
895}
896
897void GC_do_blocking(void (*fn)(void *), void *arg) {
898 struct blocking_data my_data;
899
900 my_data.fn = fn;
901 my_data.arg = arg;
902 GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
903}
904
905struct start_info {
906 void *(*start_routine)(void *);
907 void *arg;
908 word flags;
909 sem_t registered; /* 1 ==> in our thread table, but */
910 /* parent hasn't yet noticed. */
911};
912
913int GC_unregister_my_thread(void)
914{
915 GC_thread me;
916
917 LOCK();
918 /* Wait for any GC that may be marking from our stack to */
919 /* complete before we remove this thread. */
920 GC_wait_for_gc_completion(FALSE);
921 me = GC_lookup_thread(pthread_self());
922# if defined(THREAD_LOCAL_ALLOC)
923 GC_destroy_thread_local(&(me->tlfs));
924# endif
925 if (me -> flags & DETACHED) {
926 GC_delete_thread(pthread_self());
927 } else {
928 me -> flags |= FINISHED;
929 }
930# if defined(THREAD_LOCAL_ALLOC)
931 GC_remove_specific(GC_thread_key);
932# endif
933 UNLOCK();
934 return GC_SUCCESS;
935}
936
937/* Called at thread exit. */
938/* Never called for main thread. That's OK, since it */
939/* results in at most a tiny one-time leak. And */
940/* linuxthreads doesn't reclaim the main threads */
941/* resources or id anyway. */
942void GC_thread_exit_proc(void *arg)
943{
944 GC_unregister_my_thread();
945}
946
947int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
948{
949 int result;
950 GC_thread thread_gc_id;
951
952 INIT_REAL_SYMS();
953 LOCK();
954 thread_gc_id = GC_lookup_thread(thread);
955 /* This is guaranteed to be the intended one, since the thread id */
956 /* cant have been recycled by pthreads. */
957 UNLOCK();
958 result = REAL_FUNC(pthread_join)(thread, retval);
959# if defined (GC_FREEBSD_THREADS)
960 /* On FreeBSD, the wrapped pthread_join() sometimes returns (what
961 appears to be) a spurious EINTR which caused the test and real code
962 to gratuitously fail. Having looked at system pthread library source
963 code, I see how this return code may be generated. In one path of
964 code, pthread_join() just returns the errno setting of the thread
965 being joined. This does not match the POSIX specification or the
966 local man pages thus I have taken the liberty to catch this one
967 spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
968 if (result == EINTR) result = 0;
969# endif
970 if (result == 0) {
971 LOCK();
972 /* Here the pthread thread id may have been recycled. */
973 GC_delete_gc_thread(thread_gc_id);
974 UNLOCK();
975 }
976 return result;
977}
978
979int
980WRAP_FUNC(pthread_detach)(pthread_t thread)
981{
982 int result;
983 GC_thread thread_gc_id;
984
985 INIT_REAL_SYMS();
986 LOCK();
987 thread_gc_id = GC_lookup_thread(thread);
988 UNLOCK();
989 result = REAL_FUNC(pthread_detach)(thread);
990 if (result == 0) {
991 LOCK();
992 thread_gc_id -> flags |= DETACHED;
993 /* Here the pthread thread id may have been recycled. */
994 if (thread_gc_id -> flags & FINISHED) {
995 GC_delete_gc_thread(thread_gc_id);
996 }
997 UNLOCK();
998 }
999 return result;
1000}
1001
1002GC_bool GC_in_thread_creation = FALSE; /* Protected by allocation lock. */
1003
1004GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
1005 pthread_t my_pthread)
1006{
1007 GC_thread me;
1008
1009 GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
1010 me = GC_new_thread(my_pthread);
1011 GC_in_thread_creation = FALSE;
1012# ifdef GC_DARWIN_THREADS
1013 me -> stop_info.mach_thread = mach_thread_self();
1014# else
1015 me -> stop_info.stack_ptr = sb -> mem_base;
1016# endif
1017 me -> stack_end = sb -> mem_base;
1018# ifdef IA64
1019 me -> backing_store_end = sb -> reg_base;
1020# endif /* IA64 */
1021 return me;
1022}
1023
1024int GC_register_my_thread(struct GC_stack_base *sb)
1025{
1026 pthread_t my_pthread = pthread_self();
1027 GC_thread me;
1028
1029 LOCK();
1030 me = GC_lookup_thread(my_pthread);
1031 if (0 == me) {
1032 me = GC_register_my_thread_inner(sb, my_pthread);
1033 me -> flags |= DETACHED;
1034 /* Treat as detached, since we do not need to worry about */
1035 /* pointer results. */
1036 UNLOCK();
1037 return GC_SUCCESS;
1038 } else {
1039 UNLOCK();
1040 return GC_DUPLICATE;
1041 }
1042}
1043
1044void * GC_inner_start_routine(struct GC_stack_base *sb, void * arg)
1045{
1046 struct start_info * si = arg;
1047 void * result;
1048 GC_thread me;
1049 pthread_t my_pthread;
1050 void *(*start)(void *);
1051 void *start_arg;
1052
1053 my_pthread = pthread_self();
1054# ifdef DEBUG_THREADS
1055 GC_printf("Starting thread 0x%x\n", (unsigned)my_pthread);
1056 GC_printf("pid = %ld\n", (long) getpid());
1057 GC_printf("sp = 0x%lx\n", (long) &arg);
1058# endif
1059 LOCK();
1060 me = GC_register_my_thread_inner(sb, my_pthread);
1061 me -> flags = si -> flags;
1062 UNLOCK();
1063 start = si -> start_routine;
1064# ifdef DEBUG_THREADS
1065 GC_printf("start_routine = %p\n", (void *)start);
1066# endif
1067 start_arg = si -> arg;
1068 sem_post(&(si -> registered)); /* Last action on si. */
1069 /* OK to deallocate. */
1070 pthread_cleanup_push(GC_thread_exit_proc, 0);
1071# if defined(THREAD_LOCAL_ALLOC)
1072 LOCK();
1073 GC_init_thread_local(&(me->tlfs));
1074 UNLOCK();
1075# endif
1076 result = (*start)(start_arg);
1077# if DEBUG_THREADS
1078 GC_printf("Finishing thread 0x%x\n", (unsigned)pthread_self());
1079# endif
1080 me -> status = result;
1081 pthread_cleanup_pop(1);
1082 /* Cleanup acquires lock, ensuring that we can't exit */
1083 /* while a collection that thinks we're alive is trying to stop */
1084 /* us. */
1085 return(result);
1086}
1087
1088void * GC_start_routine(void * arg)
1089{
1090# ifdef INCLUDE_LINUX_THREAD_DESCR
1091 struct GC_stack_base sb;
1092
1093# ifdef REDIRECT_MALLOC
1094 /* GC_get_stack_base may call pthread_getattr_np, which can */
1095 /* unfortunately call realloc, which may allocate from an */
1096 /* unregistered thread. This is unpleasant, since it might */
1097 /* force heap growth. */
1098 GC_disable();
1099# endif
1100 if (GC_get_stack_base(&sb) != GC_SUCCESS)
1101 ABORT("Failed to get thread stack base.");
1102# ifdef REDIRECT_MALLOC
1103 GC_enable();
1104# endif
1105 return GC_inner_start_routine(&sb, arg);
1106# else
1107 return GC_call_with_stack_base(GC_inner_start_routine, arg);
1108# endif
1109}
1110
1111int
1112WRAP_FUNC(pthread_create)(pthread_t *new_thread,
1113 const pthread_attr_t *attr,
1114 void *(*start_routine)(void *), void *arg)
1115{
1116 int result;
1117 int detachstate;
1118 word my_flags = 0;
1119 struct start_info * si;
1120 /* This is otherwise saved only in an area mmapped by the thread */
1121 /* library, which isn't visible to the collector. */
1122
1123 /* We resist the temptation to muck with the stack size here, */
1124 /* even if the default is unreasonably small. That's the client's */
1125 /* responsibility. */
1126
1127 INIT_REAL_SYMS();
1128 LOCK();
1129 si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
1130 NORMAL);
1131 UNLOCK();
1132 if (!parallel_initialized) GC_init_parallel();
1133 if (0 == si) return(ENOMEM);
1134 sem_init(&(si -> registered), 0, 0);
1135 si -> start_routine = start_routine;
1136 si -> arg = arg;
1137 LOCK();
1138 if (!GC_thr_initialized) GC_thr_init();
1139# ifdef GC_ASSERTIONS
1140 {
1141 size_t stack_size = 0;
1142 if (NULL != attr) {
1143 pthread_attr_getstacksize(attr, &stack_size);
1144 }
1145 if (0 == stack_size) {
1146 pthread_attr_t my_attr;
1147 pthread_attr_init(&my_attr);
1148 pthread_attr_getstacksize(&my_attr, &stack_size);
1149 }
1150 /* On Solaris 10, with default attr initialization, */
1151 /* stack_size remains 0. Fudge it. */
1152 if (0 == stack_size) {
1153# ifndef SOLARIS
1154 WARN("Failed to get stack size for assertion checking\n", 0);
1155# endif
1156 stack_size = 1000000;
1157 }
1158# ifdef PARALLEL_MARK
1159 GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
1160# else
1161 /* FreeBSD-5.3/Alpha: default pthread stack is 64K, */
1162 /* HBLKSIZE=8192, sizeof(word)=8 */
1163 GC_ASSERT(stack_size >= 65536);
1164# endif
1165 /* Our threads may need to do some work for the GC. */
1166 /* Ridiculously small threads won't work, and they */
1167 /* probably wouldn't work anyway. */
1168 }
1169# endif
1170 if (NULL == attr) {
1171 detachstate = PTHREAD_CREATE_JOINABLE;
1172 } else {
1173 pthread_attr_getdetachstate(attr, &detachstate);
1174 }
1175 if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
1176 si -> flags = my_flags;
1177 UNLOCK();
1178# ifdef DEBUG_THREADS
1179 GC_printf("About to start new thread from thread 0x%x\n",
1180 (unsigned)pthread_self());
1181# endif
1182 GC_need_to_lock = TRUE;
1183
1184 result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
1185
1186# ifdef DEBUG_THREADS
1187 GC_printf("Started thread 0x%x\n", (unsigned)(*new_thread));
1188# endif
1189 /* Wait until child has been added to the thread table. */
1190 /* This also ensures that we hold onto si until the child is done */
1191 /* with it. Thus it doesn't matter whether it is otherwise */
1192 /* visible to the collector. */
1193 if (0 == result) {
1194 while (0 != sem_wait(&(si -> registered))) {
1195 if (EINTR != errno) ABORT("sem_wait failed");
1196 }
1197 }
1198 sem_destroy(&(si -> registered));
1199 LOCK();
1200 GC_INTERNAL_FREE(si);
1201 UNLOCK();
1202
1203 return(result);
1204}
1205
1206/* Spend a few cycles in a way that can't introduce contention with */
1207/* othre threads. */
1208void GC_pause(void)
1209{
1210 int i;
1211# if !defined(__GNUC__) || defined(__INTEL_COMPILER)
1212 volatile word dummy = 0;
1213# endif
1214
1215 for (i = 0; i < 10; ++i) {
1216# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
1217 __asm__ __volatile__ (" " : : : "memory");
1218# else
1219 /* Something that's unlikely to be optimized away. */
1220 GC_noop(++dummy);
1221# endif
1222 }
1223}
1224
1225#define SPIN_MAX 128 /* Maximum number of calls to GC_pause before */
1226 /* give up. */
1227
1228volatile GC_bool GC_collecting = 0;
1229 /* A hint that we're in the collector and */
1230 /* holding the allocation lock for an */
1231 /* extended period. */
1232
1233#if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK)
1234/* If we don't want to use the below spinlock implementation, either */
1235/* because we don't have a GC_test_and_set implementation, or because */
1236/* we don't want to risk sleeping, we can still try spinning on */
1237/* pthread_mutex_trylock for a while. This appears to be very */
1238/* beneficial in many cases. */
1239/* I suspect that under high contention this is nearly always better */
1240/* than the spin lock. But it's a bit slower on a uniprocessor. */
1241/* Hence we still default to the spin lock. */
1242/* This is also used to acquire the mark lock for the parallel */
1243/* marker. */
1244
1245/* Here we use a strict exponential backoff scheme. I don't know */
1246/* whether that's better or worse than the above. We eventually */
1247/* yield by calling pthread_mutex_lock(); it never makes sense to */
1248/* explicitly sleep. */
1249
1250#define LOCK_STATS
1251#ifdef LOCK_STATS
1252 unsigned long GC_spin_count = 0;
1253 unsigned long GC_block_count = 0;
1254 unsigned long GC_unlocked_count = 0;
1255#endif
1256
1257void GC_generic_lock(pthread_mutex_t * lock)
1258{
1259#ifndef NO_PTHREAD_TRYLOCK
1260 unsigned pause_length = 1;
1261 unsigned i;
1262
1263 if (0 == pthread_mutex_trylock(lock)) {
1264# ifdef LOCK_STATS
1265 ++GC_unlocked_count;
1266# endif
1267 return;
1268 }
1269 for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
1270 for (i = 0; i < pause_length; ++i) {
1271 GC_pause();
1272 }
1273 switch(pthread_mutex_trylock(lock)) {
1274 case 0:
1275# ifdef LOCK_STATS
1276 ++GC_spin_count;
1277# endif
1278 return;
1279 case EBUSY:
1280 break;
1281 default:
1282 ABORT("Unexpected error from pthread_mutex_trylock");
1283 }
1284 }
1285#endif /* !NO_PTHREAD_TRYLOCK */
1286# ifdef LOCK_STATS
1287 ++GC_block_count;
1288# endif
1289 pthread_mutex_lock(lock);
1290}
1291
1292#endif /* !USE_SPIN_LOCK || PARALLEL_MARK */
1293
1294#if defined(USE_SPIN_LOCK)
1295
1296/* Reasonably fast spin locks. Basically the same implementation */
1297/* as STL alloc.h. This isn't really the right way to do this. */
1298/* but until the POSIX scheduling mess gets straightened out ... */
1299
1300volatile AO_TS_t GC_allocate_lock = 0;
1301
1302
1303void GC_lock(void)
1304{
1305# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
1306# define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
1307 static unsigned spin_max = low_spin_max;
1308 unsigned my_spin_max;
1309 static unsigned last_spins = 0;
1310 unsigned my_last_spins;
1311 int i;
1312
1313 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
1314 return;
1315 }
1316 my_spin_max = spin_max;
1317 my_last_spins = last_spins;
1318 for (i = 0; i < my_spin_max; i++) {
1319 if (GC_collecting || GC_nprocs == 1) goto yield;
1320 if (i < my_last_spins/2) {
1321 GC_pause();
1322 continue;
1323 }
1324 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
1325 /*
1326 * got it!
1327 * Spinning worked. Thus we're probably not being scheduled
1328 * against the other process with which we were contending.
1329 * Thus it makes sense to spin longer the next time.
1330 */
1331 last_spins = i;
1332 spin_max = high_spin_max;
1333 return;
1334 }
1335 }
1336 /* We are probably being scheduled against the other process. Sleep. */
1337 spin_max = low_spin_max;
1338yield:
1339 for (i = 0;; ++i) {
1340 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
1341 return;
1342 }
1343# define SLEEP_THRESHOLD 12
1344 /* Under Linux very short sleeps tend to wait until */
1345 /* the current time quantum expires. On old Linux */
1346 /* kernels nanosleep(<= 2ms) just spins under Linux. */
1347 /* (Under 2.4, this happens only for real-time */
1348 /* processes.) We want to minimize both behaviors */
1349 /* here. */
1350 if (i < SLEEP_THRESHOLD) {
1351 sched_yield();
1352 } else {
1353 struct timespec ts;
1354
1355 if (i > 24) i = 24;
1356 /* Don't wait for more than about 15msecs, even */
1357 /* under extreme contention. */
1358 ts.tv_sec = 0;
1359 ts.tv_nsec = 1 << i;
1360 nanosleep(&ts, 0);
1361 }
1362 }
1363}
1364
1365#else /* !USE_SPINLOCK */
1366void GC_lock(void)
1367{
1368#ifndef NO_PTHREAD_TRYLOCK
1369 if (1 == GC_nprocs || GC_collecting) {
1370 pthread_mutex_lock(&GC_allocate_ml);
1371 } else {
1372 GC_generic_lock(&GC_allocate_ml);
1373 }
1374#else /* !NO_PTHREAD_TRYLOCK */
1375 pthread_mutex_lock(&GC_allocate_ml);
1376#endif /* !NO_PTHREAD_TRYLOCK */
1377}
1378
1379#endif /* !USE_SPINLOCK */
1380
1381#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
1382
1383#ifdef GC_ASSERTIONS
1384 unsigned long GC_mark_lock_holder = NO_THREAD;
1385#endif
1386
1387#if 0
1388 /* Ugly workaround for a linux threads bug in the final versions */
1389 /* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
1390 /* field even when it fails to acquire the mutex. This causes */
1391 /* pthread_cond_wait to die. Remove for glibc2.2. */
1392 /* According to the man page, we should use */
1393 /* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
1394 /* defined. */
1395 static pthread_mutex_t mark_mutex =
1396 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
1397#else
1398 static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
1399#endif
1400
1401static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
1402
1403void GC_acquire_mark_lock(void)
1404{
1405/*
1406 if (pthread_mutex_lock(&mark_mutex) != 0) {
1407 ABORT("pthread_mutex_lock failed");
1408 }
1409*/
1410 GC_generic_lock(&mark_mutex);
1411# ifdef GC_ASSERTIONS
1412 GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
1413# endif
1414}
1415
1416void GC_release_mark_lock(void)
1417{
1418 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1419# ifdef GC_ASSERTIONS
1420 GC_mark_lock_holder = NO_THREAD;
1421# endif
1422 if (pthread_mutex_unlock(&mark_mutex) != 0) {
1423 ABORT("pthread_mutex_unlock failed");
1424 }
1425}
1426
1427/* Collector must wait for a freelist builders for 2 reasons: */
1428/* 1) Mark bits may still be getting examined without lock. */
1429/* 2) Partial free lists referenced only by locals may not be scanned */
1430/* correctly, e.g. if they contain "pointer-free" objects, since the */
1431/* free-list link may be ignored. */
1432void GC_wait_builder(void)
1433{
1434 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1435# ifdef GC_ASSERTIONS
1436 GC_mark_lock_holder = NO_THREAD;
1437# endif
1438 if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
1439 ABORT("pthread_cond_wait failed");
1440 }
1441 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
1442# ifdef GC_ASSERTIONS
1443 GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
1444# endif
1445}
1446
1447void GC_wait_for_reclaim(void)
1448{
1449 GC_acquire_mark_lock();
1450 while (GC_fl_builder_count > 0) {
1451 GC_wait_builder();
1452 }
1453 GC_release_mark_lock();
1454}
1455
1456void GC_notify_all_builder(void)
1457{
1458 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1459 if (pthread_cond_broadcast(&builder_cv) != 0) {
1460 ABORT("pthread_cond_broadcast failed");
1461 }
1462}
1463
1464#endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
1465
1466#ifdef PARALLEL_MARK
1467
1468static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
1469
1470void GC_wait_marker(void)
1471{
1472 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1473# ifdef GC_ASSERTIONS
1474 GC_mark_lock_holder = NO_THREAD;
1475# endif
1476 if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
1477 ABORT("pthread_cond_wait failed");
1478 }
1479 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
1480# ifdef GC_ASSERTIONS
1481 GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
1482# endif
1483}
1484
1485void GC_notify_all_marker(void)
1486{
1487 if (pthread_cond_broadcast(&mark_cv) != 0) {
1488 ABORT("pthread_cond_broadcast failed");
1489 }
1490}
1491
1492#endif /* PARALLEL_MARK */
1493
1494# endif /* GC_LINUX_THREADS and friends */
1495