OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [boehm-gc/] [pthread_support.c] - Blame information for rev 22

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.