~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to pthread_support.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
3
3
 * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
4
4
 * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
5
 
 * Copyright (c) 2000-2004 by Hewlett-Packard Company.  All rights reserved.
 
5
 * Copyright (c) 2000-2005 by Hewlett-Packard Company.  All rights reserved.
6
6
 *
7
7
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8
8
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
14
14
 * modified is included with the above copyright notice.
15
15
 */
16
16
/*
17
 
 * Support code for LinuxThreads, the clone()-based kernel
 
17
 * Support code originally for LinuxThreads, the clone()-based kernel
18
18
 * thread package for Linux which is included in libc6.
19
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.
 
20
 * This code no doubt makes some assumptions beyond what is
 
21
 * guaranteed by the pthread standard, though it now does
 
22
 * very little of that.  It now also supports NPTL, and many
 
23
 * other Posix thread implementations.  We are trying to merge
 
24
 * all flavors of pthread dupport code into this file.
28
25
 */
29
26
 /* DG/UX ix86 support <takis@xfree86.org> */
30
27
/*
45
42
 */
46
43
 
47
44
/*#define DEBUG_THREADS 1*/
48
 
/*#define GC_ASSERTIONS*/
49
45
 
50
46
# include "private/pthread_support.h"
51
47
 
52
 
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
53
 
     && !defined(GC_WIN32_THREADS)
54
 
 
55
 
# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
56
 
     && !defined(USE_COMPILER_TLS)
57
 
#   ifdef __GNUC__
58
 
#     define USE_PTHREAD_SPECIFIC
59
 
      /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work.     */
60
 
#   else
61
 
#     define USE_COMPILER_TLS
62
 
#   endif
63
 
# endif
64
 
 
65
 
# if defined USE_HPUX_TLS
66
 
    --> Macro replaced by USE_COMPILER_TLS
67
 
# endif
68
 
 
69
 
# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
70
 
      defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) || \
71
 
      defined(GC_NETBSD_THREADS))                              \
72
 
      && !defined(USE_PTHREAD_SPECIFIC)
73
 
#   define USE_PTHREAD_SPECIFIC
74
 
# endif
 
48
# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
75
49
 
76
50
# if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
77
51
#   define _POSIX4A_DRAFT10_SOURCE 1
81
55
#   define _USING_POSIX4A_DRAFT10 1
82
56
# endif
83
57
 
84
 
# ifdef THREAD_LOCAL_ALLOC
85
 
#   if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_COMPILER_TLS)
86
 
#     include "private/specific.h"
87
 
#   endif
88
 
#   if defined(USE_PTHREAD_SPECIFIC)
89
 
#     define GC_getspecific pthread_getspecific
90
 
#     define GC_setspecific pthread_setspecific
91
 
#     define GC_key_create pthread_key_create
92
 
      typedef pthread_key_t GC_key_t;
93
 
#   endif
94
 
#   if defined(USE_COMPILER_TLS)
95
 
#     define GC_getspecific(x) (x)
96
 
#     define GC_setspecific(key, v) ((key) = (v), 0)
97
 
#     define GC_key_create(key, d) 0
98
 
      typedef void * GC_key_t;
99
 
#   endif
100
 
# endif
101
58
# include <stdlib.h>
102
59
# include <pthread.h>
103
60
# include <sched.h>
111
68
# include <fcntl.h>
112
69
# include <signal.h>
113
70
 
 
71
# include "gc_inline.h"
 
72
 
114
73
#if defined(GC_DARWIN_THREADS)
115
74
# include "private/darwin_semaphore.h"
116
75
#else
124
83
#if defined(GC_NETBSD_THREADS)
125
84
# include <sys/param.h>
126
85
# include <sys/sysctl.h>
127
 
#endif  /* GC_NETBSD_THREADS */
 
86
#endif        /* GC_NETBSD_THREADS */
 
87
 
 
88
/* Allocator lock definitions.          */
 
89
#if !defined(USE_SPIN_LOCK)
 
90
  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
 
91
#endif
 
92
unsigned long GC_lock_holder = NO_THREAD;
 
93
                /* Used only for assertions, and to prevent      */
 
94
                /* recursive reentry in the system call wrapper. */
128
95
 
129
96
#if defined(GC_DGUX386_THREADS)
130
97
# include <sys/dg_sys_info.h>
137
104
#   define __inline__
138
105
#endif
139
106
 
 
107
/* Undefine macros used to redirect pthread primitives. */
 
108
# undef pthread_create
 
109
# if !defined(GC_DARWIN_THREADS)
 
110
#   undef pthread_sigmask
 
111
# endif
 
112
# undef pthread_join
 
113
# undef pthread_detach
 
114
# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
 
115
     && !defined(_PTHREAD_USE_PTDNAM_)
 
116
  /* Restore the original mangled names on Tru64 UNIX.  */
 
117
#   define pthread_create __pthread_create
 
118
#   define pthread_join __pthread_join
 
119
#   define pthread_detach __pthread_detach
 
120
# endif
 
121
 
140
122
#ifdef GC_USE_LD_WRAP
141
123
#   define WRAP_FUNC(f) __wrap_##f
142
124
#   define REAL_FUNC(f) __real_##f
143
125
#else
144
 
#   define WRAP_FUNC(f) GC_##f
145
 
#   if !defined(GC_DGUX386_THREADS)
146
 
#     define REAL_FUNC(f) f
147
 
#   else /* GC_DGUX386_THREADS */
148
 
#     define REAL_FUNC(f) __d10_##f
149
 
#   endif /* GC_DGUX386_THREADS */
150
 
#   undef pthread_create
151
 
#   if !defined(GC_DARWIN_THREADS)
152
 
#     undef pthread_sigmask
153
 
#   endif
154
 
#   undef pthread_join
155
 
#   undef pthread_detach
156
 
#   if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
157
 
       && !defined(_PTHREAD_USE_PTDNAM_)
158
 
/* Restore the original mangled names on Tru64 UNIX.  */
159
 
#     define pthread_create __pthread_create
160
 
#     define pthread_join __pthread_join
161
 
#     define pthread_detach __pthread_detach
162
 
#   endif
163
 
#endif
164
 
 
165
 
void GC_thr_init();
 
126
#   ifdef GC_USE_DLOPEN_WRAP
 
127
#     include <dlfcn.h>
 
128
#     define WRAP_FUNC(f) f
 
129
#     define REAL_FUNC(f) GC_real_##f
 
130
      /* We define both GC_f and plain f to be the wrapped function.    */
 
131
      /* In that way plain calls work, as do calls from files that      */
 
132
      /* included gc.h, wich redefined f to GC_f.                       */
 
133
      /* FIXME: Needs work for DARWIN and True64 (OSF1) */
 
134
      typedef int (* GC_pthread_create_t)(pthread_t *, const pthread_attr_t *,
 
135
                                          void * (*)(void *), void *);
 
136
      static GC_pthread_create_t GC_real_pthread_create;
 
137
      typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *, sigset_t *);
 
138
      static GC_pthread_sigmask_t GC_real_pthread_sigmask;
 
139
      typedef int (* GC_pthread_join_t)(pthread_t, void **);
 
140
      static GC_pthread_join_t GC_real_pthread_join;
 
141
      typedef int (* GC_pthread_detach_t)(pthread_t);
 
142
      static GC_pthread_detach_t GC_real_pthread_detach;
 
143
#   else
 
144
#     define WRAP_FUNC(f) GC_##f
 
145
#     if !defined(GC_DGUX386_THREADS)
 
146
#       define REAL_FUNC(f) f
 
147
#     else /* GC_DGUX386_THREADS */
 
148
#       define REAL_FUNC(f) __d10_##f
 
149
#     endif /* GC_DGUX386_THREADS */
 
150
#   endif
 
151
#endif
 
152
 
 
153
#if defined(GC_USE_DL_WRAP) || defined(GC_USE_DLOPEN_WRAP)
 
154
/* Define GC_ functions as aliases for the plain ones, which will       */
 
155
/* be intercepted.  This allows files which include gc.h, and hence     */
 
156
/* generate references to the GC_ symbols, to see the right symbols.    */
 
157
      int GC_pthread_create(pthread_t * t, const pthread_attr_t * a,
 
158
                         void * (* fn)(void *), void * arg) {
 
159
          return pthread_create(t, a, fn, arg);
 
160
      }
 
161
      int GC_pthread_sigmask(int how, const sigset_t *mask, sigset_t *old) {
 
162
          return pthread_sigmask(how, mask, old);
 
163
      }
 
164
      int GC_pthread_join(pthread_t t, void **res) {
 
165
          return pthread_join(t, res);
 
166
      }
 
167
      int GC_pthread_detach(pthread_t t) {
 
168
          return pthread_detach(t);
 
169
      }
 
170
#endif /* Linker-based interception. */
 
171
 
 
172
#ifdef GC_USE_DLOPEN_WRAP
 
173
  static GC_bool GC_syms_initialized = FALSE;
 
174
 
 
175
  void GC_init_real_syms(void)
 
176
  {
 
177
    void *dl_handle;
 
178
#   define LIBPTHREAD_NAME "libpthread.so.0"
 
179
#   define LIBPTHREAD_NAME_LEN 16 /* incl. trailing 0 */
 
180
    size_t len = LIBPTHREAD_NAME_LEN - 1;
 
181
    char namebuf[LIBPTHREAD_NAME_LEN];
 
182
    static char *libpthread_name = LIBPTHREAD_NAME;
 
183
 
 
184
    if (GC_syms_initialized) return;
 
185
#   ifdef RTLD_NEXT
 
186
      dl_handle = RTLD_NEXT;
 
187
#   else
 
188
      dl_handle = dlopen(libpthread_name, RTLD_LAZY);
 
189
      if (NULL == dl_handle) {
 
190
        while (isdigit(libpthread_name[len-1])) --len;
 
191
        if (libpthread_name[len-1] == '.') --len;
 
192
        memcpy(namebuf, libpthread_name, len);
 
193
        namebuf[len] = '\0';
 
194
        dl_handle = dlopen(namebuf, RTLD_LAZY);
 
195
      }
 
196
      if (NULL == dl_handle) ABORT("Couldn't open libpthread\n");
 
197
#   endif
 
198
    GC_real_pthread_create = (GC_pthread_create_t)
 
199
                                dlsym(dl_handle, "pthread_create");
 
200
    GC_real_pthread_sigmask = (GC_pthread_sigmask_t)
 
201
                                dlsym(dl_handle, "pthread_sigmask");
 
202
    GC_real_pthread_join = (GC_pthread_join_t)
 
203
                                dlsym(dl_handle, "pthread_join");
 
204
    GC_real_pthread_detach = (GC_pthread_detach_t)
 
205
                                dlsym(dl_handle, "pthread_detach");
 
206
    GC_syms_initialized = TRUE;
 
207
  }
 
208
 
 
209
# define INIT_REAL_SYMS() if (!GC_syms_initialized) GC_init_real_syms();
 
210
#else
 
211
# define INIT_REAL_SYMS()
 
212
#endif
 
213
 
 
214
void GC_thr_init(void);
166
215
 
167
216
static GC_bool parallel_initialized = FALSE;
168
217
 
169
 
void GC_init_parallel();
170
 
 
171
 
# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
172
 
 
173
 
/* We don't really support thread-local allocation with DBG_HDRS_ALL */
174
 
 
175
 
#ifdef USE_COMPILER_TLS
176
 
  __thread
177
 
#endif
178
 
GC_key_t GC_thread_key;
179
 
 
180
 
static GC_bool keys_initialized;
181
 
 
182
 
/* Recover the contents of the freelist array fl into the global one gfl.*/
183
 
/* Note that the indexing scheme differs, in that gfl has finer size    */
184
 
/* resolution, even if not all entries are used.                        */
185
 
/* We hold the allocator lock.                                          */
186
 
static void return_freelists(ptr_t *fl, ptr_t *gfl)
187
 
{
188
 
    int i;
189
 
    ptr_t q, *qptr;
190
 
    size_t nwords;
191
 
 
192
 
    for (i = 1; i < NFREELISTS; ++i) {
193
 
        nwords = i * (GRANULARITY/sizeof(word));
194
 
        qptr = fl + i;  
195
 
        q = *qptr;
196
 
        if ((word)q >= HBLKSIZE) {
197
 
          if (gfl[nwords] == 0) {
198
 
            gfl[nwords] = q;
199
 
          } else {
200
 
            /* Concatenate: */
201
 
            for (; (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
202
 
            GC_ASSERT(0 == q);
203
 
            *qptr = gfl[nwords];
204
 
            gfl[nwords] = fl[i];
205
 
          }
206
 
        }
207
 
        /* Clear fl[i], since the thread structure may hang around.     */
208
 
        /* Do it in a way that is likely to trap if we access it.       */
209
 
        fl[i] = (ptr_t)HBLKSIZE;
210
 
    }
211
 
}
212
 
 
213
 
/* We statically allocate a single "size 0" object. It is linked to     */
214
 
/* itself, and is thus repeatedly reused for all size 0 allocation      */
215
 
/* requests.  (Size 0 gcj allocation requests are incorrect, and        */
216
 
/* we arrange for those to fault asap.)                                 */
217
 
static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
218
 
 
219
 
/* Each thread structure must be initialized.   */
220
 
/* This call must be made from the new thread.  */
221
 
/* Caller holds allocation lock.                */
222
 
void GC_init_thread_local(GC_thread p)
223
 
{
224
 
    int i;
225
 
 
226
 
    if (!keys_initialized) {
227
 
        if (0 != GC_key_create(&GC_thread_key, 0)) {
228
 
            ABORT("Failed to create key for local allocator");
229
 
        }
230
 
        keys_initialized = TRUE;
231
 
    }
232
 
    if (0 != GC_setspecific(GC_thread_key, p)) {
233
 
        ABORT("Failed to set thread specific allocation pointers");
234
 
    }
235
 
    for (i = 1; i < NFREELISTS; ++i) {
236
 
        p -> ptrfree_freelists[i] = (ptr_t)1;
237
 
        p -> normal_freelists[i] = (ptr_t)1;
238
 
#       ifdef GC_GCJ_SUPPORT
239
 
          p -> gcj_freelists[i] = (ptr_t)1;
240
 
#       endif
241
 
    }   
242
 
    /* Set up the size 0 free lists.    */
243
 
    p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object);
244
 
    p -> normal_freelists[0] = (ptr_t)(&size_zero_object);
245
 
#   ifdef GC_GCJ_SUPPORT
246
 
        p -> gcj_freelists[0] = (ptr_t)(-1);
247
 
#   endif
248
 
}
249
 
 
250
 
#ifdef GC_GCJ_SUPPORT
251
 
  extern ptr_t * GC_gcjobjfreelist;
252
 
#endif
253
 
 
254
 
/* We hold the allocator lock.  */
255
 
void GC_destroy_thread_local(GC_thread p)
256
 
{
257
 
    /* We currently only do this from the thread itself or from */
258
 
    /* the fork handler for a child process.                    */
259
 
#   ifndef HANDLE_FORK
260
 
      GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
261
 
#   endif
262
 
    return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
263
 
    return_freelists(p -> normal_freelists, GC_objfreelist);
264
 
#   ifdef GC_GCJ_SUPPORT
265
 
        return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
266
 
#   endif
267
 
}
268
 
 
269
 
extern GC_PTR GC_generic_malloc_many();
270
 
 
271
 
GC_PTR GC_local_malloc(size_t bytes)
272
 
{
273
 
    if (EXPECT(!SMALL_ENOUGH(bytes),0)) {
274
 
        return(GC_malloc(bytes));
275
 
    } else {
276
 
        int index = INDEX_FROM_BYTES(bytes);
277
 
        ptr_t * my_fl;
278
 
        ptr_t my_entry;
279
 
#       if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
280
 
        GC_key_t k = GC_thread_key;
281
 
#       endif
282
 
        void * tsd;
283
 
 
284
 
#       if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
285
 
            if (EXPECT(0 == k, 0)) {
286
 
                /* This can happen if we get called when the world is   */
287
 
                /* being initialized.  Whether we can actually complete */
288
 
                /* the initialization then is unclear.                  */
289
 
                GC_init_parallel();
290
 
                k = GC_thread_key;
291
 
            }
292
 
#       endif
293
 
        tsd = GC_getspecific(GC_thread_key);
294
 
#       ifdef GC_ASSERTIONS
295
 
          LOCK();
296
 
          GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self()));
297
 
          UNLOCK();
298
 
#       endif
299
 
        my_fl = ((GC_thread)tsd) -> normal_freelists + index;
300
 
        my_entry = *my_fl;
301
 
        if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
302
 
            ptr_t next = obj_link(my_entry);
303
 
            GC_PTR result = (GC_PTR)my_entry;
304
 
            *my_fl = next;
305
 
            obj_link(my_entry) = 0;
306
 
            PREFETCH_FOR_WRITE(next);
307
 
            return result;
308
 
        } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
309
 
            *my_fl = my_entry + index + 1;
310
 
            return GC_malloc(bytes);
311
 
        } else {
312
 
            GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl);
313
 
            if (*my_fl == 0) return GC_oom_fn(bytes);
314
 
            return GC_local_malloc(bytes);
315
 
        }
316
 
    }
317
 
}
318
 
 
319
 
GC_PTR GC_local_malloc_atomic(size_t bytes)
320
 
{
321
 
    if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
322
 
        return(GC_malloc_atomic(bytes));
323
 
    } else {
324
 
        int index = INDEX_FROM_BYTES(bytes);
325
 
        ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
326
 
                        -> ptrfree_freelists + index;
327
 
        ptr_t my_entry = *my_fl;
328
 
    
329
 
        if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
330
 
            GC_PTR result = (GC_PTR)my_entry;
331
 
            *my_fl = obj_link(my_entry);
332
 
            return result;
333
 
        } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
334
 
            *my_fl = my_entry + index + 1;
335
 
        return GC_malloc_atomic(bytes);
336
 
        } else {
337
 
            GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl);
338
 
            /* *my_fl is updated while the collector is excluded;       */
339
 
            /* the free list is always visible to the collector as      */
340
 
            /* such.                                                    */
341
 
            if (*my_fl == 0) return GC_oom_fn(bytes);
342
 
            return GC_local_malloc_atomic(bytes);
343
 
        }
344
 
    }
345
 
}
346
 
 
347
 
#ifdef GC_GCJ_SUPPORT
348
 
 
349
 
#include "include/gc_gcj.h"
350
 
 
351
 
#ifdef GC_ASSERTIONS
352
 
  extern GC_bool GC_gcj_malloc_initialized;
353
 
#endif
354
 
 
355
 
extern int GC_gcj_kind;
356
 
 
357
 
GC_PTR GC_local_gcj_malloc(size_t bytes,
358
 
                           void * ptr_to_struct_containing_descr)
359
 
{
360
 
    GC_ASSERT(GC_gcj_malloc_initialized);
361
 
    if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
362
 
        return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
363
 
    } else {
364
 
        int index = INDEX_FROM_BYTES(bytes);
365
 
        ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
366
 
                        -> gcj_freelists + index;
367
 
        ptr_t my_entry = *my_fl;
368
 
        if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
369
 
            GC_PTR result = (GC_PTR)my_entry;
370
 
            GC_ASSERT(!GC_incremental);
371
 
            /* We assert that any concurrent marker will stop us.       */
372
 
            /* Thus it is impossible for a mark procedure to see the    */
373
 
            /* allocation of the next object, but to see this object    */
374
 
            /* still containing a free list pointer.  Otherwise the     */
375
 
            /* marker might find a random "mark descriptor".            */
376
 
            *(volatile ptr_t *)my_fl = obj_link(my_entry);
377
 
            /* We must update the freelist before we store the pointer. */
378
 
            /* Otherwise a GC at this point would see a corrupted       */
379
 
            /* free list.                                               */
380
 
            /* A memory barrier is probably never needed, since the     */
381
 
            /* action of stopping this thread will cause prior writes   */
382
 
            /* to complete.                                             */
383
 
            GC_ASSERT(((void * volatile *)result)[1] == 0); 
384
 
            *(void * volatile *)result = ptr_to_struct_containing_descr; 
385
 
            return result;
386
 
        } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
387
 
            if (!GC_incremental) *my_fl = my_entry + index + 1;
388
 
                /* In the incremental case, we always have to take this */
389
 
                /* path.  Thus we leave the counter alone.              */
390
 
            return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
391
 
        } else {
392
 
            GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl);
393
 
            if (*my_fl == 0) return GC_oom_fn(bytes);
394
 
            return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr);
395
 
        }
396
 
    }
397
 
}
398
 
 
399
 
#endif /* GC_GCJ_SUPPORT */
400
 
 
401
 
# else  /* !THREAD_LOCAL_ALLOC  && !DBG_HDRS_ALL */
402
 
 
403
 
#   define GC_destroy_thread_local(t)
404
 
 
405
 
# endif /* !THREAD_LOCAL_ALLOC */
406
 
 
407
 
#if 0
408
 
/*
409
 
To make sure that we're using LinuxThreads and not some other thread
410
 
package, we generate a dummy reference to `pthread_kill_other_threads_np'
411
 
(was `__pthread_initial_thread_bos' but that disappeared),
412
 
which is a symbol defined in LinuxThreads, but (hopefully) not in other
413
 
thread packages.
414
 
 
415
 
We no longer do this, since this code is now portable enough that it might
416
 
actually work for something else.
417
 
*/
418
 
void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
419
 
#endif /* 0 */
 
218
GC_bool GC_need_to_lock = FALSE;
 
219
 
 
220
void GC_init_parallel(void);
420
221
 
421
222
long GC_nprocs = 1;     /* Number of processors.  We may not have       */
422
223
                        /* access to all of them, but this is as good   */
423
224
                        /* a guess as any ...                           */
424
225
 
 
226
#ifdef THREAD_LOCAL_ALLOC
 
227
/* We must explicitly mark ptrfree and gcj free lists, since the free   */
 
228
/* list links wouldn't otherwise be found.  We also set them in the     */
 
229
/* normal free lists, since that involves touching less memory than if  */
 
230
/* we scanned them normally.                                            */
 
231
void GC_mark_thread_local_free_lists(void)
 
232
{
 
233
    int i;
 
234
    GC_thread p;
 
235
    
 
236
    for (i = 0; i < THREAD_TABLE_SZ; ++i) {
 
237
      for (p = GC_threads[i]; 0 != p; p = p -> next) {
 
238
        GC_mark_thread_local_fls_for(&(p->tlfs));
 
239
      }
 
240
    }
 
241
}
 
242
 
 
243
#if defined(GC_ASSERTIONS)
 
244
    /* Check that all thread-local free-lists are completely marked.    */
 
245
    /* also check that thread-specific-data structures are marked.      */
 
246
    void GC_check_tls(void) {
 
247
        int i;
 
248
        GC_thread p;
 
249
        
 
250
        for (i = 0; i < THREAD_TABLE_SZ; ++i) {
 
251
          for (p = GC_threads[i]; 0 != p; p = p -> next) {
 
252
            GC_check_tls_for(&(p->tlfs));
 
253
          }
 
254
        }
 
255
#       if defined(USE_CUSTOM_SPECIFIC)
 
256
          if (GC_thread_key != 0)
 
257
            GC_check_tsd_marks(GC_thread_key);
 
258
#       endif 
 
259
    }
 
260
#endif /* GC_ASSERTIONS */
 
261
 
 
262
#endif /* Thread_local_alloc */
 
263
 
425
264
#ifdef PARALLEL_MARK
426
265
 
427
266
# ifndef MAX_MARKERS
429
268
# endif
430
269
 
431
270
static ptr_t marker_sp[MAX_MARKERS] = {0};
 
271
#ifdef IA64
 
272
  static ptr_t marker_bsp[MAX_MARKERS] = {0};
 
273
#endif
432
274
 
433
275
void * GC_mark_thread(void * id)
434
276
{
435
277
  word my_mark_no = 0;
436
278
 
437
279
  marker_sp[(word)id] = GC_approx_sp();
 
280
# ifdef IA64
 
281
    marker_bsp[(word)id] = GC_save_regs_in_stack();
 
282
# endif
438
283
  for (;; ++my_mark_no) {
439
284
    /* GC_mark_no is passed only to allow GC_help_marker to terminate   */
440
285
    /* promptly.  This is important if it were called from the signal   */
448
293
        my_mark_no = GC_mark_no;
449
294
    }
450
295
#   ifdef DEBUG_THREADS
451
 
        GC_printf1("Starting mark helper for mark number %ld\n", my_mark_no);
 
296
        GC_printf("Starting mark helper for mark number %lu\n", my_mark_no);
452
297
#   endif
453
298
    GC_help_marker(my_mark_no);
454
299
  }
462
307
 
463
308
#define PTHREAD_CREATE REAL_FUNC(pthread_create)
464
309
 
465
 
static void start_mark_threads()
 
310
static void start_mark_threads(void)
466
311
{
467
312
    unsigned i;
468
313
    pthread_attr_t attr;
493
338
        }
494
339
      }
495
340
#   endif /* HPUX || GC_DGUX386_THREADS */
496
 
#   ifdef CONDPRINT
497
 
      if (GC_print_stats) {
498
 
        GC_printf1("Starting %ld marker threads\n", GC_markers - 1);
499
 
      }
500
 
#   endif
 
341
    if (GC_print_stats) {
 
342
        GC_log_printf("Starting %ld marker threads\n", GC_markers - 1);
 
343
    }
501
344
    for (i = 0; i < GC_markers - 1; ++i) {
502
345
      if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
503
346
                              GC_mark_thread, (void *)(word)i)) {
506
349
    }
507
350
}
508
351
 
509
 
#else  /* !PARALLEL_MARK */
510
 
 
511
 
static __inline__ void start_mark_threads()
512
 
{
513
 
}
514
 
 
515
 
#endif /* !PARALLEL_MARK */
 
352
#endif /* PARALLEL_MARK */
516
353
 
517
354
GC_bool GC_thr_initialized = FALSE;
518
355
 
519
356
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
520
357
 
521
 
void GC_push_thread_structures GC_PROTO((void))
 
358
void GC_push_thread_structures(void)
522
359
{
 
360
    GC_ASSERT(I_HOLD_LOCK());
523
361
    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
524
 
#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
 
362
#   if defined(THREAD_LOCAL_ALLOC)
525
363
      GC_push_all((ptr_t)(&GC_thread_key),
526
364
          (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
527
365
#   endif
528
366
}
529
367
 
530
 
#ifdef THREAD_LOCAL_ALLOC
531
 
/* We must explicitly mark ptrfree and gcj free lists, since the free   */
532
 
/* list links wouldn't otherwise be found.  We also set them in the     */
533
 
/* normal free lists, since that involves touching less memory than if  */
534
 
/* we scanned them normally.                                            */
535
 
void GC_mark_thread_local_free_lists(void)
536
 
{
537
 
    int i, j;
538
 
    GC_thread p;
539
 
    ptr_t q;
540
 
    
541
 
    for (i = 0; i < THREAD_TABLE_SZ; ++i) {
542
 
      for (p = GC_threads[i]; 0 != p; p = p -> next) {
543
 
        for (j = 1; j < NFREELISTS; ++j) {
544
 
          q = p -> ptrfree_freelists[j];
545
 
          if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
546
 
          q = p -> normal_freelists[j];
547
 
          if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
548
 
#         ifdef GC_GCJ_SUPPORT
549
 
            q = p -> gcj_freelists[j];
550
 
            if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
551
 
#         endif /* GC_GCJ_SUPPORT */
552
 
        }
553
 
      }
554
 
    }
555
 
}
556
 
#endif /* THREAD_LOCAL_ALLOC */
557
 
 
 
368
/* It may not be safe to allocate when we register the first thread.    */
558
369
static struct GC_Thread_Rep first_thread;
559
370
 
560
371
/* Add a thread to GC_threads.  We assume it wasn't already there.      */
561
372
/* Caller holds allocation lock.                                        */
562
373
GC_thread GC_new_thread(pthread_t id)
563
374
{
564
 
    int hv = ((word)id) % THREAD_TABLE_SZ;
 
375
    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
565
376
    GC_thread result;
566
377
    static GC_bool first_thread_used = FALSE;
567
378
    
 
379
    GC_ASSERT(I_HOLD_LOCK());
568
380
    if (!first_thread_used) {
569
381
        result = &first_thread;
570
382
        first_thread_used = TRUE;
571
383
    } else {
572
384
        result = (struct GC_Thread_Rep *)
573
385
                 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
 
386
        GC_ASSERT(result -> flags == 0);
574
387
    }
575
388
    if (result == 0) return(0);
576
389
    result -> id = id;
582
395
 
583
396
/* Delete a thread from GC_threads.  We assume it is there.     */
584
397
/* (The code intentionally traps if it wasn't.)                 */
585
 
/* Caller holds allocation lock.                                */
586
398
void GC_delete_thread(pthread_t id)
587
399
{
588
 
    int hv = ((word)id) % THREAD_TABLE_SZ;
 
400
    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
589
401
    register GC_thread p = GC_threads[hv];
590
402
    register GC_thread prev = 0;
591
403
    
592
 
    while (!pthread_equal(p -> id, id)) {
 
404
    GC_ASSERT(I_HOLD_LOCK());
 
405
    while (!THREAD_EQUAL(p -> id, id)) {
593
406
        prev = p;
594
407
        p = p -> next;
595
408
    }
598
411
    } else {
599
412
        prev -> next = p -> next;
600
413
    }
601
 
        
602
 
#ifdef GC_DARWIN_THREADS
 
414
#   ifdef GC_DARWIN_THREADS
603
415
        mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
604
 
#endif
605
 
        
 
416
#   endif
606
417
    GC_INTERNAL_FREE(p);
607
418
}
608
419
 
610
421
/* been notified, then there may be more than one thread        */
611
422
/* in the table with the same pthread id.                       */
612
423
/* This is OK, but we need a way to delete a specific one.      */
613
 
void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
 
424
void GC_delete_gc_thread(GC_thread gc_id)
614
425
{
615
 
    int hv = ((word)id) % THREAD_TABLE_SZ;
 
426
    pthread_t id = gc_id -> id;
 
427
    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
616
428
    register GC_thread p = GC_threads[hv];
617
429
    register GC_thread prev = 0;
618
430
 
 
431
    GC_ASSERT(I_HOLD_LOCK());
619
432
    while (p != gc_id) {
620
433
        prev = p;
621
434
        p = p -> next;
625
438
    } else {
626
439
        prev -> next = p -> next;
627
440
    }
628
 
        
629
 
#ifdef GC_DARWIN_THREADS
 
441
#   ifdef GC_DARWIN_THREADS
630
442
        mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
631
 
#endif
632
 
        
 
443
#   endif
633
444
    GC_INTERNAL_FREE(p);
634
445
}
635
446
 
641
452
/* return the most recent one.                                  */
642
453
GC_thread GC_lookup_thread(pthread_t id)
643
454
{
644
 
    int hv = ((word)id) % THREAD_TABLE_SZ;
 
455
    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
645
456
    register GC_thread p = GC_threads[hv];
646
457
    
647
 
    while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
 
458
    while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;
648
459
    return(p);
649
460
}
650
461
 
663
474
      me = 0;
664
475
      for (p = GC_threads[hv]; 0 != p; p = next) {
665
476
        next = p -> next;
666
 
        if (p -> id == self) {
 
477
        if (THREAD_EQUAL(p -> id, self)) {
667
478
          me = p;
668
479
          p -> next = 0;
669
480
        } else {
670
481
#         ifdef THREAD_LOCAL_ALLOC
671
482
            if (!(p -> flags & FINISHED)) {
672
 
              GC_destroy_thread_local(p);
 
483
              GC_destroy_thread_local(&(p->tlfs));
673
484
            }
674
485
#         endif /* THREAD_LOCAL_ALLOC */
675
486
          if (p != &first_thread) GC_INTERNAL_FREE(p);
681
492
#endif /* HANDLE_FORK */
682
493
 
683
494
#ifdef USE_PROC_FOR_LIBRARIES
684
 
int GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
 
495
GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
685
496
{
686
497
    int i;
687
498
    GC_thread p;
688
499
    
 
500
    GC_ASSERT(I_HOLD_LOCK());
689
501
#   ifdef PARALLEL_MARK
690
502
      for (i = 0; i < GC_markers; ++i) {
691
 
        if (marker_sp[i] > lo & marker_sp[i] < hi) return 1;
 
503
        if (marker_sp[i] > lo & marker_sp[i] < hi) return TRUE;
 
504
#       ifdef IA64
 
505
          if (marker_bsp[i] > lo & marker_bsp[i] < hi) return TRUE;
 
506
#       endif
692
507
      }
693
508
#   endif
694
509
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
695
510
      for (p = GC_threads[i]; p != 0; p = p -> next) {
696
511
        if (0 != p -> stack_end) {
697
512
#         ifdef STACK_GROWS_UP
698
 
            if (p -> stack_end >= lo && p -> stack_end < hi) return 1;
 
513
            if (p -> stack_end >= lo && p -> stack_end < hi) return TRUE;
699
514
#         else /* STACK_GROWS_DOWN */
700
 
            if (p -> stack_end > lo && p -> stack_end <= hi) return 1;
 
515
            if (p -> stack_end > lo && p -> stack_end <= hi) return TRUE;
701
516
#         endif
702
517
        }
703
518
      }
704
519
    }
705
 
    return 0;
 
520
    return FALSE;
706
521
}
707
522
#endif /* USE_PROC_FOR_LIBRARIES */
708
523
 
 
524
#ifdef IA64
 
525
/* Find the largest stack_base smaller than bound.  May be used */
 
526
/* to find the boundary between a register stack and adjacent   */
 
527
/* immediately preceding memory stack.                          */
 
528
ptr_t GC_greatest_stack_base_below(ptr_t bound)
 
529
{
 
530
    int i;
 
531
    GC_thread p;
 
532
    ptr_t result = 0;
 
533
    
 
534
    GC_ASSERT(I_HOLD_LOCK());
 
535
#   ifdef PARALLEL_MARK
 
536
      for (i = 0; i < GC_markers; ++i) {
 
537
        if (marker_sp[i] > result && marker_sp[i] < bound)
 
538
          result = marker_sp[i];
 
539
      }
 
540
#   endif
 
541
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
 
542
      for (p = GC_threads[i]; p != 0; p = p -> next) {
 
543
        if (p -> stack_end > result && p -> stack_end < bound) {
 
544
          result = p -> stack_end;
 
545
        }
 
546
      }
 
547
    }
 
548
    return result;
 
549
}
 
550
#endif /* IA64 */
 
551
 
709
552
#ifdef GC_LINUX_THREADS
710
553
/* Return the number of processors, or i<= 0 if it can't be determined. */
711
 
int GC_get_nprocs()
 
554
int GC_get_nprocs(void)
712
555
{
713
556
    /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that       */
714
557
    /* appears to be buggy in many cases.                               */
747
590
/* If wait_for_all is true, then we exit with the GC lock held and no   */
748
591
/* collection in progress; otherwise we just wait for the current GC    */
749
592
/* to finish.                                                           */
750
 
extern GC_bool GC_collection_in_progress();
 
593
extern GC_bool GC_collection_in_progress(void);
751
594
void GC_wait_for_gc_completion(GC_bool wait_for_all)
752
595
{
 
596
    GC_ASSERT(I_HOLD_LOCK());
753
597
    if (GC_incremental && GC_collection_in_progress()) {
754
598
        int old_gc_no = GC_gc_no;
755
599
 
827
671
 
828
672
#if defined(GC_DGUX386_THREADS)
829
673
/* Return the number of processors, or i<= 0 if it can't be determined. */
830
 
int GC_get_nprocs()
 
674
int GC_get_nprocs(void)
831
675
{
832
676
    /* <takis@XFree86.Org> */
833
677
    int numCpus;
844
688
      numCpus = pm_sysinfo.idle_vp_count;
845
689
 
846
690
#  ifdef DEBUG_THREADS
847
 
    GC_printf1("Number of active CPUs in this system: %d\n", numCpus);
 
691
    GC_printf("Number of active CPUs in this system: %d\n", numCpus);
848
692
#  endif
849
693
    return(numCpus);
850
694
}
862
706
}
863
707
#endif  /* GC_NETBSD_THREADS */
864
708
 
 
709
# if defined(GC_LINUX_THREADS) && defined(INCLUDE_LINUX_THREAD_DESCR)
 
710
__thread int dummy_thread_local;
 
711
# endif
 
712
 
865
713
/* We hold the allocation lock. */
866
 
void GC_thr_init()
 
714
void GC_thr_init(void)
867
715
{
868
716
#   ifndef GC_DARWIN_THREADS
869
 
      int dummy;
 
717
        int dummy;
870
718
#   endif
871
719
    GC_thread t;
872
720
 
878
726
        pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
879
727
                       GC_fork_child_proc);
880
728
#   endif /* HANDLE_FORK */
 
729
#   if defined(INCLUDE_LINUX_THREAD_DESCR)
 
730
      /* Explicitly register the region including the address           */
 
731
      /* of a thread local variable.  This should include thread        */
 
732
      /* locals for the main thread, except for those allocated         */
 
733
      /* in response to dlopen calls.                                   */  
 
734
        {
 
735
          ptr_t thread_local_addr = (ptr_t)(&dummy_thread_local);
 
736
          ptr_t main_thread_start, main_thread_end;
 
737
          if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
 
738
                                    &main_thread_end)) {
 
739
            ABORT("Failed to find mapping for main thread thread locals");
 
740
          }
 
741
          GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
 
742
        }
 
743
#   endif
881
744
    /* Add the initial thread, so we can stop it.       */
882
745
      t = GC_new_thread(pthread_self());
883
746
#     ifdef GC_DARWIN_THREADS
899
762
#       if defined(GC_HPUX_THREADS)
900
763
          GC_nprocs = pthread_num_processors_np();
901
764
#       endif
902
 
#       if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS)
 
765
#       if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
 
766
           || defined(GC_SOLARIS_THREADS) || defined(GC_GNU_THREADS)
903
767
          GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
904
768
          if (GC_nprocs <= 0) GC_nprocs = 1;
905
769
#       endif
939
803
#       endif
940
804
      }
941
805
#   ifdef PARALLEL_MARK
942
 
#     ifdef CONDPRINT
943
 
        if (GC_print_stats) {
944
 
          GC_printf2("Number of processors = %ld, "
 
806
      if (GC_print_stats) {
 
807
          GC_log_printf("Number of processors = %ld, "
945
808
                 "number of marker threads = %ld\n", GC_nprocs, GC_markers);
946
 
        }
947
 
#     endif
 
809
      }
948
810
      if (GC_markers == 1) {
949
811
        GC_parallel = FALSE;
950
 
#       ifdef CONDPRINT
951
 
          if (GC_print_stats) {
952
 
            GC_printf0("Single marker thread, turning off parallel marking\n");
953
 
          }
954
 
#       endif
 
812
        if (GC_print_stats) {
 
813
            GC_log_printf(
 
814
                "Single marker thread, turning off parallel marking\n");
 
815
        }
955
816
      } else {
956
817
        GC_parallel = TRUE;
957
818
        /* Disable true incremental collection, but generational is OK. */
967
828
/* may require allocation.                              */
968
829
/* Called without allocation lock.                      */
969
830
/* Must be called before a second thread is created.    */
970
 
/* Called without allocation lock.                      */
971
 
void GC_init_parallel()
 
831
/* Did we say it's called without the allocation lock?  */
 
832
void GC_init_parallel(void)
972
833
{
973
834
    if (parallel_initialized) return;
974
835
    parallel_initialized = TRUE;
976
837
    /* GC_init() calls us back, so set flag first.      */
977
838
    if (!GC_is_initialized) GC_init();
978
839
    /* Initialize thread local free lists if used.      */
979
 
#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
 
840
#   if defined(THREAD_LOCAL_ALLOC)
980
841
      LOCK();
981
 
      GC_init_thread_local(GC_lookup_thread(pthread_self()));
 
842
      GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
982
843
      UNLOCK();
983
844
#   endif
984
845
}
989
850
{
990
851
    sigset_t fudged_set;
991
852
    
 
853
    INIT_REAL_SYMS();
992
854
    if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
993
855
        fudged_set = *set;
994
856
        sigdelset(&fudged_set, SIG_SUSPEND);
998
860
}
999
861
#endif /* !GC_DARWIN_THREADS */
1000
862
 
1001
 
/* Wrappers for functions that are likely to block for an appreciable   */
1002
 
/* length of time.  Must be called in pairs, if at all.                 */
1003
 
/* Nothing much beyond the system call itself should be executed        */
1004
 
/* between these.                                                       */
1005
 
 
1006
 
void GC_start_blocking(void) {
1007
 
#   define SP_SLOP 128
 
863
/* Wrapper for functions that are likely to block for an appreciable    */
 
864
/* length of time.                                                      */
 
865
 
 
866
struct blocking_data {
 
867
    void (*fn)(void *);
 
868
    void *arg;
 
869
};
 
870
 
 
871
static void GC_do_blocking_inner(ptr_t data, void * context) {
 
872
    struct blocking_data * d = (struct blocking_data *) data;
1008
873
    GC_thread me;
1009
874
    LOCK();
1010
875
    me = GC_lookup_thread(pthread_self());
1011
876
    GC_ASSERT(!(me -> thread_blocked));
1012
877
#   ifdef SPARC
1013
 
        me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
1014
 
#   else
1015
 
#   ifndef GC_DARWIN_THREADS
1016
 
        me -> stop_info.stack_ptr = (ptr_t)GC_approx_sp();
1017
 
#   endif
 
878
        me -> stop_info.stack_ptr = GC_save_regs_in_stack();
 
879
#   elif !defined(GC_DARWIN_THREADS)
 
880
        me -> stop_info.stack_ptr = GC_approx_sp();
1018
881
#   endif
1019
882
#   ifdef IA64
1020
 
        me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;
1021
 
#   endif
1022
 
    /* Add some slop to the stack pointer, since the wrapped call may   */
1023
 
    /* end up pushing more callee-save registers.                       */
1024
 
#   ifndef GC_DARWIN_THREADS
1025
 
#   ifdef STACK_GROWS_UP
1026
 
        me -> stop_info.stack_ptr += SP_SLOP;
1027
 
#   else
1028
 
        me -> stop_info.stack_ptr -= SP_SLOP;
1029
 
#   endif
 
883
        me -> backing_store_ptr = GC_save_regs_in_stack();
1030
884
#   endif
1031
885
    me -> thread_blocked = TRUE;
 
886
    /* Save context here if we want to support precise stack marking */
1032
887
    UNLOCK();
1033
 
}
1034
 
 
1035
 
void GC_end_blocking(void) {
1036
 
    GC_thread me;
 
888
    (d -> fn)(d -> arg);
1037
889
    LOCK();   /* This will block if the world is stopped.       */
1038
 
    me = GC_lookup_thread(pthread_self());
1039
 
    GC_ASSERT(me -> thread_blocked);
1040
890
    me -> thread_blocked = FALSE;
1041
891
    UNLOCK();
1042
892
}
 
893
 
 
894
void GC_do_blocking(void (*fn)(void *), void *arg) {
 
895
    struct blocking_data my_data;
 
896
 
 
897
    my_data.fn = fn;
 
898
    my_data.arg = arg;
 
899
    GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
 
900
}
1043
901
    
1044
 
#if defined(GC_DGUX386_THREADS)
1045
 
#define __d10_sleep sleep
1046
 
#endif /* GC_DGUX386_THREADS */
1047
 
 
1048
 
/* A wrapper for the standard C sleep function  */
1049
 
int WRAP_FUNC(sleep) (unsigned int seconds)
1050
 
{
1051
 
    int result;
1052
 
 
1053
 
    GC_start_blocking();
1054
 
    result = REAL_FUNC(sleep)(seconds);
1055
 
    GC_end_blocking();
1056
 
    return result;
1057
 
}
1058
 
 
1059
902
struct start_info {
1060
903
    void *(*start_routine)(void *);
1061
904
    void *arg;
1064
907
                                /* parent hasn't yet noticed.           */
1065
908
};
1066
909
 
 
910
int GC_unregister_my_thread(void)
 
911
{
 
912
    GC_thread me;
 
913
 
 
914
    LOCK();
 
915
    /* Wait for any GC that may be marking from our stack to    */
 
916
    /* complete before we remove this thread.                   */
 
917
    GC_wait_for_gc_completion(FALSE);
 
918
    me = GC_lookup_thread(pthread_self());
 
919
#   if defined(THREAD_LOCAL_ALLOC)
 
920
      GC_destroy_thread_local(&(me->tlfs));
 
921
#   endif
 
922
    if (me -> flags & DETACHED) {
 
923
        GC_delete_thread(pthread_self());
 
924
    } else {
 
925
        me -> flags |= FINISHED;
 
926
    }
 
927
#   if defined(THREAD_LOCAL_ALLOC)
 
928
      GC_remove_specific(GC_thread_key);
 
929
#   endif
 
930
    UNLOCK();
 
931
    return GC_SUCCESS;
 
932
}
 
933
 
1067
934
/* Called at thread exit.                               */
1068
935
/* Never called for main thread.  That's OK, since it   */
1069
936
/* results in at most a tiny one-time leak.  And        */
1071
938
/* resources or id anyway.                              */
1072
939
void GC_thread_exit_proc(void *arg)
1073
940
{
1074
 
    GC_thread me;
1075
 
 
1076
 
    LOCK();
1077
 
    me = GC_lookup_thread(pthread_self());
1078
 
    GC_destroy_thread_local(me);
1079
 
    if (me -> flags & DETACHED) {
1080
 
        GC_delete_thread(pthread_self());
1081
 
    } else {
1082
 
        me -> flags |= FINISHED;
1083
 
    }
1084
 
#   if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
1085
 
       && !defined(USE_COMPILER_TLS) && !defined(DBG_HDRS_ALL)
1086
 
      GC_remove_specific(GC_thread_key);
1087
 
#   endif
1088
 
    /* The following may run the GC from "nonexistent" thread.  */
1089
 
    GC_wait_for_gc_completion(FALSE);
1090
 
    UNLOCK();
 
941
    GC_unregister_my_thread();
1091
942
}
1092
943
 
1093
944
int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
1095
946
    int result;
1096
947
    GC_thread thread_gc_id;
1097
948
    
 
949
    INIT_REAL_SYMS();
1098
950
    LOCK();
1099
951
    thread_gc_id = GC_lookup_thread(thread);
1100
952
    /* This is guaranteed to be the intended one, since the thread id   */
1115
967
    if (result == 0) {
1116
968
        LOCK();
1117
969
        /* Here the pthread thread id may have been recycled. */
1118
 
        GC_delete_gc_thread(thread, thread_gc_id);
 
970
        GC_delete_gc_thread(thread_gc_id);
1119
971
        UNLOCK();
1120
972
    }
1121
973
    return result;
1127
979
    int result;
1128
980
    GC_thread thread_gc_id;
1129
981
    
 
982
    INIT_REAL_SYMS();
1130
983
    LOCK();
1131
984
    thread_gc_id = GC_lookup_thread(thread);
1132
985
    UNLOCK();
1136
989
      thread_gc_id -> flags |= DETACHED;
1137
990
      /* Here the pthread thread id may have been recycled. */
1138
991
      if (thread_gc_id -> flags & FINISHED) {
1139
 
        GC_delete_gc_thread(thread, thread_gc_id);
 
992
        GC_delete_gc_thread(thread_gc_id);
1140
993
      }
1141
994
      UNLOCK();
1142
995
    }
1143
996
    return result;
1144
997
}
1145
998
 
1146
 
GC_bool GC_in_thread_creation = FALSE;
1147
 
 
1148
 
void * GC_start_routine(void * arg)
1149
 
{
1150
 
    int dummy;
 
999
GC_bool GC_in_thread_creation = FALSE;  /* Protected by allocation lock. */
 
1000
 
 
1001
GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
 
1002
                                      pthread_t my_pthread)
 
1003
{
 
1004
    GC_thread me;
 
1005
 
 
1006
    GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
 
1007
    me = GC_new_thread(my_pthread);
 
1008
    GC_in_thread_creation = FALSE;
 
1009
#   ifdef GC_DARWIN_THREADS
 
1010
      me -> stop_info.mach_thread = mach_thread_self();
 
1011
#   else
 
1012
      me -> stop_info.stack_ptr = sb -> mem_base;
 
1013
#   endif
 
1014
    me -> stack_end = sb -> mem_base;
 
1015
#   ifdef IA64
 
1016
      me -> backing_store_end = sb -> reg_base;
 
1017
#   endif /* IA64 */
 
1018
    return me;
 
1019
}
 
1020
 
 
1021
int GC_register_my_thread(struct GC_stack_base *sb)
 
1022
{
 
1023
    pthread_t my_pthread = pthread_self();
 
1024
    GC_thread me;
 
1025
 
 
1026
    LOCK();
 
1027
    me = GC_lookup_thread(my_pthread);
 
1028
    if (0 == me) {
 
1029
        me = GC_register_my_thread_inner(sb, my_pthread);
 
1030
        me -> flags |= DETACHED;
 
1031
          /* Treat as detached, since we do not need to worry about     */
 
1032
          /* pointer results.                                           */
 
1033
        UNLOCK();
 
1034
        return GC_SUCCESS;
 
1035
    } else {
 
1036
        UNLOCK();
 
1037
        return GC_DUPLICATE;
 
1038
    }
 
1039
}
 
1040
 
 
1041
void * GC_inner_start_routine(struct GC_stack_base *sb, void * arg)
 
1042
{
1151
1043
    struct start_info * si = arg;
1152
1044
    void * result;
1153
1045
    GC_thread me;
1157
1049
 
1158
1050
    my_pthread = pthread_self();
1159
1051
#   ifdef DEBUG_THREADS
1160
 
        GC_printf1("Starting thread 0x%lx\n", my_pthread);
1161
 
        GC_printf1("pid = %ld\n", (long) getpid());
1162
 
        GC_printf1("sp = 0x%lx\n", (long) &arg);
 
1052
        GC_printf("Starting thread 0x%x\n", (unsigned)my_pthread);
 
1053
        GC_printf("pid = %ld\n", (long) getpid());
 
1054
        GC_printf("sp = 0x%lx\n", (long) &arg);
1163
1055
#   endif
1164
1056
    LOCK();
1165
 
    GC_in_thread_creation = TRUE;
1166
 
    me = GC_new_thread(my_pthread);
1167
 
    GC_in_thread_creation = FALSE;
1168
 
#ifdef GC_DARWIN_THREADS
1169
 
    me -> stop_info.mach_thread = mach_thread_self();
1170
 
#else
1171
 
    me -> stop_info.stack_ptr = 0;
1172
 
#endif
 
1057
    me = GC_register_my_thread_inner(sb, my_pthread);
1173
1058
    me -> flags = si -> flags;
1174
 
    /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99)    */
1175
 
    /* doesn't work because the stack base in /proc/self/stat is the    */
1176
 
    /* one for the main thread.  There is a strong argument that that's */
1177
 
    /* a kernel bug, but a pervasive one.                               */
1178
 
#   ifdef STACK_GROWS_DOWN
1179
 
      me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
1180
 
                                & ~(GC_page_size - 1));
1181
 
#         ifndef GC_DARWIN_THREADS
1182
 
        me -> stop_info.stack_ptr = me -> stack_end - 0x10;
1183
 
#         endif
1184
 
        /* Needs to be plausible, since an asynchronous stack mark      */
1185
 
        /* should not crash.                                            */
1186
 
#   else
1187
 
      me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1));
1188
 
      me -> stop_info.stack_ptr = me -> stack_end + 0x10;
1189
 
#   endif
1190
 
    /* This is dubious, since we may be more than a page into the stack, */
1191
 
    /* and hence skip some of it, though it's not clear that matters.    */
1192
 
#   ifdef IA64
1193
 
      me -> backing_store_end = (ptr_t)
1194
 
                        (GC_save_regs_in_stack() & ~(GC_page_size - 1));
1195
 
      /* This is also < 100% convincing.  We should also read this      */
1196
 
      /* from /proc, but the hook to do so isn't there yet.             */
1197
 
#   endif /* IA64 */
1198
1059
    UNLOCK();
1199
1060
    start = si -> start_routine;
1200
1061
#   ifdef DEBUG_THREADS
1201
 
        GC_printf1("start_routine = 0x%lx\n", start);
 
1062
        GC_printf("start_routine = %p\n", (void *)start);
1202
1063
#   endif
1203
1064
    start_arg = si -> arg;
1204
1065
    sem_post(&(si -> registered));      /* Last action on si.   */
1205
1066
                                        /* OK to deallocate.    */
1206
1067
    pthread_cleanup_push(GC_thread_exit_proc, 0);
1207
 
#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
 
1068
#   if defined(THREAD_LOCAL_ALLOC)
1208
1069
        LOCK();
1209
 
        GC_init_thread_local(me);
 
1070
        GC_init_thread_local(&(me->tlfs));
1210
1071
        UNLOCK();
1211
1072
#   endif
1212
1073
    result = (*start)(start_arg);
1213
 
#if DEBUG_THREADS
1214
 
        GC_printf1("Finishing thread 0x%x\n", pthread_self());
1215
 
#endif
 
1074
#   if DEBUG_THREADS
 
1075
        GC_printf("Finishing thread 0x%x\n", (unsigned)pthread_self());
 
1076
#   endif
1216
1077
    me -> status = result;
1217
1078
    pthread_cleanup_pop(1);
1218
1079
    /* Cleanup acquires lock, ensuring that we can't exit               */
1221
1082
    return(result);
1222
1083
}
1223
1084
 
 
1085
void * GC_start_routine(void * arg)
 
1086
{
 
1087
#   ifdef INCLUDE_LINUX_THREAD_DESCR
 
1088
      struct GC_stack_base sb;
 
1089
 
 
1090
#     ifdef REDIRECT_MALLOC
 
1091
        /* GC_get_stack_base may call pthread_getattr_np, which can     */
 
1092
        /* unfortunately call realloc, which may allocate from an       */
 
1093
        /* unregistered thread.  This is unpleasant, since it might     */ 
 
1094
        /* force heap growth.                                           */
 
1095
        GC_disable();
 
1096
#     endif
 
1097
      if (GC_get_stack_base(&sb) != GC_SUCCESS)
 
1098
        ABORT("Failed to get thread stack base.");
 
1099
#     ifdef REDIRECT_MALLOC
 
1100
        GC_enable();
 
1101
#     endif
 
1102
      return GC_inner_start_routine(&sb, arg);
 
1103
#   else
 
1104
      return GC_call_with_stack_base(GC_inner_start_routine, arg);
 
1105
#   endif
 
1106
}
 
1107
 
1224
1108
int
1225
1109
WRAP_FUNC(pthread_create)(pthread_t *new_thread,
1226
1110
                  const pthread_attr_t *attr,
1237
1121
    /* even if the default is unreasonably small.  That's the client's  */
1238
1122
    /* responsibility.                                                  */
1239
1123
 
 
1124
    INIT_REAL_SYMS();
1240
1125
    LOCK();
1241
1126
    si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
1242
1127
                                                 NORMAL);
1250
1135
    if (!GC_thr_initialized) GC_thr_init();
1251
1136
#   ifdef GC_ASSERTIONS
1252
1137
      {
1253
 
        size_t stack_size;
1254
 
        if (NULL == attr) {
 
1138
        size_t stack_size = 0;
 
1139
        if (NULL != attr) {
 
1140
           pthread_attr_getstacksize(attr, &stack_size);
 
1141
        }
 
1142
        if (0 == stack_size) {
1255
1143
           pthread_attr_t my_attr;
1256
1144
           pthread_attr_init(&my_attr);
1257
1145
           pthread_attr_getstacksize(&my_attr, &stack_size);
1258
 
        } else {
1259
 
           pthread_attr_getstacksize(attr, &stack_size);
 
1146
        }
 
1147
        /* On Solaris 10, with default attr initialization,     */
 
1148
        /* stack_size remains 0.  Fudge it.                     */
 
1149
        if (0 == stack_size) {
 
1150
#           ifndef SOLARIS
 
1151
              WARN("Failed to get stack size for assertion checking\n", 0);
 
1152
#           endif
 
1153
            stack_size = 1000000;
1260
1154
        }
1261
1155
#       ifdef PARALLEL_MARK
1262
1156
          GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
1279
1173
    si -> flags = my_flags;
1280
1174
    UNLOCK();
1281
1175
#   ifdef DEBUG_THREADS
1282
 
        GC_printf1("About to start new thread from thread 0x%X\n",
1283
 
                   pthread_self());
 
1176
        GC_printf("About to start new thread from thread 0x%x\n",
 
1177
                  (unsigned)pthread_self());
1284
1178
#   endif
 
1179
    GC_need_to_lock = TRUE;
1285
1180
 
1286
1181
    result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
1287
1182
 
1288
1183
#   ifdef DEBUG_THREADS
1289
 
        GC_printf1("Started thread 0x%X\n", *new_thread);
 
1184
        GC_printf("Started thread 0x%x\n", (unsigned)(*new_thread));
1290
1185
#   endif
1291
1186
    /* Wait until child has been added to the thread table.             */
1292
1187
    /* This also ensures that we hold onto si until the child is done   */
1305
1200
    return(result);
1306
1201
}
1307
1202
 
1308
 
#ifdef GENERIC_COMPARE_AND_SWAP
1309
 
  pthread_mutex_t GC_compare_and_swap_lock = PTHREAD_MUTEX_INITIALIZER;
1310
 
 
1311
 
  GC_bool GC_compare_and_exchange(volatile GC_word *addr,
1312
 
                                  GC_word old, GC_word new_val)
1313
 
  {
1314
 
    GC_bool result;
1315
 
    pthread_mutex_lock(&GC_compare_and_swap_lock);
1316
 
    if (*addr == old) {
1317
 
      *addr = new_val;
1318
 
      result = TRUE;
1319
 
    } else {
1320
 
      result = FALSE;
1321
 
    }
1322
 
    pthread_mutex_unlock(&GC_compare_and_swap_lock);
1323
 
    return result;
1324
 
  }
1325
 
  
1326
 
  GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much)
1327
 
  {
1328
 
    GC_word old;
1329
 
    pthread_mutex_lock(&GC_compare_and_swap_lock);
1330
 
    old = *addr;
1331
 
    *addr = old + how_much;
1332
 
    pthread_mutex_unlock(&GC_compare_and_swap_lock);
1333
 
    return old;
1334
 
  }
1335
 
 
1336
 
#endif /* GENERIC_COMPARE_AND_SWAP */
1337
1203
/* Spend a few cycles in a way that can't introduce contention with     */
1338
1204
/* othre threads.                                                       */
1339
 
void GC_pause()
 
1205
void GC_pause(void)
1340
1206
{
1341
1207
    int i;
1342
1208
#   if !defined(__GNUC__) || defined(__INTEL_COMPILER)
1356
1222
#define SPIN_MAX 128    /* Maximum number of calls to GC_pause before   */
1357
1223
                        /* give up.                                     */
1358
1224
 
1359
 
VOLATILE GC_bool GC_collecting = 0;
 
1225
volatile GC_bool GC_collecting = 0;
1360
1226
                        /* A hint that we're in the collector and       */
1361
1227
                        /* holding the allocation lock for an           */
1362
1228
                        /* extended period.                             */
1428
1294
/* as STL alloc.h.  This isn't really the right way to do this.   */
1429
1295
/* but until the POSIX scheduling mess gets straightened out ...  */
1430
1296
 
1431
 
volatile unsigned int GC_allocate_lock = 0;
1432
 
 
1433
 
 
1434
 
void GC_lock()
 
1297
volatile AO_TS_t GC_allocate_lock = 0;
 
1298
 
 
1299
 
 
1300
void GC_lock(void)
1435
1301
{
1436
1302
#   define low_spin_max 30  /* spin cycles if we suspect uniprocessor */
1437
1303
#   define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
1441
1307
    unsigned my_last_spins;
1442
1308
    int i;
1443
1309
 
1444
 
    if (!GC_test_and_set(&GC_allocate_lock)) {
 
1310
    if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
1445
1311
        return;
1446
1312
    }
1447
1313
    my_spin_max = spin_max;
1448
1314
    my_last_spins = last_spins;
1449
1315
    for (i = 0; i < my_spin_max; i++) {
1450
1316
        if (GC_collecting || GC_nprocs == 1) goto yield;
1451
 
        if (i < my_last_spins/2 || GC_allocate_lock) {
 
1317
        if (i < my_last_spins/2) {
1452
1318
            GC_pause();
1453
1319
            continue;
1454
1320
        }
1455
 
        if (!GC_test_and_set(&GC_allocate_lock)) {
 
1321
        if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
1456
1322
            /*
1457
1323
             * got it!
1458
1324
             * Spinning worked.  Thus we're probably not being scheduled
1468
1334
    spin_max = low_spin_max;
1469
1335
yield:
1470
1336
    for (i = 0;; ++i) {
1471
 
        if (!GC_test_and_set(&GC_allocate_lock)) {
 
1337
        if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
1472
1338
            return;
1473
1339
        }
1474
1340
#       define SLEEP_THRESHOLD 12
1494
1360
}
1495
1361
 
1496
1362
#else  /* !USE_SPINLOCK */
1497
 
void GC_lock()
 
1363
void GC_lock(void)
1498
1364
{
1499
1365
#ifndef NO_PTHREAD_TRYLOCK
1500
1366
    if (1 == GC_nprocs || GC_collecting) {
1512
1378
#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
1513
1379
 
1514
1380
#ifdef GC_ASSERTIONS
1515
 
  pthread_t GC_mark_lock_holder = NO_THREAD;
 
1381
  unsigned long GC_mark_lock_holder = NO_THREAD;
1516
1382
#endif
1517
1383
 
1518
1384
#if 0
1531
1397
 
1532
1398
static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
1533
1399
 
1534
 
void GC_acquire_mark_lock()
 
1400
void GC_acquire_mark_lock(void)
1535
1401
{
1536
1402
/*
1537
1403
    if (pthread_mutex_lock(&mark_mutex) != 0) {
1540
1406
*/
1541
1407
    GC_generic_lock(&mark_mutex);
1542
1408
#   ifdef GC_ASSERTIONS
1543
 
        GC_mark_lock_holder = pthread_self();
 
1409
        GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
1544
1410
#   endif
1545
1411
}
1546
1412
 
1547
 
void GC_release_mark_lock()
 
1413
void GC_release_mark_lock(void)
1548
1414
{
1549
 
    GC_ASSERT(GC_mark_lock_holder == pthread_self());
 
1415
    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1550
1416
#   ifdef GC_ASSERTIONS
1551
1417
        GC_mark_lock_holder = NO_THREAD;
1552
1418
#   endif
1560
1426
/* 2) Partial free lists referenced only by locals may not be scanned   */
1561
1427
/*    correctly, e.g. if they contain "pointer-free" objects, since the */
1562
1428
/*    free-list link may be ignored.                                    */
1563
 
void GC_wait_builder()
 
1429
void GC_wait_builder(void)
1564
1430
{
1565
 
    GC_ASSERT(GC_mark_lock_holder == pthread_self());
 
1431
    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1566
1432
#   ifdef GC_ASSERTIONS
1567
1433
        GC_mark_lock_holder = NO_THREAD;
1568
1434
#   endif
1571
1437
    }
1572
1438
    GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
1573
1439
#   ifdef GC_ASSERTIONS
1574
 
        GC_mark_lock_holder = pthread_self();
 
1440
        GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
1575
1441
#   endif
1576
1442
}
1577
1443
 
1578
 
void GC_wait_for_reclaim()
 
1444
void GC_wait_for_reclaim(void)
1579
1445
{
1580
1446
    GC_acquire_mark_lock();
1581
1447
    while (GC_fl_builder_count > 0) {
1584
1450
    GC_release_mark_lock();
1585
1451
}
1586
1452
 
1587
 
void GC_notify_all_builder()
 
1453
void GC_notify_all_builder(void)
1588
1454
{
1589
 
    GC_ASSERT(GC_mark_lock_holder == pthread_self());
 
1455
    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1590
1456
    if (pthread_cond_broadcast(&builder_cv) != 0) {
1591
1457
        ABORT("pthread_cond_broadcast failed");
1592
1458
    }
1598
1464
 
1599
1465
static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
1600
1466
 
1601
 
void GC_wait_marker()
 
1467
void GC_wait_marker(void)
1602
1468
{
1603
 
    GC_ASSERT(GC_mark_lock_holder == pthread_self());
 
1469
    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
1604
1470
#   ifdef GC_ASSERTIONS
1605
1471
        GC_mark_lock_holder = NO_THREAD;
1606
1472
#   endif
1609
1475
    }
1610
1476
    GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
1611
1477
#   ifdef GC_ASSERTIONS
1612
 
        GC_mark_lock_holder = pthread_self();
 
1478
        GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
1613
1479
#   endif
1614
1480
}
1615
1481
 
1616
 
void GC_notify_all_marker()
 
1482
void GC_notify_all_marker(void)
1617
1483
{
1618
1484
    if (pthread_cond_broadcast(&mark_cv) != 0) {
1619
1485
        ABORT("pthread_cond_broadcast failed");