2 * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
4 * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
6 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9 * Permission is hereby granted to use or copy this program
10 * for any purpose, provided the above notices are retained on all copies.
11 * Permission to modify the code and to distribute modified code is granted,
12 * provided the above notices are retained, and a notice that the code was
13 * modified is included with the above copyright notice.
16 * Support code for Irix (>=6.2) Pthreads and for AIX pthreads.
17 * This relies on properties
18 * not guaranteed by the Pthread standard. It may or may not be portable
19 * to other implementations.
21 * Note that there is a lot of code duplication between this file and
22 * (pthread_support.c, pthread_stop_world.c). They should be merged.
23 * Pthread_support.c should be directly usable.
25 * Please avoid adding new ports here; use the generic pthread support
29 # if defined(GC_IRIX_THREADS) || defined(GC_AIX_THREADS)
31 # include "private/gc_priv.h"
34 # include <semaphore.h>
38 # include <sys/mman.h>
39 # include <sys/time.h>
42 #undef pthread_sigmask
45 #if defined(GC_IRIX_THREADS) && !defined(MUTEX_RECURSIVE_NP)
46 #define MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
52 void GC_print_sig_mask()
57 if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
58 ABORT("pthread_sigmask");
59 GC_printf0("Blocked: ");
60 for (i = 1; i <= MAXSIG; i++) {
61 if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
67 /* We use the allocation lock to protect thread-related data structures. */
69 /* The set of all known threads. We intercept thread creation and */
70 /* joins. We never actually create detached threads. We allocate all */
71 /* new thread stacks ourselves. These allow us to maintain this */
73 /* Protected by GC_thr_lock. */
74 /* Some of this should be declared volatile, but that's incosnsistent */
75 /* with some library routine declarations. */
76 typedef struct GC_Thread_Rep {
77 struct GC_Thread_Rep * next; /* More recently allocated threads */
78 /* with a given pthread id come */
79 /* first. (All but the first are */
80 /* guaranteed to be dead, but we may */
81 /* not yet have registered the join.) */
84 # define NOT_STOPPED 0
85 # define PLEASE_STOP 1
88 # define FINISHED 1 /* Thread has exited. */
89 # define DETACHED 2 /* Thread is intended to be detached. */
90 # define CLIENT_OWNS_STACK 4
91 /* Stack was supplied by client. */
93 ptr_t stack_ptr; /* Valid only when stopped. */
94 /* But must be within stack region at */
96 size_t stack_size; /* 0 for original thread. */
97 void * status; /* Used only to avoid premature */
98 /* reclamation of any data it might */
102 GC_thread GC_lookup_thread(pthread_t id);
105 * The only way to suspend threads given the pthread interface is to send
106 * signals. Unfortunately, this means we have to reserve
107 * a signal, and intercept client calls to change the signal mask.
110 # if defined(GC_AIX_THREADS)
111 # define SIG_SUSPEND SIGUSR1
113 # define SIG_SUSPEND (SIGRTMIN + 6)
117 pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
118 /* Number of threads stopped so far */
119 pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;
120 pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;
122 void GC_suspend_handler(int sig)
130 if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
131 me = GC_lookup_thread(pthread_self());
132 /* The lookup here is safe, since I'm doing this on behalf */
133 /* of a thread which holds the allocation lock in order */
134 /* to stop the world. Thus concurrent modification of the */
135 /* data structure is impossible. */
136 if (PLEASE_STOP != me -> stop) {
137 /* Misdirected signal. */
138 pthread_mutex_unlock(&GC_suspend_lock);
141 pthread_mutex_lock(&GC_suspend_lock);
142 me -> stack_ptr = (ptr_t)(&dummy);
143 me -> stop = STOPPED;
144 pthread_cond_signal(&GC_suspend_ack_cv);
145 pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);
146 pthread_mutex_unlock(&GC_suspend_lock);
147 /* GC_printf1("Continuing 0x%x\n", pthread_self()); */
151 GC_bool GC_thr_initialized = FALSE;
153 size_t GC_min_stack_sz;
157 # define N_FREE_LISTS 25
158 ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
159 /* GC_stack_free_lists[i] is free list for stacks of */
160 /* size GC_min_stack_sz*2**i. */
161 /* Free lists are linked through first word. */
163 /* Return a stack of size at least *stack_size. *stack_size is */
164 /* replaced by the actual stack size. */
165 /* Caller holds allocation lock. */
166 ptr_t GC_stack_alloc(size_t * stack_size)
168 register size_t requested_sz = *stack_size;
169 register size_t search_sz = GC_min_stack_sz;
170 register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
171 register ptr_t result;
173 while (search_sz < requested_sz) {
177 if ((result = GC_stack_free_lists[index]) == 0
178 && (result = GC_stack_free_lists[index+1]) != 0) {
179 /* Try next size up. */
180 search_sz *= 2; index++;
183 GC_stack_free_lists[index] = *(ptr_t *)result;
185 result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz);
186 result = (ptr_t)(((word)result + GC_page_sz) & ~(GC_page_sz - 1));
187 /* Protect hottest page to detect overflow. */
188 # ifdef STACK_GROWS_UP
189 /* mprotect(result + search_sz, GC_page_sz, PROT_NONE); */
191 /* mprotect(result, GC_page_sz, PROT_NONE); */
192 result += GC_page_sz;
195 *stack_size = search_sz;
199 /* Caller holds allocation lock. */
200 void GC_stack_free(ptr_t stack, size_t size)
202 register int index = 0;
203 register size_t search_sz = GC_min_stack_sz;
205 while (search_sz < size) {
209 if (search_sz != size) ABORT("Bad stack size");
210 *(ptr_t *)stack = GC_stack_free_lists[index];
211 GC_stack_free_lists[index] = stack;
216 # define THREAD_TABLE_SZ 128 /* Must be power of 2 */
217 volatile GC_thread GC_threads[THREAD_TABLE_SZ];
219 void GC_push_thread_structures GC_PROTO((void))
221 GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
224 /* Add a thread to GC_threads. We assume it wasn't already there. */
225 /* Caller holds allocation lock. */
226 GC_thread GC_new_thread(pthread_t id)
228 int hv = ((word)id) % THREAD_TABLE_SZ;
230 static struct GC_Thread_Rep first_thread;
231 static GC_bool first_thread_used = FALSE;
233 if (!first_thread_used) {
234 result = &first_thread;
235 first_thread_used = TRUE;
236 /* Dont acquire allocation lock, since we may already hold it. */
238 result = (struct GC_Thread_Rep *)
239 GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
241 if (result == 0) return(0);
243 result -> next = GC_threads[hv];
244 GC_threads[hv] = result;
245 /* result -> flags = 0; */
246 /* result -> stop = 0; */
250 /* Delete a thread from GC_threads. We assume it is there. */
251 /* (The code intentionally traps if it wasn't.) */
252 /* Caller holds allocation lock. */
253 void GC_delete_thread(pthread_t id)
255 int hv = ((word)id) % THREAD_TABLE_SZ;
256 register GC_thread p = GC_threads[hv];
257 register GC_thread prev = 0;
259 while (!pthread_equal(p -> id, id)) {
264 GC_threads[hv] = p -> next;
266 prev -> next = p -> next;
270 /* If a thread has been joined, but we have not yet */
271 /* been notified, then there may be more than one thread */
272 /* in the table with the same pthread id. */
273 /* This is OK, but we need a way to delete a specific one. */
274 void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
276 int hv = ((word)id) % THREAD_TABLE_SZ;
277 register GC_thread p = GC_threads[hv];
278 register GC_thread prev = 0;
285 GC_threads[hv] = p -> next;
287 prev -> next = p -> next;
291 /* Return a GC_thread corresponding to a given thread_t. */
292 /* Returns 0 if it's not there. */
293 /* Caller holds allocation lock or otherwise inhibits */
295 /* If there is more than one thread with the given id we */
296 /* return the most recent one. */
297 GC_thread GC_lookup_thread(pthread_t id)
299 int hv = ((word)id) % THREAD_TABLE_SZ;
300 register GC_thread p = GC_threads[hv];
302 while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
306 #if defined(GC_AIX_THREADS)
309 pthread_t my_thread = pthread_self();
311 register GC_thread p;
313 struct timespec timeout;
315 for (i = 0; i < THREAD_TABLE_SZ; i++) {
316 for (p = GC_threads[i]; p != 0; p = p -> next) {
317 if (p -> id != my_thread) {
318 pthread_suspend_np(p->id);
322 /* GC_printf1("World stopped 0x%x\n", pthread_self()); */
325 void GC_start_world()
329 pthread_t my_thread = pthread_self();
331 /* GC_printf0("World starting\n"); */
332 for (i = 0; i < THREAD_TABLE_SZ; i++) {
333 for (p = GC_threads[i]; p != 0; p = p -> next) {
334 if (p -> id != my_thread) {
335 pthread_continue_np(p->id);
341 #else /* GC_AIX_THREADS */
343 /* Caller holds allocation lock. */
346 pthread_t my_thread = pthread_self();
348 register GC_thread p;
350 struct timespec timeout;
352 for (i = 0; i < THREAD_TABLE_SZ; i++) {
353 for (p = GC_threads[i]; p != 0; p = p -> next) {
354 if (p -> id != my_thread) {
355 if (p -> flags & FINISHED) {
359 p -> stop = PLEASE_STOP;
360 result = pthread_kill(p -> id, SIG_SUSPEND);
361 /* GC_printf1("Sent signal to 0x%x\n", p -> id); */
364 /* Not really there anymore. Possible? */
370 ABORT("pthread_kill failed");
375 pthread_mutex_lock(&GC_suspend_lock);
376 for (i = 0; i < THREAD_TABLE_SZ; i++) {
377 for (p = GC_threads[i]; p != 0; p = p -> next) {
378 while (p -> id != my_thread && p -> stop != STOPPED) {
379 clock_gettime(CLOCK_REALTIME, &timeout);
380 timeout.tv_nsec += 50000000; /* 50 msecs */
381 if (timeout.tv_nsec >= 1000000000) {
382 timeout.tv_nsec -= 1000000000;
385 result = pthread_cond_timedwait(&GC_suspend_ack_cv,
388 if (result == ETIMEDOUT) {
389 /* Signal was lost or misdirected. Try again. */
390 /* Duplicate signals should be benign. */
391 result = pthread_kill(p -> id, SIG_SUSPEND);
396 pthread_mutex_unlock(&GC_suspend_lock);
397 /* GC_printf1("World stopped 0x%x\n", pthread_self()); */
400 /* Caller holds allocation lock. */
401 void GC_start_world()
406 /* GC_printf0("World starting\n"); */
407 for (i = 0; i < THREAD_TABLE_SZ; i++) {
408 for (p = GC_threads[i]; p != 0; p = p -> next) {
409 p -> stop = NOT_STOPPED;
412 pthread_mutex_lock(&GC_suspend_lock);
413 /* All other threads are at pthread_cond_wait in signal handler. */
414 /* Otherwise we couldn't have acquired the lock. */
415 pthread_mutex_unlock(&GC_suspend_lock);
416 pthread_cond_broadcast(&GC_continue_cv);
419 #endif /* GC_AIX_THREADS */
422 --> not really supported yet.
423 int GC_is_thread_stack(ptr_t addr)
426 register GC_thread p;
428 for (i = 0; i < THREAD_TABLE_SZ; i++) {
429 for (p = GC_threads[i]; p != 0; p = p -> next) {
430 if (p -> stack_size != 0) {
431 if (p -> stack <= addr &&
432 addr < p -> stack + p -> stack_size)
441 /* We hold allocation lock. Should do exactly the right thing if the */
442 /* world is stopped. Should not fail if it isn't. */
443 void GC_push_all_stacks()
446 register GC_thread p;
447 register ptr_t sp = GC_approx_sp();
448 register ptr_t hot, cold;
449 pthread_t me = pthread_self();
451 if (!GC_thr_initialized) GC_thr_init();
452 /* GC_printf1("Pushing stacks from thread 0x%x\n", me); */
453 for (i = 0; i < THREAD_TABLE_SZ; i++) {
454 for (p = GC_threads[i]; p != 0; p = p -> next) {
455 if (p -> flags & FINISHED) continue;
456 if (pthread_equal(p -> id, me)) {
457 hot = GC_approx_sp();
459 #ifdef GC_AIX_THREADS
460 /* AIX doesn't use signals to suspend, so we need to get an accurate hot stack pointer */
461 pthread_t id = p -> id;
462 struct __pthrdsinfo pinfo;
465 int retval = pthread_getthrds_np(&id, PTHRDSINFO_QUERY_ALL, &pinfo, sizeof(pinfo), regbuf, &val);
466 if (retval != 0) { printf("ERROR: pthread_getthrds_np() failed in GC\n"); abort(); }
467 hot = (ptr_t)(unsigned long)pinfo.__pi_ustk;
468 if ((p -> stack_size != 0 &&
469 (pinfo.__pi_stackend != ((ptr_t)p -> stack) + p -> stack_size ||
470 p -> stack_ptr < p -> stack ||
471 p -> stack_ptr > ((ptr_t)p -> stack) + p -> stack_size))) {
472 printf("ERROR in GC_push_all_stacks() stack state:\n"
474 "p->stack_size: 0x%08x\n"
475 "p->stack_ptr: 0x%08x\n"
476 "(p->stack+p->stack_size): 0x%08x\n"
477 "pinfo.__pi_stackaddr: 0x%08x\n"
478 "pinfo.__pi_stacksize: 0x%08x\n"
479 "pinfo.__pi_stackend: 0x%08x\n"
480 "GC_stackbottom: 0x%08x\n"
482 (uintptr_t)p->stack, (uintptr_t)p->stack_size,
483 (uintptr_t)p->stack_ptr, (uintptr_t)(((ptr_t)(p->stack))+p->stack_size),
484 (uintptr_t)pinfo.__pi_stackaddr, (uintptr_t)pinfo.__pi_stacksize, (uintptr_t)pinfo.__pi_stackend,
485 (uintptr_t)GC_stackbottom
488 /* push the registers too, because they won't be on stack */
489 GC_push_all_eager((ptr_t)&pinfo.__pi_context, (ptr_t)((&pinfo.__pi_context)+1));
490 GC_push_all_eager((ptr_t)regbuf, (ptr_t)®buf[val]);
492 hot = p -> stack_ptr;
495 if (p -> stack_size != 0) {
496 # ifdef STACK_GROWS_UP
499 cold = p -> stack + p -> stack_size;
502 /* The original stack. */
503 cold = GC_stackbottom;
505 # ifdef STACK_GROWS_UP
506 GC_push_all_stack(cold, hot);
508 /* printf("thread 0x%x: hot=0x%08x cold=0x%08x\n", p -> id, hot, cold); */
509 GC_push_all_stack(hot, cold);
516 /* We hold the allocation lock. */
520 struct sigaction act;
522 if (GC_thr_initialized) return;
523 GC_thr_initialized = TRUE;
524 GC_min_stack_sz = HBLKSIZE;
525 GC_page_sz = sysconf(_SC_PAGESIZE);
526 #ifndef GC_AIX_THREADS
527 (void) sigaction(SIG_SUSPEND, 0, &act);
528 if (act.sa_handler != SIG_DFL)
529 ABORT("Previously installed SIG_SUSPEND handler");
530 /* Install handler. */
531 act.sa_handler = GC_suspend_handler;
532 act.sa_flags = SA_RESTART;
533 (void) sigemptyset(&act.sa_mask);
534 if (0 != sigaction(SIG_SUSPEND, &act, 0))
535 ABORT("Failed to install SIG_SUSPEND handler");
537 /* Add the initial thread, so we can stop it. */
538 t = GC_new_thread(pthread_self());
540 t -> stack_ptr = (ptr_t)(&t);
541 t -> flags = DETACHED;
544 int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
548 #ifdef GC_AIX_THREADS
549 return(pthread_sigmask(how, set, oset));
552 if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
554 sigdelset(&fudged_set, SIG_SUSPEND);
557 return(pthread_sigmask(how, set, oset));
561 void *(*start_routine)(void *);
566 pthread_mutex_t registeredlock;
567 pthread_cond_t registered;
568 int volatile registereddone;
571 void GC_thread_exit_proc(void *arg)
576 me = GC_lookup_thread(pthread_self());
577 if (me -> flags & DETACHED) {
578 GC_delete_thread(pthread_self());
580 me -> flags |= FINISHED;
585 int GC_pthread_join(pthread_t thread, void **retval)
588 GC_thread thread_gc_id;
591 thread_gc_id = GC_lookup_thread(thread);
592 /* This is guaranteed to be the intended one, since the thread id */
593 /* cant have been recycled by pthreads. */
595 result = pthread_join(thread, retval);
596 /* Some versions of the Irix pthreads library can erroneously */
597 /* return EINTR when the call succeeds. */
598 if (EINTR == result) result = 0;
600 /* Here the pthread thread id may have been recycled. */
601 GC_delete_gc_thread(thread, thread_gc_id);
606 void * GC_start_routine(void * arg)
608 struct start_info * si = arg;
611 pthread_t my_pthread;
612 void *(*start)(void *);
615 my_pthread = pthread_self();
616 /* If a GC occurs before the thread is registered, that GC will */
617 /* ignore this thread. That's fine, since it will block trying to */
618 /* acquire the allocation lock, and won't yet hold interesting */
621 /* We register the thread here instead of in the parent, so that */
622 /* we don't need to hold the allocation lock during pthread_create. */
623 /* Holding the allocation lock there would make REDIRECT_MALLOC */
624 /* impossible. It probably still doesn't work, but we're a little */
626 /* This unfortunately means that we have to be careful the parent */
627 /* doesn't try to do a pthread_join before we're registered. */
628 me = GC_new_thread(my_pthread);
629 me -> flags = si -> flags;
630 me -> stack = si -> stack;
631 me -> stack_size = si -> stack_size;
632 #ifdef STACK_GROWS_UP
633 me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
635 /* stack_ptr needs to point to the hot part of the stack (or conservatively, past it) */
636 me -> stack_ptr = (ptr_t)si -> stack;
639 start = si -> start_routine;
640 start_arg = si -> arg;
642 pthread_mutex_lock(&(si->registeredlock));
643 si->registereddone = 1;
644 pthread_cond_signal(&(si->registered));
645 pthread_mutex_unlock(&(si->registeredlock));
647 pthread_cleanup_push(GC_thread_exit_proc, 0);
648 result = (*start)(start_arg);
649 me -> status = result;
650 pthread_cleanup_pop(1);
651 /* This involves acquiring the lock, ensuring that we can't exit */
652 /* while a collection that thinks we're alive is trying to stop */
657 # if defined(GC_AIX_THREADS)
658 /* pthread_attr_t is not a structure, thus a simple structure copy */
660 static void copy_attr(pthread_attr_t * pa_ptr,
661 const pthread_attr_t * source) {
665 struct sched_param sp_tmp;
666 #ifndef GC_AIX_THREADS
667 pthread_spu_t ps_tmp;
669 (void) pthread_attr_init(pa_ptr);
670 (void) pthread_attr_getdetachstate(source, &tmp);
671 (void) pthread_attr_setdetachstate(pa_ptr, tmp);
672 (void) pthread_attr_getinheritsched(source, &tmp);
673 (void) pthread_attr_setinheritsched(pa_ptr, tmp);
674 (void) pthread_attr_getschedpolicy(source, &tmp);
675 (void) pthread_attr_setschedpolicy(pa_ptr, tmp);
676 (void) pthread_attr_getstacksize(source, &stmp);
677 (void) pthread_attr_setstacksize(pa_ptr, stmp);
678 (void) pthread_attr_getguardsize(source, &stmp);
679 (void) pthread_attr_setguardsize(pa_ptr, stmp);
680 (void) pthread_attr_getstackaddr(source, &vtmp);
681 (void) pthread_attr_setstackaddr(pa_ptr, vtmp);
682 (void) pthread_attr_getscope(source, &tmp);
683 (void) pthread_attr_setscope(pa_ptr, tmp);
684 (void) pthread_attr_getschedparam(source, &sp_tmp);
685 (void) pthread_attr_setschedparam(pa_ptr, &sp_tmp);
686 #ifndef GC_AIX_THREADS
687 (void) pthread_attr_getprocessor_np(source, &ps_tmp, &tmp);
688 (void) pthread_attr_setprocessor_np(pa_ptr, ps_tmp, tmp);
692 # define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
696 GC_pthread_create(pthread_t *new_thread,
697 const pthread_attr_t *attr,
698 void *(*start_routine)(void *), void *arg)
704 pthread_attr_t new_attr;
707 struct start_info * si = GC_malloc(sizeof(struct start_info));
709 /* This is otherwise saved only in an area mmapped by the thread */
710 /* library, which isn't visible to the collector. */
712 if (0 == si) return(ENOMEM);
713 pthread_mutex_init(&(si->registeredlock), NULL);
714 pthread_cond_init(&(si->registered),NULL);
715 si -> start_routine = start_routine;
718 if (!GC_thr_initialized) GC_thr_init();
722 (void) pthread_attr_init(&new_attr);
724 copy_attr(&new_attr, attr);
725 pthread_attr_getstackaddr(&new_attr, &stack);
727 pthread_attr_getstacksize(&new_attr, &stacksize);
728 pthread_attr_getdetachstate(&new_attr, &detachstate);
729 #ifdef GC_AIX_THREADS
730 GC_min_stack_sz = 5*1048576;
731 if (stacksize < GC_min_stack_sz) {
732 stacksize = GC_min_stack_sz;
734 { int alignment = 16*1024; /* size must be multiple of 16KB greater than 56KB */
735 int minval = 56*1024;
736 if ((stacksize - minval) % alignment != 0) {
737 stacksize = minval + alignment * ((stacksize-minval)/alignment + 1);
742 stack = (void *)GC_stack_alloc(&stacksize);
747 pthread_attr_setstacksize(&new_attr, stacksize);
748 #ifdef GC_AIX_THREADS
749 pthread_attr_setstackaddr(&new_attr, ((char *)stack)+stacksize);
751 pthread_attr_setstackaddr(&new_attr, stack);
754 my_flags |= CLIENT_OWNS_STACK;
757 if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
758 si -> flags = my_flags;
760 si -> stack_size = stacksize;
761 result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
763 if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
764 GC_stack_free(stack, stacksize);
767 /* Wait until child has been added to the thread table. */
768 /* This also ensures that we hold onto si until the child is done */
769 /* with it. Thus it doesn't matter whether it is otherwise */
770 /* visible to the collector. */
772 si->registereddone = 0;
773 pthread_mutex_lock(&(si->registeredlock));
774 while (!si->registereddone)
775 pthread_cond_wait(&(si->registered), &(si->registeredlock));
776 pthread_mutex_unlock(&(si->registeredlock));
778 pthread_cond_destroy(&(si->registered));
779 pthread_mutex_destroy(&(si->registeredlock));
780 pthread_attr_destroy(&new_attr);
785 /* For now we use the pthreads locking primitives on HP/UX */
787 VOLATILE GC_bool GC_collecting = 0; /* A hint that we're in the collector and */
788 /* holding the allocation lock for an */
789 /* extended period. */
791 /* Reasonably fast spin locks. Basically the same implementation */
792 /* as STL alloc.h. */
794 #define SLEEP_THRESHOLD 3
796 volatile unsigned int GC_allocate_lock = 0;
797 #define GC_TRY_LOCK() !GC_test_and_set(&GC_allocate_lock)
798 #define GC_LOCK_TAKEN GC_allocate_lock
802 # define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
803 # define high_spin_max 1000 /* spin cycles for multiprocessor */
804 static unsigned spin_max = low_spin_max;
805 unsigned my_spin_max;
806 static unsigned last_spins = 0;
807 unsigned my_last_spins;
808 volatile unsigned junk;
809 # define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
816 my_spin_max = spin_max;
817 my_last_spins = last_spins;
818 for (i = 0; i < my_spin_max; i++) {
819 if (GC_collecting) goto yield;
820 if (i < my_last_spins/2 || GC_LOCK_TAKEN) {
827 * Spinning worked. Thus we're probably not being scheduled
828 * against the other process with which we were contending.
829 * Thus it makes sense to spin longer the next time.
832 spin_max = high_spin_max;
836 /* We are probably being scheduled against the other process. Sleep. */
837 spin_max = low_spin_max;
843 if (i < SLEEP_THRESHOLD) {
849 /* Don't wait for more than about 60msecs, even */
850 /* under extreme contention. */
858 # else /* !GC_IRIX_THREADS && !GC_AIX_THREADS */
861 int GC_no_Irix_threads;
864 # endif /* IRIX_THREADS */