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

Annotation of OpenXM_contrib2/asir2000/gc/linux_threads.c, Revision 1.6

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

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