[BACK]Return to pthread_support.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Annotation of OpenXM_contrib2/asir2000/gc/pthread_support.c, Revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>