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

« back to all changes in this revision

Viewing changes to win32_threads.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:
1
1
#include "private/gc_priv.h"
2
2
 
3
 
#if defined(GC_WIN32_THREADS) 
 
3
#if defined(GC_WIN32_THREADS)
4
4
 
5
5
#include <windows.h>
6
6
 
7
 
#ifdef CYGWIN32
 
7
#ifdef THREAD_LOCAL_ALLOC
 
8
# include "private/thread_local_alloc.h"
 
9
#endif /* THREAD_LOCAL_ALLOC */
 
10
 
 
11
/* Allocation lock declarations.        */
 
12
#if !defined(USE_PTHREAD_LOCKS)
 
13
# if defined(GC_DLL)
 
14
    __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
 
15
# else
 
16
    CRITICAL_SECTION GC_allocate_ml;
 
17
# endif
 
18
  DWORD GC_lock_holder = NO_THREAD;
 
19
        /* Thread id for current holder of allocation lock */
 
20
#else
 
21
  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
 
22
  unsigned long GC_lock_holder = NO_THREAD;
 
23
#endif
 
24
 
 
25
#ifdef GC_PTHREADS
8
26
# include <errno.h>
9
27
 
 
28
/* GC_DLL should not normally be defined, especially since we often do turn */
 
29
/* on THREAD_LOCAL_ALLOC, which is currently incompatible.                  */
 
30
/* It might be possible to get GC_DLL and DllMain-based thread registration */
 
31
/* to work with Cygwin, but if you try you are on your own.                 */
 
32
#ifdef GC_DLL
 
33
# error GC_DLL untested with Cygwin
 
34
#endif
 
35
 
10
36
 /* Cygwin-specific forward decls */
11
37
# undef pthread_create 
12
38
# undef pthread_sigmask 
14
40
# undef pthread_detach
15
41
# undef dlopen 
16
42
 
17
 
# define DEBUG_CYGWIN_THREADS 0
 
43
# ifdef DEBUG_THREADS
 
44
#   ifdef CYGWIN32
 
45
#     define DEBUG_CYGWIN_THREADS 1
 
46
#     define DEBUG_WIN32_PTHREADS 0
 
47
#   else
 
48
#     define DEBUG_WIN32_PTHREADS 1
 
49
#     define DEBUG_CYGWIN_THREADS 0
 
50
#   endif
 
51
# else
 
52
#   define DEBUG_CYGWIN_THREADS 0
 
53
#   define DEBUG_WIN32_PTHREADS 0
 
54
# endif
18
55
 
19
 
  void * GC_start_routine(void * arg);
 
56
  void * GC_pthread_start(void * arg);
20
57
  void GC_thread_exit_proc(void *arg);
21
58
 
22
 
#endif
 
59
# include <pthread.h>
 
60
 
 
61
#else
 
62
 
 
63
# ifdef DEBUG_THREADS
 
64
#   define DEBUG_WIN32_THREADS 1
 
65
# else
 
66
#   define DEBUG_WIN32_THREADS 0
 
67
# endif
 
68
 
 
69
# undef CreateThread
 
70
# undef ExitThread
 
71
# undef _beginthreadex
 
72
# undef _endthreadex
 
73
# undef _beginthread
 
74
# ifdef DEBUG_THREADS
 
75
#   define DEBUG_WIN32_THREADS 1
 
76
# else
 
77
#   define DEBUG_WIN32_THREADS 0
 
78
# endif
 
79
 
 
80
# include <process.h>  /* For _beginthreadex, _endthreadex */
 
81
 
 
82
#endif
 
83
 
 
84
#if defined(GC_DLL) && !defined(MSWINCE)
 
85
  static GC_bool GC_win32_dll_threads = FALSE;
 
86
  /* This code operates in two distinct modes, depending on     */
 
87
  /* the setting of GC_win32_dll_threads.  If                   */
 
88
  /* GC_win32_dll_threads is set, all threads in the process    */
 
89
  /* are implicitly registered with the GC by DllMain.          */
 
90
  /* No explicit registration is required, and attempts at      */
 
91
  /* explicit registration are ignored.  This mode is           */
 
92
  /* very different from the Posix operation of the collector.  */
 
93
  /* In this mode access to the thread table is lock-free.      */
 
94
  /* Hence there is a static limit on the number of threads.    */
 
95
  
 
96
  /* If GC_win32_dll_threads is FALSE, or the collector is      */
 
97
  /* built without GC_DLL defined, things operate in a way      */
 
98
  /* that is very similar to Posix platforms, and new threads   */
 
99
  /* must be registered with the collector, e.g. by using       */
 
100
  /* preprocessor-based interception of the thread primitives.  */
 
101
  /* In this case, we use a real data structure for the thread  */
 
102
  /* table.  Note that there is no equivalent of linker-based   */
 
103
  /* call interception, since we don't have ELF-like            */
 
104
  /* facilities.  The Windows analog appears to be "API         */
 
105
  /* hooking", which really seems to be a standard way to       */
 
106
  /* do minor binary rewriting (?).  I'd prefer not to have     */
 
107
  /* the basic collector rely on such facilities, but an        */
 
108
  /* optional package that intercepts thread calls this way     */
 
109
  /* would probably be nice.                                    */
 
110
 
 
111
  /* GC_win32_dll_threads must be set at initialization time,   */
 
112
  /* i.e. before any collector or thread calls.  We make it a   */
 
113
  /* "dynamic" option only to avoid multiple library versions.  */
 
114
#else
 
115
# define GC_win32_dll_threads FALSE
 
116
#endif
 
117
 
 
118
/* We have two versions of the thread table.  Which one */
 
119
/* we us depends on whether or not GC_win32_dll_threads */
 
120
/* is set.  Note that before initialization, we don't   */
 
121
/* add any entries to either table, even if DllMain is  */
 
122
/* called.  The main thread will be added on            */
 
123
/* initialization.                                      */
23
124
 
24
125
/* The type of the first argument to InterlockedExchange.       */
25
126
/* Documented to be LONG volatile *, but at least gcc likes     */
26
127
/* this better.                                                 */
27
128
typedef LONG * IE_t;
28
129
 
29
 
#ifndef MAX_THREADS
30
 
# define MAX_THREADS 256
31
 
    /* FIXME:                                                   */
32
 
    /* Things may get quite slow for large numbers of threads,  */
33
 
    /* since we look them up with sequential search.            */
34
 
#endif
35
 
 
36
130
GC_bool GC_thr_initialized = FALSE;
37
131
 
 
132
GC_bool GC_need_to_lock = FALSE;
 
133
 
 
134
static GC_bool parallel_initialized = FALSE;
 
135
 
 
136
void GC_init_parallel(void);
 
137
 
 
138
#ifdef GC_DLL
 
139
  /* Turn on GC_win32_dll_threads       */
 
140
  GC_API void GC_use_DllMain(void)
 
141
  {
 
142
#     ifdef THREAD_LOCAL_ALLOC
 
143
          ABORT("Cannot use thread local allocation with DllMain-based "
 
144
                "thread registration.");
 
145
          /* Thread-local allocation really wants to lock at thread     */
 
146
          /* entry and exit.                                            */
 
147
#     endif
 
148
      GC_ASSERT(!parallel_initialized);
 
149
      GC_win32_dll_threads = TRUE;
 
150
      GC_init_parallel();
 
151
  }
 
152
#else
 
153
  GC_API void GC_use_DllMain(void)
 
154
  {
 
155
      ABORT("GC not configured as DLL");
 
156
  }
 
157
#endif
 
158
 
38
159
DWORD GC_main_thread = 0;
39
160
 
40
 
struct GC_thread_Rep {
41
 
  LONG in_use; /* Updated without lock. */
42
 
                        /* We assert that unused        */
43
 
                        /* entries have invalid ids of  */
44
 
                        /* zero and zero stack fields.  */
 
161
struct GC_Thread_Rep {
 
162
  union {
 
163
    AO_t tm_in_use;     /* Updated without lock.                */
 
164
                        /* We assert that unused                */
 
165
                        /* entries have invalid ids of          */
 
166
                        /* zero and zero stack fields.          */
 
167
                        /* Used only with GC_win32_dll_threads. */
 
168
    struct GC_Thread_Rep * tm_next;
 
169
                        /* Hash table link without              */
 
170
                        /* GC_win32_dll_threads.                */
 
171
                        /* More recently allocated threads      */
 
172
                        /* with a given pthread id come         */
 
173
                        /* first.  (All but the first are       */
 
174
                        /* guaranteed to be dead, but we may    */
 
175
                        /* not yet have registered the join.)   */
 
176
  } table_management;
 
177
# define in_use table_management.tm_in_use
 
178
# define next table_management.tm_next
45
179
  DWORD id;
46
180
  HANDLE handle;
47
181
  ptr_t stack_base;     /* The cold end of the stack.   */
49
183
                        /* !in_use ==> stack_base == 0  */
50
184
  GC_bool suspended;
51
185
 
52
 
# ifdef CYGWIN32
 
186
# ifdef GC_PTHREADS
53
187
    void *status; /* hold exit value until join in case it's a pointer */
54
188
    pthread_t pthread_id;
55
189
    short flags;                /* Protected by GC lock.        */
56
190
#       define FINISHED 1       /* Thread has exited.   */
57
191
#       define DETACHED 2       /* Thread is intended to be detached.   */
 
192
#   define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
 
193
# else
 
194
#   define KNOWN_FINISHED(t) 0
 
195
# endif
 
196
# ifdef THREAD_LOCAL_ALLOC
 
197
    struct thread_local_freelists tlfs;
58
198
# endif
59
199
};
60
200
 
61
 
typedef volatile struct GC_thread_Rep * GC_thread;
 
201
typedef struct GC_Thread_Rep * GC_thread;
 
202
typedef volatile struct GC_Thread_Rep * GC_vthread;
62
203
 
63
204
/*
64
 
 * We generally assume that volatile ==> memory ordering, at least among
65
 
 * volatiles.
 
205
 * We assumed that volatile ==> memory ordering, at least among
 
206
 * volatiles.  This code should consistently use atomic_ops.
66
207
 */
67
208
 
68
209
volatile GC_bool GC_please_stop = FALSE;
69
210
 
70
 
volatile struct GC_thread_Rep thread_table[MAX_THREADS];
71
 
 
72
 
volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table */
73
 
                                       /* that was ever used.           */
 
211
/*
 
212
 * We track thread attachments while the world is supposed to be stopped.
 
213
 * Unfortunately, we can't stop them from starting, since blocking in
 
214
 * DllMain seems to cause the world to deadlock.  Thus we have to recover
 
215
 * If we notice this in the middle of marking.
 
216
 */
 
217
 
 
218
AO_t GC_attached_thread = FALSE;
 
219
/* Return TRUE if an thread was attached since we last asked or */
 
220
/* since GC_attached_thread was explicitly reset.               */
 
221
GC_bool GC_started_thread_while_stopped(void)
 
222
{
 
223
  AO_t result;
 
224
 
 
225
  if (GC_win32_dll_threads) {
 
226
    AO_nop_full();      /* Prior heap reads need to complete earlier. */
 
227
    result = AO_load(&GC_attached_thread);
 
228
    if (result) {
 
229
      AO_store(&GC_attached_thread, FALSE);
 
230
    }
 
231
    return ((GC_bool)result);
 
232
  } else {
 
233
    return FALSE;
 
234
  }
 
235
}
 
236
 
 
237
/* Thread table used if GC_win32_dll_threads is set.    */
 
238
/* This is a fixed size array.                          */
 
239
/* Since we use runtime conditionals, both versions     */
 
240
/* are always defined.                                  */
 
241
# ifndef MAX_THREADS
 
242
#   define MAX_THREADS 512
 
243
#  endif
 
244
  /* Things may get quite slow for large numbers of threads,    */
 
245
  /* since we look them up with sequential search.              */
 
246
 
 
247
  volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
 
248
 
 
249
  volatile LONG GC_max_thread_index = 0;
 
250
                        /* Largest index in dll_thread_table    */
 
251
                        /* that was ever used.                  */
 
252
 
 
253
/* And now the version used if GC_win32_dll_threads is not set. */
 
254
/* This is a chained hash table, with much of the code borrowed */
 
255
/* From the Posix implementation.                               */
 
256
# define THREAD_TABLE_SZ 256    /* Must be power of 2   */
 
257
  GC_thread GC_threads[THREAD_TABLE_SZ];
 
258
  
 
259
 
 
260
/* Add a thread to GC_threads.  We assume it wasn't already there.      */
 
261
/* Caller holds allocation lock.                                        */
 
262
/* Unlike the pthreads version, the id field is set by the caller.      */
 
263
GC_thread GC_new_thread(DWORD id)
 
264
{
 
265
    word hv = ((word)id) % THREAD_TABLE_SZ;
 
266
    GC_thread result;
 
267
    /* It may not be safe to allocate when we register the first thread. */
 
268
    static struct GC_Thread_Rep first_thread;
 
269
    static GC_bool first_thread_used = FALSE;
 
270
    
 
271
    GC_ASSERT(I_HOLD_LOCK());
 
272
    if (!first_thread_used) {
 
273
        result = &first_thread;
 
274
        first_thread_used = TRUE;
 
275
    } else {
 
276
        GC_ASSERT(!GC_win32_dll_threads);
 
277
        result = (struct GC_Thread_Rep *)
 
278
                 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
 
279
#       ifdef GC_PTHREADS
 
280
          /* result can be NULL -> segfault */
 
281
          GC_ASSERT(result -> flags == 0);
 
282
#       endif
 
283
    }
 
284
    if (result == 0) return(0);
 
285
    /* result -> id = id; Done by caller.       */
 
286
    result -> next = GC_threads[hv];
 
287
    GC_threads[hv] = result;
 
288
#   ifdef GC_PTHREADS
 
289
      GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);
 
290
#   endif
 
291
    return(result);
 
292
}
74
293
 
75
294
extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
76
295
 
 
296
#if defined(GWW_VDB) && defined(MPROTECT_VDB)
 
297
  extern GC_bool GC_gww_dirty_init(void);
 
298
  /* Defined in os_dep.c.  Returns TRUE if GetWriteWatch is available.  */
 
299
  /* may be called repeatedly.                                          */
 
300
#endif
 
301
 
 
302
GC_bool GC_in_thread_creation = FALSE;  /* Protected by allocation lock. */
 
303
 
77
304
/*
78
305
 * This may be called from DllMain, and hence operates under unusual
79
 
 * constraints.
 
306
 * constraints.  In particular, it must be lock-free if GC_win32_dll_threads
 
307
 * is set.  Always called from the thread being added.
 
308
 * If GC_win32_dll_threads is not set, we already hold the allocation lock,
 
309
 * except possibly during single-threaded start-up code.
80
310
 */
81
 
static GC_thread GC_new_thread(void) {
82
 
  int i;
83
 
  /* It appears to be unsafe to acquire a lock here, since this */
84
 
  /* code is apparently not preeemptible on some systems.       */
85
 
  /* (This is based on complaints, not on Microsoft's official  */
86
 
  /* documentation, which says this should perform "only simple */
87
 
  /* initialization tasks".)                                    */
88
 
  /* Hence we make do with nonblocking synchronization.         */
 
311
static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
 
312
                                             DWORD thread_id)
 
313
{
 
314
  GC_vthread me;
89
315
 
90
316
  /* The following should be a noop according to the win32      */
91
317
  /* documentation.  There is empirical evidence that it        */
92
318
  /* isn't.             - HB                                    */
93
319
# if defined(MPROTECT_VDB)
94
 
   if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
 
320
#   if defined(GWW_VDB)
 
321
      if (GC_incremental && !GC_gww_dirty_init())
 
322
        SetUnhandledExceptionFilter(GC_write_fault_handler);
 
323
#   else
 
324
      if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
 
325
#   endif
95
326
# endif
 
327
 
 
328
  if (GC_win32_dll_threads) {
 
329
    int i;
 
330
    /* It appears to be unsafe to acquire a lock here, since this       */
 
331
    /* code is apparently not preeemptible on some systems.             */
 
332
    /* (This is based on complaints, not on Microsoft's official        */
 
333
    /* documentation, which says this should perform "only simple       */
 
334
    /* initialization tasks".)                                          */
 
335
    /* Hence we make do with nonblocking synchronization.               */
 
336
    /* It has been claimed that DllMain is really only executed with    */
 
337
    /* a particular system lock held, and thus careful use of locking   */
 
338
    /* around code that doesn't call back into the system libraries     */
 
339
    /* might be OK.  But this hasn't been tested across all win32       */
 
340
    /* variants.                                                        */
96
341
                /* cast away volatile qualifier */
97
 
  for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) {
98
 
    /* Compare-and-swap would make this cleaner, but that's not         */
99
 
    /* supported before Windows 98 and NT 4.0.  In Windows 2000,        */
100
 
    /* InterlockedExchange is supposed to be replaced by                */
101
 
    /* InterlockedExchangePointer, but that's not really what I         */
102
 
    /* want here.                                                       */
103
 
    if (i == MAX_THREADS - 1)
104
 
      ABORT("too many threads");
105
 
  }
106
 
  /* Update GC_max_thread_index if necessary.  The following is safe,   */
107
 
  /* and unlike CompareExchange-based solutions seems to work on all    */
108
 
  /* Windows95 and later platforms.                                     */
109
 
  /* Unfortunately, GC_max_thread_index may be temporarily out of       */
110
 
  /* bounds, so readers have to compensate.                             */
111
 
  while (i > GC_max_thread_index) {
112
 
    InterlockedIncrement((IE_t)&GC_max_thread_index);
113
 
  }
114
 
  if (GC_max_thread_index >= MAX_THREADS) {
115
 
    /* We overshot due to simultaneous increments.      */
116
 
    /* Setting it to MAX_THREADS-1 is always safe.      */
117
 
    GC_max_thread_index = MAX_THREADS - 1;
118
 
  }
119
 
  
120
 
# ifdef CYGWIN32
121
 
    thread_table[i].pthread_id = pthread_self();
 
342
    for (i = 0; InterlockedExchange((IE_t)&dll_thread_table[i].in_use,1) != 0;
 
343
         i++) {
 
344
      /* Compare-and-swap would make this cleaner, but that's not       */
 
345
      /* supported before Windows 98 and NT 4.0.  In Windows 2000,      */
 
346
      /* InterlockedExchange is supposed to be replaced by              */
 
347
      /* InterlockedExchangePointer, but that's not really what I       */
 
348
      /* want here.                                                     */
 
349
      /* FIXME: We should eventually declare Win95 dead and use AO_     */
 
350
      /* primitives here.                                               */
 
351
      if (i == MAX_THREADS - 1)
 
352
        ABORT("too many threads");
 
353
    }
 
354
    /* Update GC_max_thread_index if necessary.  The following is safe, */
 
355
    /* and unlike CompareExchange-based solutions seems to work on all  */
 
356
    /* Windows95 and later platforms.                                   */
 
357
    /* Unfortunately, GC_max_thread_index may be temporarily out of     */
 
358
    /* bounds, so readers have to compensate.                           */
 
359
    while (i > GC_max_thread_index) {
 
360
      InterlockedIncrement((IE_t)&GC_max_thread_index);
 
361
    }
 
362
    if (GC_max_thread_index >= MAX_THREADS) {
 
363
      /* We overshot due to simultaneous increments.    */
 
364
      /* Setting it to MAX_THREADS-1 is always safe.    */
 
365
      GC_max_thread_index = MAX_THREADS - 1;
 
366
    }
 
367
    me = dll_thread_table + i;
 
368
  } else /* Not using DllMain */ {
 
369
    GC_ASSERT(I_HOLD_LOCK());
 
370
    GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
 
371
    me = GC_new_thread(thread_id);
 
372
    GC_in_thread_creation = FALSE;
 
373
  }
 
374
# ifdef GC_PTHREADS
 
375
    /* me can be NULL -> segfault */
 
376
    me -> pthread_id = pthread_self();
122
377
# endif
 
378
 
123
379
  if (!DuplicateHandle(GetCurrentProcess(),
124
 
                       GetCurrentThread(),
125
 
                       GetCurrentProcess(),
126
 
                       (HANDLE*)&thread_table[i].handle,
127
 
                       0,
128
 
                       0,
129
 
                       DUPLICATE_SAME_ACCESS)) {
 
380
                        GetCurrentThread(),
 
381
                        GetCurrentProcess(),
 
382
                        (HANDLE*)&(me -> handle),
 
383
                        0,
 
384
                        0,
 
385
                        DUPLICATE_SAME_ACCESS)) {
130
386
        DWORD last_error = GetLastError();
131
 
        GC_printf1("Last error code: %lx\n", last_error);
 
387
        GC_err_printf("Last error code: %d\n", last_error);
132
388
        ABORT("DuplicateHandle failed");
133
389
  }
134
 
  thread_table[i].stack_base = GC_get_stack_base();
 
390
  me -> stack_base = sb -> mem_base;
135
391
  /* Up until this point, GC_push_all_stacks considers this thread      */
136
392
  /* invalid.                                                           */
137
 
  if (thread_table[i].stack_base == NULL) 
138
 
    ABORT("Failed to find stack base in GC_new_thread");
139
393
  /* Up until this point, this entry is viewed as reserved but invalid  */
140
394
  /* by GC_delete_thread.                                               */
141
 
  thread_table[i].id = GetCurrentThreadId();
142
 
  /* If this thread is being created while we are trying to stop        */
143
 
  /* the world, wait here.  Hopefully this can't happen on any  */
144
 
  /* systems that don't allow us to block here.                 */
145
 
  while (GC_please_stop) Sleep(20);
146
 
  return thread_table + i;
 
395
  me -> id = thread_id;
 
396
# if defined(THREAD_LOCAL_ALLOC)
 
397
      GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
 
398
# endif
 
399
  if (me -> stack_base == NULL) 
 
400
      ABORT("Bad stack base in GC_register_my_thread_inner");
 
401
  if (GC_win32_dll_threads) {
 
402
    if (GC_please_stop) {
 
403
      AO_store(&GC_attached_thread, TRUE);
 
404
      AO_nop_full();  // Later updates must become visible after this.
 
405
    }
 
406
    /* We'd like to wait here, but can't, since waiting in DllMain      */
 
407
    /* provokes deadlocks.                                              */
 
408
    /* Thus we force marking to be restarted instead.                   */
 
409
  } else {
 
410
    GC_ASSERT(!GC_please_stop);
 
411
        /* Otherwise both we and the thread stopping code would be      */
 
412
        /* holding the allocation lock.                                 */
 
413
  }
 
414
  return (GC_thread)(me);
147
415
}
148
416
 
149
417
/*
161
429
  return my_max;
162
430
}
163
431
 
164
 
/* This is intended to be lock-free, though that                        */
165
 
/* assumes that the CloseHandle becomes visible before the              */
166
 
/* in_use assignment.                                                   */
167
 
static void GC_delete_gc_thread(GC_thread thr)
168
 
{
169
 
    CloseHandle(thr->handle);
170
 
      /* cast away volatile qualifier */
171
 
    thr->stack_base = 0;
172
 
    thr->id = 0;
 
432
/* Return the GC_thread corresponding to a thread id.  May be called    */
 
433
/* without a lock, but should be called in contexts in which the        */
 
434
/* requested thread cannot be asynchronously deleted, e.g. from the     */
 
435
/* thread itself.                                                       */
 
436
/* This version assumes that either GC_win32_dll_threads is set, or     */
 
437
/* we hold the allocator lock.                                          */
 
438
/* Also used (for assertion checking only) from thread_local_alloc.c.   */
 
439
GC_thread GC_lookup_thread_inner(DWORD thread_id) {
 
440
  if (GC_win32_dll_threads) {
 
441
    int i;
 
442
    LONG my_max = GC_get_max_thread_index();
 
443
    for (i = 0;
 
444
       i <= my_max &&
 
445
       (!AO_load_acquire(&(dll_thread_table[i].in_use))
 
446
        || dll_thread_table[i].id != thread_id);
 
447
       /* Must still be in_use, since nobody else can store our thread_id. */
 
448
       i++) {}
 
449
    if (i > my_max) {
 
450
      return 0;
 
451
    } else {
 
452
      return (GC_thread)(dll_thread_table + i);
 
453
    }
 
454
  } else {
 
455
    word hv = ((word)thread_id) % THREAD_TABLE_SZ;
 
456
    register GC_thread p = GC_threads[hv];
 
457
    
 
458
    GC_ASSERT(I_HOLD_LOCK());
 
459
    while (p != 0 && p -> id != thread_id) p = p -> next;
 
460
    return(p);
 
461
  }
 
462
}
 
463
 
 
464
/* A version of the above that acquires the lock if necessary.  Note    */
 
465
/* that the identically named function for pthreads is different, and   */
 
466
/* just assumes we hold the lock.                                       */
 
467
/* Also used (for assertion checking only) from thread_local_alloc.c.   */
 
468
static GC_thread GC_lookup_thread(DWORD thread_id)
 
469
{
 
470
  if (GC_win32_dll_threads) {
 
471
    return GC_lookup_thread_inner(thread_id);
 
472
  } else {
 
473
    GC_thread result;
 
474
    LOCK();
 
475
    result = GC_lookup_thread_inner(thread_id);
 
476
    UNLOCK();
 
477
    return result;
 
478
  }
 
479
}
 
480
 
 
481
/* If a thread has been joined, but we have not yet             */
 
482
/* been notified, then there may be more than one thread        */
 
483
/* in the table with the same win32 id.                         */
 
484
/* This is OK, but we need a way to delete a specific one.      */
 
485
/* Assumes we hold the allocation lock unless                   */
 
486
/* GC_win32_dll_threads is set.                                 */
 
487
/* If GC_win32_dll_threads is set it should be called from the  */
 
488
/* thread being deleted.                                        */
 
489
void GC_delete_gc_thread(GC_vthread gc_id)
 
490
{
 
491
  CloseHandle(gc_id->handle);
 
492
  if (GC_win32_dll_threads) {
 
493
    /* This is intended to be lock-free.                                */
 
494
    /* It is either called synchronously from the thread being deleted, */
 
495
    /* or by the joining thread.                                        */
 
496
    /* In this branch asynchronosu changes to *gc_id are possible.      */
 
497
    gc_id -> stack_base = 0;
 
498
    gc_id -> id = 0;
173
499
#   ifdef CYGWIN32
174
 
      thr->pthread_id = 0;
 
500
      gc_id -> pthread_id = 0;
175
501
#   endif /* CYGWIN32 */
176
 
    thr->in_use = FALSE;
177
 
}
178
 
 
179
 
static void GC_delete_thread(DWORD thread_id) {
180
 
  int i;
181
 
  LONG my_max = GC_get_max_thread_index();
182
 
 
183
 
  for (i = 0;
184
 
       i <= my_max &&
185
 
       (!thread_table[i].in_use || thread_table[i].id != thread_id);
186
 
       /* Must still be in_use, since nobody else can store our thread_id. */
187
 
       i++) {}
188
 
  if (i > my_max) {
189
 
    WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id);
190
 
  } else {
191
 
    GC_delete_gc_thread(thread_table+i);
192
 
  }
193
 
}
194
 
 
195
 
 
196
 
#ifdef CYGWIN32
 
502
#   ifdef GC_WIN32_PTHREADS
 
503
      gc_id -> pthread_id.p = NULL;
 
504
#   endif /* GC_WIN32_PTHREADS */
 
505
    AO_store_release(&(gc_id->in_use), FALSE);
 
506
  } else {
 
507
    /* Cast away volatile qualifier, since we have lock. */
 
508
    GC_thread gc_nvid = (GC_thread)gc_id;
 
509
    DWORD id = gc_nvid -> id;
 
510
    word hv = ((word)id) % THREAD_TABLE_SZ;
 
511
    register GC_thread p = GC_threads[hv];
 
512
    register GC_thread prev = 0;
 
513
 
 
514
    GC_ASSERT(I_HOLD_LOCK());
 
515
    while (p != gc_nvid) {
 
516
        prev = p;
 
517
        p = p -> next;
 
518
    }
 
519
    if (prev == 0) {
 
520
        GC_threads[hv] = p -> next;
 
521
    } else {
 
522
        prev -> next = p -> next;
 
523
    }
 
524
    GC_INTERNAL_FREE(p);
 
525
  }
 
526
}
 
527
 
 
528
/* Delete a thread from GC_threads.  We assume it is there.     */
 
529
/* (The code intentionally traps if it wasn't.)                 */
 
530
/* Assumes we hold the allocation lock unless                   */
 
531
/* GC_win32_dll_threads is set.                                 */
 
532
/* If GC_win32_dll_threads is set it should be called from the  */
 
533
/* thread being deleted.                                        */
 
534
void GC_delete_thread(DWORD id)
 
535
{
 
536
  if (GC_win32_dll_threads) {
 
537
    GC_thread t = GC_lookup_thread_inner(id);
 
538
 
 
539
    if (0 == t) {
 
540
      WARN("Removing nonexistent thread %ld\n", (GC_word)id);
 
541
    } else {
 
542
      GC_delete_gc_thread(t);
 
543
    }
 
544
  } else {
 
545
    word hv = ((word)id) % THREAD_TABLE_SZ;
 
546
    register GC_thread p = GC_threads[hv];
 
547
    register GC_thread prev = 0;
 
548
    
 
549
    GC_ASSERT(I_HOLD_LOCK());
 
550
    while (p -> id != id) {
 
551
        prev = p;
 
552
        p = p -> next;
 
553
    }
 
554
    CloseHandle(p->handle);
 
555
    if (prev == 0) {
 
556
        GC_threads[hv] = p -> next;
 
557
    } else {
 
558
        prev -> next = p -> next;
 
559
    }
 
560
    GC_INTERNAL_FREE(p);
 
561
  }
 
562
}
 
563
 
 
564
GC_API int GC_register_my_thread(struct GC_stack_base *sb) {
 
565
  DWORD t = GetCurrentThreadId();
 
566
 
 
567
  if (0 == GC_lookup_thread(t)) {
 
568
    /* We lock here, since we want to wait for an ongoing GC.   */
 
569
    LOCK();
 
570
    GC_register_my_thread_inner(sb, t);
 
571
    UNLOCK();
 
572
    return GC_SUCCESS;
 
573
  } else {
 
574
    return GC_DUPLICATE;
 
575
  }
 
576
}
 
577
 
 
578
GC_API int GC_unregister_my_thread(void)
 
579
{
 
580
    DWORD t = GetCurrentThreadId();
 
581
 
 
582
#   if defined(THREAD_LOCAL_ALLOC)
 
583
      LOCK();
 
584
      {
 
585
        GC_thread me = GC_lookup_thread_inner(t);
 
586
        GC_destroy_thread_local(&(me->tlfs));
 
587
      }
 
588
      UNLOCK();
 
589
#   endif
 
590
    if (GC_win32_dll_threads) {
 
591
      /* Should we just ignore this? */
 
592
      GC_delete_thread(t);
 
593
    } else {
 
594
      LOCK();
 
595
      GC_delete_thread(t);
 
596
      UNLOCK();
 
597
    }
 
598
    return GC_SUCCESS;
 
599
}
 
600
 
 
601
 
 
602
#ifdef GC_PTHREADS
 
603
 
 
604
/* A quick-and-dirty cache of the mapping between pthread_t     */
 
605
/* and win32 thread id.                                         */
 
606
#define PTHREAD_MAP_SIZE 512
 
607
DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE];
 
608
#define HASH(pthread_id) ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
 
609
        /* It appears pthread_t is really a pointer type ... */
 
610
#define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
 
611
        GC_pthread_map_cache[HASH(pthread_id)] = (win32_id);
 
612
#define GET_PTHREAD_MAP_CACHE(pthread_id) \
 
613
        GC_pthread_map_cache[HASH(pthread_id)]
197
614
 
198
615
/* Return a GC_thread corresponding to a given pthread_t.       */
199
616
/* Returns 0 if it's not there.                                 */
200
617
/* We assume that this is only called for pthread ids that      */
201
 
/* have not yet terminated or are still joinable.               */
202
 
static GC_thread GC_lookup_thread(pthread_t id)
 
618
/* have not yet terminated or are still joinable, and           */
 
619
/* cannot be concurrently terminated.                           */
 
620
/* Assumes we do NOT hold the allocation lock.                  */
 
621
static GC_thread GC_lookup_pthread(pthread_t id)
203
622
{
204
 
  int i;
205
 
  LONG my_max = GC_get_max_thread_index();
 
623
  if (GC_win32_dll_threads) {
 
624
    int i;
 
625
    LONG my_max = GC_get_max_thread_index();
206
626
 
207
 
  for (i = 0;
208
 
       i <= my_max &&
209
 
       (!thread_table[i].in_use || thread_table[i].pthread_id != id
210
 
        || !thread_table[i].in_use);
 
627
    for (i = 0;
 
628
         i <= my_max &&
 
629
         (!AO_load_acquire(&(dll_thread_table[i].in_use))
 
630
          || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
211
631
       /* Must still be in_use, since nobody else can store our thread_id. */
212
632
       i++);
213
 
  if (i > my_max) return 0;
214
 
  return thread_table + i;
 
633
    if (i > my_max) return 0;
 
634
    return (GC_thread)(dll_thread_table + i);
 
635
  } else {
 
636
    /* We first try the cache.  If that fails, we use a very slow       */
 
637
    /* approach.                                                        */
 
638
    int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ;
 
639
    int hv;
 
640
    GC_thread p;
 
641
 
 
642
    LOCK();
 
643
    for (p = GC_threads[hv_guess]; 0 != p; p = p -> next) {
 
644
      if (THREAD_EQUAL(p -> pthread_id, id))
 
645
        goto foundit; 
 
646
    }
 
647
    for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
 
648
      for (p = GC_threads[hv]; 0 != p; p = p -> next) {
 
649
        if (THREAD_EQUAL(p -> pthread_id, id))
 
650
          goto foundit; 
 
651
      }
 
652
    }
 
653
    p = 0;
 
654
   foundit:
 
655
    UNLOCK();
 
656
    return p;
 
657
  }
215
658
}
216
659
 
217
 
#endif /* CYGWIN32 */
 
660
#endif /* GC_PTHREADS */
218
661
 
219
 
void GC_push_thread_structures GC_PROTO((void))
 
662
void GC_push_thread_structures(void)
220
663
{
 
664
  GC_ASSERT(I_HOLD_LOCK());
 
665
  if (GC_win32_dll_threads) {
221
666
    /* Unlike the other threads implementations, the thread table here  */
222
667
    /* contains no pointers to the collectable heap.  Thus we have      */
223
668
    /* no private structures we need to preserve.                       */
224
 
# ifdef CYGWIN32
225
 
  { int i; /* pthreads may keep a pointer in the thread exit value */
226
 
    LONG my_max = GC_get_max_thread_index();
 
669
#   ifdef GC_PTHREADS 
 
670
    { int i; /* pthreads may keep a pointer in the thread exit value */
 
671
      LONG my_max = GC_get_max_thread_index();
227
672
 
228
 
    for (i = 0; i <= my_max; i++)
229
 
      if (thread_table[i].in_use)
230
 
        GC_push_all((ptr_t)&(thread_table[i].status),
231
 
                    (ptr_t)(&(thread_table[i].status)+1));
 
673
      for (i = 0; i <= my_max; i++)
 
674
        if (dll_thread_table[i].in_use)
 
675
          GC_push_all((ptr_t)&(dll_thread_table[i].status),
 
676
                      (ptr_t)(&(dll_thread_table[i].status)+1));
 
677
    }
 
678
#   endif
 
679
  } else {
 
680
    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
232
681
  }
233
 
# endif
 
682
# if defined(THREAD_LOCAL_ALLOC)
 
683
    GC_push_all((ptr_t)(&GC_thread_key),
 
684
      (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
 
685
    /* Just in case we ever use our own TLS implementation.     */
 
686
# endif
 
687
}
 
688
 
 
689
/* Suspend the given thread, if it's still active.      */
 
690
void GC_suspend(GC_thread t)
 
691
{
 
692
# ifdef MSWINCE
 
693
    /* SuspendThread will fail if thread is running kernel code */
 
694
      while (SuspendThread(t -> handle) == (DWORD)-1)
 
695
        Sleep(10);
 
696
# else
 
697
    /* Apparently the Windows 95 GetOpenFileName call creates   */
 
698
    /* a thread that does not properly get cleaned up, and              */
 
699
    /* SuspendThread on its descriptor may provoke a crash.             */
 
700
    /* This reduces the probability of that event, though it still      */
 
701
    /* appears there's a race here.                                     */
 
702
    DWORD exitCode; 
 
703
    if (GetExitCodeThread(t -> handle, &exitCode) &&
 
704
        exitCode != STILL_ACTIVE) {
 
705
      t -> stack_base = 0; /* prevent stack from being pushed */
 
706
#     ifndef GC_PTHREADS
 
707
        /* this breaks pthread_join on Cygwin, which is guaranteed to  */
 
708
        /* only see user pthreads                                      */
 
709
        GC_ASSERT(GC_win32_dll_threads);
 
710
        GC_delete_gc_thread(t);
 
711
#     endif
 
712
      return;
 
713
    }
 
714
    if (SuspendThread(t -> handle) == (DWORD)-1)
 
715
      ABORT("SuspendThread failed");
 
716
# endif
 
717
   t -> suspended = TRUE;
234
718
}
235
719
 
236
720
/* Defined in misc.c */
237
 
extern CRITICAL_SECTION GC_write_cs;
 
721
#ifndef CYGWIN32
 
722
  extern CRITICAL_SECTION GC_write_cs;
 
723
#endif
238
724
 
239
 
void GC_stop_world()
 
725
void GC_stop_world(void)
240
726
{
241
727
  DWORD thread_id = GetCurrentThreadId();
242
728
  int i;
243
729
 
244
730
  if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
 
731
  GC_ASSERT(I_HOLD_LOCK());
245
732
 
246
733
  GC_please_stop = TRUE;
247
734
# ifndef CYGWIN32
248
735
    EnterCriticalSection(&GC_write_cs);
249
 
# endif /* !CYGWIN32 */
250
 
  for (i = 0; i <= GC_get_max_thread_index(); i++)
251
 
    if (thread_table[i].stack_base != 0
252
 
        && thread_table[i].id != thread_id) {
253
 
#     ifdef MSWINCE
254
 
        /* SuspendThread will fail if thread is running kernel code */
255
 
        while (SuspendThread(thread_table[i].handle) == (DWORD)-1)
256
 
          Sleep(10);
257
 
#     else
258
 
        /* Apparently the Windows 95 GetOpenFileName call creates       */
259
 
        /* a thread that does not properly get cleaned up, and          */
260
 
        /* SuspendThread on its descriptor may provoke a crash.         */
261
 
        /* This reduces the probability of that event, though it still  */
262
 
        /* appears there's a race here.                                 */
263
 
        DWORD exitCode; 
264
 
        if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
265
 
            exitCode != STILL_ACTIVE) {
266
 
          thread_table[i].stack_base = 0; /* prevent stack from being pushed */
267
 
#         ifndef CYGWIN32
268
 
            /* this breaks pthread_join on Cygwin, which is guaranteed to  */
269
 
            /* only see user pthreads                                      */
270
 
            thread_table[i].in_use = FALSE;
271
 
            CloseHandle(thread_table[i].handle);
272
 
#         endif
273
 
          continue;
 
736
# endif
 
737
  if (GC_win32_dll_threads) {
 
738
    /* Any threads being created during this loop will end up setting   */
 
739
    /* GC_attached_thread when they start.  This will force marking to  */
 
740
    /* restart.                                                         */
 
741
    /* This is not ideal, but hopefully correct.                        */
 
742
    GC_attached_thread = FALSE;
 
743
    for (i = 0; i <= GC_get_max_thread_index(); i++) {
 
744
      GC_vthread t = dll_thread_table + i;
 
745
      if (t -> stack_base != 0
 
746
          && t -> id != thread_id) {
 
747
          GC_suspend((GC_thread)t);
 
748
      }
 
749
    }
 
750
  } else {
 
751
      GC_thread t;
 
752
      int i;
 
753
 
 
754
      for (i = 0; i < THREAD_TABLE_SZ; i++) {
 
755
        for (t = GC_threads[i]; t != 0; t = t -> next) {
 
756
          if (t -> stack_base != 0
 
757
          && !KNOWN_FINISHED(t)
 
758
          && t -> id != thread_id) {
 
759
            GC_suspend(t);
 
760
          }
274
761
        }
275
 
        if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
276
 
          ABORT("SuspendThread failed");
277
 
#     endif
278
 
      thread_table[i].suspended = TRUE;
279
 
    }
 
762
      }
 
763
  }
280
764
# ifndef CYGWIN32
281
765
    LeaveCriticalSection(&GC_write_cs);
282
 
# endif /* !CYGWIN32 */
 
766
# endif    
283
767
}
284
768
 
285
 
void GC_start_world()
 
769
void GC_start_world(void)
286
770
{
287
771
  DWORD thread_id = GetCurrentThreadId();
288
772
  int i;
289
773
  LONG my_max = GC_get_max_thread_index();
290
774
 
291
 
  for (i = 0; i <= my_max; i++)
292
 
    if (thread_table[i].stack_base != 0 && thread_table[i].suspended
293
 
        && thread_table[i].id != thread_id) {
294
 
      if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
295
 
        ABORT("ResumeThread failed");
296
 
      thread_table[i].suspended = FALSE;
297
 
    }
 
775
  GC_ASSERT(I_HOLD_LOCK());
 
776
  if (GC_win32_dll_threads) {
 
777
    for (i = 0; i <= my_max; i++) {
 
778
      GC_thread t = (GC_thread)(dll_thread_table + i);
 
779
      if (t -> stack_base != 0 && t -> suspended
 
780
          && t -> id != thread_id) {
 
781
        if (ResumeThread(t -> handle) == (DWORD)-1)
 
782
          ABORT("ResumeThread failed");
 
783
        t -> suspended = FALSE;
 
784
      }
 
785
    }
 
786
  } else {
 
787
    GC_thread t;
 
788
    int i;
 
789
 
 
790
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
 
791
      for (t = GC_threads[i]; t != 0; t = t -> next) {
 
792
        if (t -> stack_base != 0 && t -> suspended
 
793
            && t -> id != thread_id) {
 
794
          if (ResumeThread(t -> handle) == (DWORD)-1)
 
795
            ABORT("ResumeThread failed");
 
796
          t -> suspended = FALSE;
 
797
        }
 
798
      }
 
799
    }
 
800
  }
298
801
  GC_please_stop = FALSE;
299
802
}
300
803
 
301
 
# ifdef _MSC_VER
302
 
#   pragma warning(disable:4715)
303
 
# endif
304
 
ptr_t GC_current_stackbottom()
305
 
{
306
 
  DWORD thread_id = GetCurrentThreadId();
307
 
  int i;
308
 
  LONG my_max = GC_get_max_thread_index();
309
 
 
310
 
  for (i = 0; i <= my_max; i++)
311
 
    if (thread_table[i].stack_base && thread_table[i].id == thread_id)
312
 
      return thread_table[i].stack_base;
313
 
  ABORT("no thread table entry for current thread");
314
 
}
315
 
# ifdef _MSC_VER
316
 
#   pragma warning(default:4715)
317
 
# endif
318
 
 
319
804
# ifdef MSWINCE
320
805
    /* The VirtualQuery calls below won't work properly on WinCE, but   */
321
806
    /* since each stack is restricted to an aligned 64K region of       */
337
822
    }
338
823
# endif
339
824
 
340
 
void GC_push_all_stacks()
 
825
void GC_push_stack_for(GC_thread thread)
341
826
{
342
 
  DWORD thread_id = GetCurrentThreadId();
343
 
  GC_bool found_me = FALSE;
344
 
  int i;
345
 
  int dummy;
346
 
  ptr_t sp, stack_min;
347
 
  GC_thread thread;
348
 
  LONG my_max = GC_get_max_thread_index();
349
 
  
350
 
  for (i = 0; i <= my_max; i++) {
351
 
    thread = thread_table + i;
352
 
    if (thread -> in_use && thread -> stack_base) {
353
 
      if (thread -> id == thread_id) {
 
827
    int dummy;
 
828
    ptr_t sp, stack_min;
 
829
    DWORD me = GetCurrentThreadId();
 
830
 
 
831
    if (thread -> stack_base) {
 
832
      if (thread -> id == me) {
354
833
        sp = (ptr_t) &dummy;
355
 
        found_me = TRUE;
356
834
      } else {
357
835
        CONTEXT context;
358
836
        context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
359
 
        if (!GetThreadContext(thread_table[i].handle, &context))
 
837
        if (!GetThreadContext(thread -> handle, &context))
360
838
          ABORT("GetThreadContext failed");
361
839
 
362
840
        /* Push all registers that might point into the heap.  Frame    */
368
846
#       if defined(I386)
369
847
          PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
370
848
          sp = (ptr_t)context.Esp;
 
849
#       elif defined(X86_64)
 
850
          PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
 
851
          PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
 
852
          sp = (ptr_t)context.Rsp;
371
853
#       elif defined(ARM32)
372
854
          PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
373
855
          sp = (ptr_t)context.Sp;
396
878
#       else
397
879
#         error "architecture is not supported"
398
880
#       endif
399
 
      }
 
881
      } /* ! current thread */
400
882
 
401
883
      stack_min = GC_get_stack_min(thread->stack_base);
402
884
 
403
 
      if (sp >= stack_min && sp < thread->stack_base)
 
885
      if (sp >= stack_min && sp < thread->stack_base) {
 
886
#       if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \
 
887
           || DEBUG_CYGWIN_THREADS
 
888
          GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n",
 
889
                    sp, thread -> stack_base, thread -> id, me);
 
890
#       endif
404
891
        GC_push_all_stack(sp, thread->stack_base);
405
 
      else {
 
892
      } else {
406
893
        WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
407
 
             (unsigned long)sp);
 
894
             (unsigned long)(size_t)sp);
408
895
        GC_push_all_stack(stack_min, thread->stack_base);
409
896
      }
410
 
    }
411
 
  }
412
 
  if (!found_me) ABORT("Collecting from unknown thread.");
 
897
    } /* thread looks live */
 
898
}
 
899
 
 
900
void GC_push_all_stacks(void)
 
901
{
 
902
  DWORD me = GetCurrentThreadId();
 
903
  GC_bool found_me = FALSE;
 
904
  size_t nthreads = 0;
 
905
  
 
906
  if (GC_win32_dll_threads) {
 
907
    int i;
 
908
    LONG my_max = GC_get_max_thread_index();
 
909
 
 
910
    for (i = 0; i <= my_max; i++) {
 
911
      GC_thread t = (GC_thread)(dll_thread_table + i);
 
912
      if (t -> in_use) {
 
913
        ++nthreads;
 
914
        GC_push_stack_for(t);
 
915
        if (t -> id == me) found_me = TRUE;
 
916
      }
 
917
    }
 
918
  } else {
 
919
    GC_thread t;
 
920
    int i;
 
921
 
 
922
    for (i = 0; i < THREAD_TABLE_SZ; i++) {
 
923
      for (t = GC_threads[i]; t != 0; t = t -> next) {
 
924
        ++nthreads;
 
925
        if (!KNOWN_FINISHED(t)) GC_push_stack_for(t);
 
926
        if (t -> id == me) found_me = TRUE;
 
927
      }
 
928
    }
 
929
  }
 
930
  if (GC_print_stats == VERBOSE) {
 
931
    GC_log_printf("Pushed %d thread stacks ", nthreads);
 
932
    if (GC_win32_dll_threads) {
 
933
        GC_log_printf("based on DllMain thread tracking\n");
 
934
    } else {
 
935
        GC_log_printf("\n");
 
936
    }
 
937
  }
 
938
  if (!found_me && !GC_in_thread_creation)
 
939
    ABORT("Collecting from unknown thread.");
413
940
}
414
941
 
415
942
void GC_get_next_stack(char *start, char **lo, char **hi)
417
944
    int i;
418
945
#   define ADDR_LIMIT (char *)(-1L)
419
946
    char * current_min = ADDR_LIMIT;
420
 
    LONG my_max = GC_get_max_thread_index();
 
947
 
 
948
    if (GC_win32_dll_threads) {
 
949
      LONG my_max = GC_get_max_thread_index();
421
950
  
422
 
    for (i = 0; i <= my_max; i++) {
423
 
        char * s = (char *)thread_table[i].stack_base;
 
951
      for (i = 0; i <= my_max; i++) {
 
952
        ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
424
953
 
425
954
        if (0 != s && s > start && s < current_min) {
426
955
            current_min = s;
427
956
        }
 
957
      }
 
958
    } else {
 
959
      for (i = 0; i < THREAD_TABLE_SZ; i++) {
 
960
        GC_thread t;
 
961
 
 
962
        for (t = GC_threads[i]; t != 0; t = t -> next) {
 
963
          ptr_t s = (ptr_t)(t -> stack_base);
 
964
 
 
965
          if (0 != s && s > start && s < current_min) {
 
966
            current_min = s;
 
967
          }
 
968
        }
 
969
      }
428
970
    }
429
971
    *hi = current_min;
430
972
    if (current_min == ADDR_LIMIT) {
435
977
    if (*lo < start) *lo = start;
436
978
}
437
979
 
438
 
#if !defined(CYGWIN32)
439
 
 
440
 
#if !defined(MSWINCE) && defined(GC_DLL)
441
 
 
442
 
/* We register threads from DllMain */
443
 
 
444
 
GC_API HANDLE WINAPI GC_CreateThread(
445
 
    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
446
 
    DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
447
 
    LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
448
 
{
449
 
    return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
450
 
                        lpParameter, dwCreationFlags, lpThreadId);
451
 
}
452
 
 
453
 
#else /* defined(MSWINCE) || !defined(GC_DLL))  */
 
980
#ifndef GC_PTHREADS
454
981
 
455
982
/* We have no DllMain to take care of new threads.  Thus we     */
456
983
/* must properly intercept thread creation.                     */
462
989
 
463
990
static DWORD WINAPI thread_start(LPVOID arg);
464
991
 
465
 
GC_API HANDLE WINAPI GC_CreateThread(
466
 
    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
467
 
    DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
468
 
    LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
469
 
{
470
 
    HANDLE thread_h = NULL;
471
 
 
472
 
    thread_args *args;
473
 
 
474
 
    if (!GC_is_initialized) GC_init();
475
 
                /* make sure GC is initialized (i.e. main thread is attached) */
476
 
    
477
 
    args = GC_malloc_uncollectable(sizeof(thread_args)); 
478
 
        /* Handed off to and deallocated by child thread.       */
479
 
    if (0 == args) {
480
 
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
481
 
        return NULL;
482
 
    }
483
 
 
484
 
    /* set up thread arguments */
485
 
        args -> start = lpStartAddress;
486
 
        args -> param = lpParameter;
487
 
 
488
 
    thread_h = CreateThread(lpThreadAttributes,
489
 
                            dwStackSize, thread_start,
490
 
                            args, dwCreationFlags,
491
 
                            lpThreadId);
492
 
 
493
 
    return thread_h;
494
 
}
495
 
 
496
 
static DWORD WINAPI thread_start(LPVOID arg)
497
 
{
498
 
    DWORD ret = 0;
 
992
void * GC_win32_start_inner(struct GC_stack_base *sb, LPVOID arg)
 
993
{
 
994
    void * ret;
499
995
    thread_args *args = (thread_args *)arg;
500
996
 
501
 
    GC_new_thread();
 
997
#   if DEBUG_WIN32_THREADS
 
998
      GC_printf("thread 0x%x starting...\n", GetCurrentThreadId());
 
999
#   endif
 
1000
 
 
1001
    GC_register_my_thread(sb); /* This waits for an in-progress GC. */
502
1002
 
503
1003
    /* Clear the thread entry even if we exit with an exception.        */
504
1004
    /* This is probably pointless, since an uncaught exception is       */
506
1006
#ifndef __GNUC__
507
1007
    __try {
508
1008
#endif /* __GNUC__ */
509
 
        ret = args->start (args->param);
 
1009
        ret = (void *)(size_t)args->start (args->param);
510
1010
#ifndef __GNUC__
511
1011
    } __finally {
512
1012
#endif /* __GNUC__ */
 
1013
        GC_unregister_my_thread();
513
1014
        GC_free(args);
514
 
        GC_delete_thread(GetCurrentThreadId());
515
1015
#ifndef __GNUC__
516
1016
    }
517
1017
#endif /* __GNUC__ */
518
1018
 
 
1019
#   if DEBUG_WIN32_THREADS
 
1020
      GC_printf("thread 0x%x returned from start routine.\n",
 
1021
                GetCurrentThreadId());
 
1022
#   endif
519
1023
    return ret;
520
1024
}
521
 
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))  */
522
 
 
523
 
#endif /* !CYGWIN32 */
 
1025
 
 
1026
DWORD WINAPI GC_win32_start(LPVOID arg)
 
1027
{
 
1028
    return (DWORD)(size_t)GC_call_with_stack_base(GC_win32_start_inner, arg);
 
1029
}
 
1030
 
 
1031
GC_API HANDLE WINAPI GC_CreateThread(
 
1032
    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
 
1033
    DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
 
1034
    LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
 
1035
{
 
1036
    HANDLE thread_h = NULL;
 
1037
 
 
1038
    thread_args *args;
 
1039
 
 
1040
    if (!parallel_initialized) GC_init_parallel();
 
1041
                /* make sure GC is initialized (i.e. main thread is attached,
 
1042
                   tls initialized) */
 
1043
 
 
1044
#   if DEBUG_WIN32_THREADS
 
1045
      GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
 
1046
#   endif
 
1047
    if (GC_win32_dll_threads) {
 
1048
      return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
 
1049
                        lpParameter, dwCreationFlags, lpThreadId);
 
1050
    } else {
 
1051
      args = GC_malloc_uncollectable(sizeof(thread_args)); 
 
1052
        /* Handed off to and deallocated by child thread.       */
 
1053
      if (0 == args) {
 
1054
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 
1055
        return NULL;
 
1056
      }
 
1057
 
 
1058
      /* set up thread arguments */
 
1059
        args -> start = lpStartAddress;
 
1060
        args -> param = lpParameter;
 
1061
 
 
1062
      GC_need_to_lock = TRUE;
 
1063
      thread_h = CreateThread(lpThreadAttributes,
 
1064
                              dwStackSize, GC_win32_start,
 
1065
                              args, dwCreationFlags,
 
1066
                              lpThreadId);
 
1067
      if( thread_h == 0 ) GC_free( args );
 
1068
      return thread_h;
 
1069
    }
 
1070
}
 
1071
 
 
1072
void WINAPI GC_ExitThread(DWORD dwExitCode)
 
1073
{
 
1074
  GC_unregister_my_thread();
 
1075
  ExitThread(dwExitCode);
 
1076
}
 
1077
 
 
1078
uintptr_t GC_beginthreadex(
 
1079
    void *security, unsigned stack_size,
 
1080
    unsigned ( __stdcall *start_address )( void * ),
 
1081
    void *arglist, unsigned initflag, unsigned *thrdaddr)
 
1082
{
 
1083
    uintptr_t thread_h;
 
1084
 
 
1085
    thread_args *args;
 
1086
 
 
1087
    if (!parallel_initialized) GC_init_parallel();
 
1088
                /* make sure GC is initialized (i.e. main thread is attached,
 
1089
                   tls initialized) */
 
1090
#   if DEBUG_WIN32_THREADS
 
1091
      GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
 
1092
#   endif
 
1093
 
 
1094
    if (GC_win32_dll_threads) {
 
1095
      return _beginthreadex(security, stack_size, start_address,
 
1096
                            arglist, initflag, thrdaddr);
 
1097
    } else {
 
1098
      args = GC_malloc_uncollectable(sizeof(thread_args)); 
 
1099
        /* Handed off to and deallocated by child thread.       */
 
1100
      if (0 == args) {
 
1101
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 
1102
        return (uintptr_t)(-1L);
 
1103
      }
 
1104
 
 
1105
      /* set up thread arguments */
 
1106
        args -> start = (LPTHREAD_START_ROUTINE)start_address;
 
1107
        args -> param = arglist;
 
1108
 
 
1109
      GC_need_to_lock = TRUE;
 
1110
      thread_h = _beginthreadex(security, stack_size,
 
1111
                 (unsigned (__stdcall *) (void *))GC_win32_start,
 
1112
                                args, initflag, thrdaddr);
 
1113
      if( thread_h == 0 ) GC_free( args );
 
1114
      return thread_h;
 
1115
    }
 
1116
}
 
1117
 
 
1118
void GC_endthreadex(unsigned retval)
 
1119
{
 
1120
  GC_unregister_my_thread();
 
1121
  _endthreadex(retval);
 
1122
}
 
1123
 
 
1124
#endif /* !GC_PTHREADS */
524
1125
 
525
1126
#ifdef MSWINCE
526
1127
 
575
1176
# else /* !MSWINCE */
576
1177
 
577
1178
/* Called by GC_init() - we hold the allocation lock.   */
578
 
void GC_thr_init() {
 
1179
void GC_thr_init(void) {
 
1180
    struct GC_stack_base sb;
 
1181
    int sb_result;
 
1182
 
 
1183
    GC_ASSERT(I_HOLD_LOCK());
579
1184
    if (GC_thr_initialized) return;
580
1185
    GC_main_thread = GetCurrentThreadId();
581
1186
    GC_thr_initialized = TRUE;
582
1187
 
583
1188
    /* Add the initial thread, so we can stop it.       */
584
 
    GC_new_thread();
 
1189
    sb_result = GC_get_stack_base(&sb);
 
1190
    GC_ASSERT(sb_result == GC_SUCCESS);
 
1191
    GC_register_my_thread(&sb);
585
1192
}
586
1193
 
587
 
#ifdef CYGWIN32
 
1194
#ifdef GC_PTHREADS
588
1195
 
589
1196
struct start_info {
590
1197
    void *(*start_routine)(void *);
595
1202
int GC_pthread_join(pthread_t pthread_id, void **retval) {
596
1203
    int result;
597
1204
    int i;
598
 
    GC_thread me;
 
1205
    GC_thread joinee;
599
1206
 
600
1207
#   if DEBUG_CYGWIN_THREADS
601
 
      GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",
602
 
                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
 
1208
      GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
 
1209
                (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
 
1210
#   endif
 
1211
#   if DEBUG_WIN32_PTHREADS
 
1212
      GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
 
1213
                (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
603
1214
#   endif
604
1215
 
 
1216
    if (!parallel_initialized) GC_init_parallel();
605
1217
    /* Thread being joined might not have registered itself yet. */
606
1218
    /* After the join,thread id may have been recycled.          */
607
1219
    /* FIXME: It would be better if this worked more like        */
608
1220
    /* pthread_support.c.                                        */
609
1221
 
610
 
    while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10);
 
1222
    #ifndef GC_WIN32_PTHREADS
 
1223
      while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10);
 
1224
    #endif
611
1225
 
612
1226
    result = pthread_join(pthread_id, retval);
613
1227
 
614
 
    GC_delete_gc_thread(me);
 
1228
    #ifdef GC_WIN32_PTHREADS
 
1229
      /* win32_pthreads id are unique */
 
1230
      joinee = GC_lookup_pthread(pthread_id);
 
1231
    #endif
 
1232
 
 
1233
    if (!GC_win32_dll_threads) {
 
1234
      LOCK();
 
1235
      GC_delete_gc_thread(joinee);
 
1236
      UNLOCK();
 
1237
    } /* otherwise dllmain handles it.  */
615
1238
 
616
1239
#   if DEBUG_CYGWIN_THREADS
617
 
      GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
 
1240
      GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
618
1241
                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
619
1242
#   endif
 
1243
#   if DEBUG_WIN32_PTHREADS
 
1244
      GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
 
1245
                (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
 
1246
#   endif
620
1247
 
621
1248
    return result;
622
1249
}
632
1259
    int result;
633
1260
    struct start_info * si;
634
1261
 
635
 
    if (!GC_is_initialized) GC_init();
 
1262
    if (!parallel_initialized) GC_init_parallel();
636
1263
                /* make sure GC is initialized (i.e. main thread is attached) */
 
1264
    if (GC_win32_dll_threads) {
 
1265
      return pthread_create(new_thread, attr, start_routine, arg);
 
1266
    }
637
1267
    
638
1268
    /* This is otherwise saved only in an area mmapped by the thread */
639
1269
    /* library, which isn't visible to the collector.            */
649
1279
    }
650
1280
 
651
1281
#   if DEBUG_CYGWIN_THREADS
652
 
      GC_printf2("About to create a thread from 0x%x(0x%x)\n",
653
 
                 (int)pthread_self(), GetCurrentThreadId);
654
 
#   endif
655
 
    result = pthread_create(new_thread, attr, GC_start_routine, si); 
 
1282
      GC_printf("About to create a thread from 0x%x(0x%x)\n",
 
1283
                (int)pthread_self(), GetCurrentThreadId);
 
1284
#   endif
 
1285
#   if DEBUG_WIN32_PTHREADS
 
1286
      GC_printf("About to create a thread from 0x%x(0x%x)\n",
 
1287
                (int)(pthread_self()).p, GetCurrentThreadId());
 
1288
#   endif
 
1289
    GC_need_to_lock = TRUE;
 
1290
    result = pthread_create(new_thread, attr, GC_pthread_start, si); 
656
1291
 
657
1292
    if (result) { /* failure */
658
1293
        GC_free(si);
661
1296
    return(result);
662
1297
}
663
1298
 
664
 
void * GC_start_routine(void * arg)
 
1299
void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg)
665
1300
{
666
1301
    struct start_info * si = arg;
667
1302
    void * result;
668
1303
    void *(*start)(void *);
669
1304
    void *start_arg;
670
 
    pthread_t pthread_id;
 
1305
    DWORD thread_id = GetCurrentThreadId();
 
1306
    pthread_t pthread_id = pthread_self();
671
1307
    GC_thread me;
672
1308
    GC_bool detached;
673
1309
    int i;
674
1310
 
675
1311
#   if DEBUG_CYGWIN_THREADS
676
 
      GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
677
 
                                                   GetCurrentThreadId());
 
1312
      GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id,
 
1313
                                                  thread_id);
 
1314
#   endif
 
1315
#   if DEBUG_WIN32_PTHREADS
 
1316
      GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p,
 
1317
                                                  thread_id);
678
1318
#   endif
679
1319
 
 
1320
    GC_ASSERT(!GC_win32_dll_threads);
680
1321
    /* If a GC occurs before the thread is registered, that GC will     */
681
1322
    /* ignore this thread.  That's fine, since it will block trying to  */
682
1323
    /* acquire the allocation lock, and won't yet hold interesting      */
684
1325
    LOCK();
685
1326
    /* We register the thread here instead of in the parent, so that    */
686
1327
    /* we don't need to hold the allocation lock during pthread_create. */
687
 
    me = GC_new_thread();
 
1328
    me = GC_register_my_thread_inner(sb, thread_id);
 
1329
    SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
688
1330
    UNLOCK();
689
1331
 
690
1332
    start = si -> start_routine;
691
1333
    start_arg = si -> arg;
692
1334
    if (si-> detached) me -> flags |= DETACHED;
693
 
    me -> pthread_id = pthread_id = pthread_self();
 
1335
    me -> pthread_id = pthread_id;
694
1336
 
695
1337
    GC_free(si); /* was allocated uncollectable */
696
1338
 
697
1339
    pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
698
1340
    result = (*start)(start_arg);
699
1341
    me -> status = result;
700
 
    pthread_cleanup_pop(0);
 
1342
    pthread_cleanup_pop(1);
701
1343
 
702
1344
#   if DEBUG_CYGWIN_THREADS
703
 
      GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
704
 
                 (int)pthread_self(),GetCurrentThreadId());
 
1345
      GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
 
1346
                (int)pthread_self(),GetCurrentThreadId());
 
1347
#   endif
 
1348
#   if DEBUG_WIN32_PTHREADS
 
1349
      GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
 
1350
                (int)(pthread_self()).p, GetCurrentThreadId());
705
1351
#   endif
706
1352
 
707
1353
    return(result);
708
1354
}
709
1355
 
 
1356
void * GC_pthread_start(void * arg)
 
1357
{
 
1358
    return GC_call_with_stack_base(GC_pthread_start_inner, arg);
 
1359
}
 
1360
 
710
1361
void GC_thread_exit_proc(void *arg)
711
1362
{
712
1363
    GC_thread me = (GC_thread)arg;
713
1364
    int i;
714
1365
 
 
1366
    GC_ASSERT(!GC_win32_dll_threads);
715
1367
#   if DEBUG_CYGWIN_THREADS
716
 
      GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
717
 
                 (int)pthread_self(),GetCurrentThreadId());
 
1368
      GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
 
1369
                (int)pthread_self(),GetCurrentThreadId());
 
1370
#   endif
 
1371
#   if DEBUG_WIN32_PTHREADS
 
1372
      GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
 
1373
                (int)(pthread_self()).p,GetCurrentThreadId());
718
1374
#   endif
719
1375
 
720
1376
    LOCK();
 
1377
#   if defined(THREAD_LOCAL_ALLOC)
 
1378
      GC_destroy_thread_local(&(me->tlfs));
 
1379
#   endif
721
1380
    if (me -> flags & DETACHED) {
722
1381
      GC_delete_thread(GetCurrentThreadId());
723
1382
    } else {
727
1386
    UNLOCK();
728
1387
}
729
1388
 
 
1389
#ifndef GC_WIN32_PTHREADS
 
1390
/* win32 pthread does not support sigmask */
730
1391
/* nothing required here... */
731
1392
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
 
1393
  if (!parallel_initialized) GC_init_parallel();
732
1394
  return pthread_sigmask(how, set, oset);
733
1395
}
 
1396
#endif
734
1397
 
735
1398
int GC_pthread_detach(pthread_t thread)
736
1399
{
737
1400
    int result;
738
1401
    GC_thread thread_gc_id;
739
1402
    
 
1403
    if (!parallel_initialized) GC_init_parallel();
740
1404
    LOCK();
741
 
    thread_gc_id = GC_lookup_thread(thread);
 
1405
    thread_gc_id = GC_lookup_pthread(thread);
742
1406
    UNLOCK();
743
1407
    result = pthread_detach(thread);
744
1408
    if (result == 0) {
753
1417
    return result;
754
1418
}
755
1419
 
756
 
#else /* !CYGWIN32 */
 
1420
#else /* !GC_PTHREADS */
757
1421
 
758
1422
/*
759
1423
 * We avoid acquiring locks here, since this doesn't seem to be preemptable.
760
 
 * Pontus Rydin suggests wrapping the thread start routine instead.
 
1424
 * This may run with an uninitialized collector, in which case we don't do much.
 
1425
 * This implies that no threads other than the main one should be created
 
1426
 * with an uninitialized collector.  (The alternative of initializing
 
1427
 * the collector here seems dangerous, since DllMain is limited in what it
 
1428
 * can do.)
761
1429
 */
762
1430
#ifdef GC_DLL
763
 
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
 
1431
GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
764
1432
{
 
1433
  struct GC_stack_base sb;
 
1434
  DWORD thread_id;
 
1435
  int sb_result;
 
1436
  static int entry_count = 0;
 
1437
 
 
1438
  if (parallel_initialized && !GC_win32_dll_threads) return TRUE;
 
1439
 
765
1440
  switch (reason) {
766
 
  case DLL_PROCESS_ATTACH:
767
 
    GC_init();  /* Force initialization before thread attach.   */
768
 
    /* fall through */
769
 
  case DLL_THREAD_ATTACH:
770
 
    GC_ASSERT(GC_thr_initialized);
771
 
    if (GC_main_thread != GetCurrentThreadId()) {
772
 
        GC_new_thread();
 
1441
   case DLL_THREAD_ATTACH:
 
1442
    GC_ASSERT(entry_count == 0 || parallel_initialized);
 
1443
    ++entry_count; /* and fall through: */
 
1444
   case DLL_PROCESS_ATTACH:
 
1445
    /* This may run with the collector uninitialized. */
 
1446
    thread_id = GetCurrentThreadId();
 
1447
    if (parallel_initialized && GC_main_thread != thread_id) {
 
1448
        /* Don't lock here.     */
 
1449
        sb_result = GC_get_stack_base(&sb);
 
1450
        GC_ASSERT(sb_result == GC_SUCCESS);
 
1451
#       ifdef THREAD_LOCAL_ALLOC
 
1452
          ABORT("Cannot initialize thread local cache from DllMain");
 
1453
#       endif
 
1454
        GC_register_my_thread_inner(&sb, thread_id);
773
1455
    } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
774
1456
    break;
775
1457
 
776
 
  case DLL_THREAD_DETACH:
 
1458
   case DLL_THREAD_DETACH:
 
1459
    /* We are hopefully running in the context of the exiting thread.   */
 
1460
    GC_ASSERT(parallel_initialized);
 
1461
    if (!GC_win32_dll_threads) return TRUE;
777
1462
    GC_delete_thread(GetCurrentThreadId());
778
1463
    break;
779
1464
 
780
 
  case DLL_PROCESS_DETACH:
 
1465
   case DLL_PROCESS_DETACH:
781
1466
    {
782
1467
      int i;
783
1468
 
784
 
      LOCK();
 
1469
      if (!GC_win32_dll_threads) return TRUE;
785
1470
      for (i = 0; i <= GC_get_max_thread_index(); ++i)
786
1471
      {
787
 
          if (thread_table[i].in_use)
788
 
            GC_delete_gc_thread(thread_table + i);
 
1472
          if (AO_load(&(dll_thread_table[i].in_use)))
 
1473
            GC_delete_gc_thread(dll_thread_table + i);
789
1474
      }
790
 
      UNLOCK();
791
1475
 
792
1476
      GC_deinit();
793
1477
      DeleteCriticalSection(&GC_allocate_ml);
798
1482
  return TRUE;
799
1483
}
800
1484
#endif /* GC_DLL */
801
 
#endif /* !CYGWIN32 */
 
1485
#endif /* !GC_PTHREADS */
802
1486
 
803
1487
# endif /* !MSWINCE */
804
1488
 
 
1489
/* Perform all initializations, including those that    */
 
1490
/* may require allocation.                              */
 
1491
/* Called without allocation lock.                      */
 
1492
/* Must be called before a second thread is created.    */
 
1493
void GC_init_parallel(void)
 
1494
{
 
1495
    if (parallel_initialized) return;
 
1496
    parallel_initialized = TRUE;
 
1497
    /* GC_init() calls us back, so set flag first.      */
 
1498
    
 
1499
    if (!GC_is_initialized) GC_init();
 
1500
    if (GC_win32_dll_threads) {
 
1501
      GC_need_to_lock = TRUE;
 
1502
        /* Cannot intercept thread creation.  Hence we don't know if    */
 
1503
        /* other threads exist.  However, client is not allowed to      */
 
1504
        /* create other threads before collector initialization.        */
 
1505
        /* Thus it's OK not to lock before this.                        */
 
1506
    }
 
1507
    /* Initialize thread local free lists if used.      */
 
1508
#   if defined(THREAD_LOCAL_ALLOC)
 
1509
      LOCK();
 
1510
      GC_init_thread_local(&(GC_lookup_thread(GetCurrentThreadId())->tlfs));
 
1511
      UNLOCK();
 
1512
#   endif
 
1513
}
 
1514
 
 
1515
#if defined(USE_PTHREAD_LOCKS)
 
1516
  /* Support for pthread locking code.          */
 
1517
  /* Pthread_mutex_try_lock may not win here,   */
 
1518
  /* due to builtinsupport for spinning first?  */
 
1519
 
 
1520
volatile GC_bool GC_collecting = 0;
 
1521
                        /* A hint that we're in the collector and       */
 
1522
                        /* holding the allocation lock for an           */
 
1523
                        /* extended period.                             */
 
1524
 
 
1525
void GC_lock(void)
 
1526
{
 
1527
    pthread_mutex_lock(&GC_allocate_ml);
 
1528
}
 
1529
#endif /* USE_PTHREAD ... */
 
1530
 
 
1531
# if defined(THREAD_LOCAL_ALLOC)
 
1532
 
 
1533
/* Add thread-local allocation support.  Microsoft uses __declspec(thread) */
 
1534
 
 
1535
/* We must explicitly mark ptrfree and gcj free lists, since the free   */
 
1536
/* list links wouldn't otherwise be found.  We also set them in the     */
 
1537
/* normal free lists, since that involves touching less memory than if  */
 
1538
/* we scanned them normally.                                            */
 
1539
void GC_mark_thread_local_free_lists(void)
 
1540
{
 
1541
    int i;
 
1542
    GC_thread p;
 
1543
    
 
1544
    for (i = 0; i < THREAD_TABLE_SZ; ++i) {
 
1545
      for (p = GC_threads[i]; 0 != p; p = p -> next) {
 
1546
        GC_mark_thread_local_fls_for(&(p->tlfs));
 
1547
      }
 
1548
    }
 
1549
}
 
1550
 
 
1551
#if defined(GC_ASSERTIONS)
 
1552
    /* Check that all thread-local free-lists are completely marked.    */
 
1553
    /* also check that thread-specific-data structures are marked.      */
 
1554
    void GC_check_tls(void) {
 
1555
        int i;
 
1556
        GC_thread p;
 
1557
        
 
1558
        for (i = 0; i < THREAD_TABLE_SZ; ++i) {
 
1559
          for (p = GC_threads[i]; 0 != p; p = p -> next) {
 
1560
            GC_check_tls_for(&(p->tlfs));
 
1561
          }
 
1562
        }
 
1563
#       if defined(USE_CUSTOM_SPECIFIC)
 
1564
          if (GC_thread_key != 0)
 
1565
            GC_check_tsd_marks(GC_thread_key);
 
1566
#       endif 
 
1567
    }
 
1568
#endif /* GC_ASSERTIONS */
 
1569
 
 
1570
#endif /* THREAD_LOCAL_ALLOC ... */
 
1571
 
805
1572
#endif /* GC_WIN32_THREADS */