]> granicus.if.org Git - gc/blob - win32_threads.c
Eliminate 'conversion from int to void*' MS VC warning in cordtest (x64)
[gc] / win32_threads.c
1 /*
2  * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
3  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
4  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
5  * Copyright (c) 2000-2008 by Hewlett-Packard Development Company.
6  * All rights reserved.
7  *
8  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
9  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
10  *
11  * Permission is hereby granted to use or copy this program
12  * for any purpose,  provided the above notices are retained on all copies.
13  * Permission to modify the code and to distribute modified code is granted,
14  * provided the above notices are retained, and a notice that the code was
15  * modified is included with the above copyright notice.
16  */
17
18 #include "private/gc_priv.h"
19
20 #if defined(GC_WIN32_THREADS)
21
22 #ifndef WIN32_LEAN_AND_MEAN
23 # define WIN32_LEAN_AND_MEAN 1
24 #endif
25 #define NOSERVICE
26 #include <windows.h>
27
28 #ifdef THREAD_LOCAL_ALLOC
29 # include "private/thread_local_alloc.h"
30 #endif /* THREAD_LOCAL_ALLOC */
31
32 /* Allocation lock declarations.        */
33 #if !defined(USE_PTHREAD_LOCKS)
34   GC_INNER CRITICAL_SECTION GC_allocate_ml;
35 # ifdef GC_ASSERTIONS
36     GC_INNER DWORD GC_lock_holder = NO_THREAD;
37         /* Thread id for current holder of allocation lock */
38 # endif
39 #else
40   GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
41 # ifdef GC_ASSERTIONS
42     GC_INNER unsigned long GC_lock_holder = NO_THREAD;
43 # endif
44 #endif
45
46 #undef CreateThread
47 #undef ExitThread
48 #undef _beginthreadex
49 #undef _endthreadex
50
51 #ifdef GC_PTHREADS
52 # include <errno.h> /* for EAGAIN */
53
54  /* Cygwin-specific forward decls */
55 # undef pthread_create
56 # undef pthread_join
57 # undef pthread_detach
58
59 # ifndef GC_NO_PTHREAD_SIGMASK
60 #   undef pthread_sigmask
61 # endif
62
63   STATIC void * GC_pthread_start(void * arg);
64   STATIC void GC_thread_exit_proc(void *arg);
65
66 # include <pthread.h>
67 # ifdef CAN_CALL_ATFORK
68 #   include <unistd.h>
69 # endif
70
71 #elif !defined(MSWINCE)
72 # include <process.h>  /* For _beginthreadex, _endthreadex */
73 # include <errno.h> /* for errno, EAGAIN */
74
75 #endif /* !GC_PTHREADS && !MSWINCE */
76
77 /* DllMain-based thread registration is currently incompatible  */
78 /* with thread-local allocation, pthreads and WinCE.            */
79 #if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) && !defined(NO_CRT) \
80         && !defined(GC_NO_THREADS_DISCOVERY) && !defined(MSWINCE) \
81         && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
82
83   /* This code operates in two distinct modes, depending on     */
84   /* the setting of GC_win32_dll_threads.                       */
85   /* If GC_win32_dll_threads is set, all threads in the process */
86   /* are implicitly registered with the GC by DllMain.          */
87   /* No explicit registration is required, and attempts at      */
88   /* explicit registration are ignored.  This mode is           */
89   /* very different from the Posix operation of the collector.  */
90   /* In this mode access to the thread table is lock-free.      */
91   /* Hence there is a static limit on the number of threads.    */
92
93 # ifdef GC_DISCOVER_TASK_THREADS
94     /* GC_DISCOVER_TASK_THREADS should be used if DllMain-based */
95     /* thread registration is required but it is impossible to  */
96     /* call GC_use_threads_discovery before other GC routines.  */
97 #   define GC_win32_dll_threads TRUE
98 # else
99     STATIC GC_bool GC_win32_dll_threads = FALSE;
100     /* GC_win32_dll_threads must be set (if needed) at the      */
101     /* application initialization time, i.e. before any         */
102     /* collector or thread calls.  We make it a "dynamic"       */
103     /* option only to avoid multiple library versions.          */
104 # endif
105
106 #else
107   /* If GC_win32_dll_threads is FALSE (or the collector is      */
108   /* built without GC_DLL defined), things operate in a way     */
109   /* that is very similar to Posix platforms, and new threads   */
110   /* must be registered with the collector, e.g. by using       */
111   /* preprocessor-based interception of the thread primitives.  */
112   /* In this case, we use a real data structure for the thread  */
113   /* table.  Note that there is no equivalent of linker-based   */
114   /* call interception, since we don't have ELF-like            */
115   /* facilities.  The Windows analog appears to be "API         */
116   /* hooking", which really seems to be a standard way to       */
117   /* do minor binary rewriting (?).  I'd prefer not to have     */
118   /* the basic collector rely on such facilities, but an        */
119   /* optional package that intercepts thread calls this way     */
120   /* would probably be nice.                                    */
121 # ifndef GC_NO_THREADS_DISCOVERY
122 #   define GC_NO_THREADS_DISCOVERY
123 # endif
124 # define GC_win32_dll_threads FALSE
125 # undef MAX_THREADS
126 # define MAX_THREADS 1 /* dll_thread_table[] is always empty.   */
127 #endif /* GC_NO_THREADS_DISCOVERY */
128
129 /* We have two versions of the thread table.  Which one */
130 /* we us depends on whether or not GC_win32_dll_threads */
131 /* is set.  Note that before initialization, we don't   */
132 /* add any entries to either table, even if DllMain is  */
133 /* called.  The main thread will be added on            */
134 /* initialization.                                      */
135
136 /* The type of the first argument to InterlockedExchange.       */
137 /* Documented to be LONG volatile *, but at least gcc likes     */
138 /* this better.                                                 */
139 typedef LONG * IE_t;
140
141 STATIC GC_bool GC_thr_initialized = FALSE;
142
143 #ifndef GC_ALWAYS_MULTITHREADED
144   GC_INNER GC_bool GC_need_to_lock = FALSE;
145 #endif
146
147 static GC_bool parallel_initialized = FALSE;
148
149 /* GC_use_threads_discovery() is currently incompatible with pthreads   */
150 /* and WinCE.  It might be possible to get DllMain-based thread         */
151 /* registration to work with Cygwin, but if you try it then you are on  */
152 /* your own.                                                            */
153 GC_API void GC_CALL GC_use_threads_discovery(void)
154 {
155 # ifdef GC_NO_THREADS_DISCOVERY
156     ABORT("GC DllMain-based thread registration unsupported");
157 # else
158     /* Turn on GC_win32_dll_threads. */
159     GC_ASSERT(!parallel_initialized);
160     /* Note that GC_use_threads_discovery is expected to be called by   */
161     /* the client application (not from DllMain) at start-up.           */
162 #   ifndef GC_DISCOVER_TASK_THREADS
163       GC_win32_dll_threads = TRUE;
164 #   endif
165     GC_init_parallel();
166 # endif
167 }
168
169 #define ADDR_LIMIT ((ptr_t)GC_WORD_MAX)
170
171 struct GC_Thread_Rep {
172   union {
173 #   ifndef GC_NO_THREADS_DISCOVERY
174       volatile AO_t in_use;
175                         /* Updated without lock.                */
176                         /* We assert that unused                */
177                         /* entries have invalid ids of          */
178                         /* zero and zero stack fields.          */
179                         /* Used only with GC_win32_dll_threads. */
180       LONG long_in_use; /* The same but of the type that        */
181                         /* matches the first argument of        */
182                         /* InterlockedExchange(); volatile is   */
183                         /* omitted because the ancient version  */
184                         /* of the prototype lacks the qualifier.*/
185 #   endif
186     struct GC_Thread_Rep * next;
187                         /* Hash table link without              */
188                         /* GC_win32_dll_threads.                */
189                         /* More recently allocated threads      */
190                         /* with a given pthread id come         */
191                         /* first.  (All but the first are       */
192                         /* guaranteed to be dead, but we may    */
193                         /* not yet have registered the join.)   */
194   } tm; /* table_management */
195   DWORD id;
196
197 # ifdef MSWINCE
198     /* According to MSDN specs for WinCE targets:                       */
199     /* - DuplicateHandle() is not applicable to thread handles; and     */
200     /* - the value returned by GetCurrentThreadId() could be used as    */
201     /* a "real" thread handle (for SuspendThread(), ResumeThread() and  */
202     /* GetThreadContext()).                                             */
203 #   define THREAD_HANDLE(t) (HANDLE)(word)(t)->id
204 # else
205     HANDLE handle;
206 #   define THREAD_HANDLE(t) (t)->handle
207 # endif
208
209   ptr_t stack_base;     /* The cold end of the stack.   */
210                         /* 0 ==> entry not valid.       */
211                         /* !in_use ==> stack_base == 0  */
212   ptr_t last_stack_min; /* Last known minimum (hottest) address */
213                         /* in stack or ADDR_LIMIT if unset      */
214 # ifdef IA64
215     ptr_t backing_store_end;
216     ptr_t backing_store_ptr;
217 # elif defined(I386)
218     ptr_t initial_stack_base;
219                         /* The cold end of the stack saved by   */
220                         /* GC_record_stack_base (never modified */
221                         /* by GC_set_stackbottom).              */
222 # endif
223
224   ptr_t thread_blocked_sp;      /* Protected by GC lock.                */
225                                 /* NULL value means thread unblocked.   */
226                                 /* If set to non-NULL, thread will      */
227                                 /* acquire GC lock before doing any     */
228                                 /* pointer manipulations.  Thus it does */
229                                 /* not need to stop this thread.        */
230
231   struct GC_traced_stack_sect_s *traced_stack_sect;
232                                 /* Points to the "stack section" data   */
233                                 /* held in stack by the innermost       */
234                                 /* GC_call_with_gc_active() of this     */
235                                 /* thread.  May be NULL.                */
236
237   unsigned short finalizer_skipped;
238   unsigned char finalizer_nested;
239                                 /* Used by GC_check_finalizer_nested()  */
240                                 /* to minimize the level of recursion   */
241                                 /* when a client finalizer allocates    */
242                                 /* memory (initially both are 0).       */
243
244   unsigned char suspended; /* really of GC_bool type */
245
246 # ifdef GC_PTHREADS
247     unsigned char flags;        /* Protected by GC lock.                */
248 #   define FINISHED 1           /* Thread has exited.                   */
249 #   define DETACHED 2           /* Thread is intended to be detached.   */
250 #   define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
251     pthread_t pthread_id;
252     void *status;  /* hold exit value until join in case it's a pointer */
253 # else
254 #   define KNOWN_FINISHED(t) 0
255 # endif
256
257 # ifdef THREAD_LOCAL_ALLOC
258     struct thread_local_freelists tlfs;
259 # endif
260 };
261
262 typedef struct GC_Thread_Rep * GC_thread;
263 typedef volatile struct GC_Thread_Rep * GC_vthread;
264
265 #ifndef GC_NO_THREADS_DISCOVERY
266   STATIC DWORD GC_main_thread = 0;
267
268   /* We track thread attachments while the world is supposed to be      */
269   /* stopped.  Unfortunately, we cannot stop them from starting, since  */
270   /* blocking in DllMain seems to cause the world to deadlock.  Thus,   */
271   /* we have to recover if we notice this in the middle of marking.     */
272   STATIC volatile AO_t GC_attached_thread = FALSE;
273
274   /* We assumed that volatile ==> memory ordering, at least among       */
275   /* volatiles.  This code should consistently use atomic_ops.          */
276   STATIC volatile GC_bool GC_please_stop = FALSE;
277 #elif defined(GC_ASSERTIONS)
278   STATIC GC_bool GC_please_stop = FALSE;
279 #endif /* GC_NO_THREADS_DISCOVERY && GC_ASSERTIONS */
280
281 #if defined(WRAP_MARK_SOME) && !defined(GC_PTHREADS)
282   /* Return TRUE if an thread was attached since we last asked or */
283   /* since GC_attached_thread was explicitly reset.               */
284   GC_INNER GC_bool GC_started_thread_while_stopped(void)
285   {
286 #   ifndef GC_NO_THREADS_DISCOVERY
287       if (GC_win32_dll_threads) {
288 #       ifdef AO_HAVE_compare_and_swap_release
289           if (AO_compare_and_swap_release(&GC_attached_thread, TRUE,
290                                           FALSE /* stored */))
291             return TRUE;
292 #       else
293           AO_nop_full(); /* Prior heap reads need to complete earlier. */
294           if (AO_load(&GC_attached_thread)) {
295             AO_store(&GC_attached_thread, FALSE);
296             return TRUE;
297           }
298 #       endif
299       }
300 #   endif
301     return FALSE;
302   }
303 #endif /* WRAP_MARK_SOME */
304
305 /* Thread table used if GC_win32_dll_threads is set.    */
306 /* This is a fixed size array.                          */
307 /* Since we use runtime conditionals, both versions     */
308 /* are always defined.                                  */
309 # ifndef MAX_THREADS
310 #   define MAX_THREADS 512
311 # endif
312
313 /* Things may get quite slow for large numbers of threads,      */
314 /* since we look them up with sequential search.                */
315 volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
316
317 STATIC volatile LONG GC_max_thread_index = 0;
318                         /* Largest index in dll_thread_table    */
319                         /* that was ever used.                  */
320
321 /* And now the version used if GC_win32_dll_threads is not set. */
322 /* This is a chained hash table, with much of the code borrowed */
323 /* from the Posix implementation.                               */
324 #ifndef THREAD_TABLE_SZ
325 # define THREAD_TABLE_SZ 256    /* Power of 2 (for speed). */
326 #endif
327 #define THREAD_TABLE_INDEX(id) /* id is of DWORD type */ \
328                 (int)((((id) >> 8) ^ (id)) % THREAD_TABLE_SZ)
329 STATIC GC_thread GC_threads[THREAD_TABLE_SZ];
330
331 /* It may not be safe to allocate when we register the first thread.    */
332 /* Thus we allocated one statically.  It does not contain any field we  */
333 /* need to push ("next" and "status" fields are unused).                */
334 static struct GC_Thread_Rep first_thread;
335 static GC_bool first_thread_used = FALSE;
336
337 /* Add a thread to GC_threads.  We assume it wasn't already there.      */
338 /* Caller holds allocation lock.                                        */
339 /* Unlike the pthreads version, the id field is set by the caller.      */
340 STATIC GC_thread GC_new_thread(DWORD id)
341 {
342   int hv = THREAD_TABLE_INDEX(id);
343   GC_thread result;
344
345 # ifdef DEBUG_THREADS
346     GC_log_printf("Creating thread 0x%lx\n", (long)id);
347     if (GC_threads[hv] != NULL)
348       GC_log_printf("Hash collision at GC_threads[%d]\n", hv);
349 # endif
350   GC_ASSERT(I_HOLD_LOCK());
351   if (!EXPECT(first_thread_used, TRUE)) {
352     result = &first_thread;
353     first_thread_used = TRUE;
354     GC_ASSERT(NULL == GC_threads[hv]);
355   } else {
356     GC_ASSERT(!GC_win32_dll_threads);
357     result = (struct GC_Thread_Rep *)
358                 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
359     if (result == 0) return(0);
360   }
361   /* result -> id = id; Done by caller.       */
362   result -> tm.next = GC_threads[hv];
363   GC_threads[hv] = result;
364 # ifdef GC_PTHREADS
365     GC_ASSERT(result -> flags == 0);
366 # endif
367   GC_ASSERT(result -> thread_blocked_sp == NULL);
368   if (EXPECT(result != &first_thread, TRUE))
369     GC_dirty(result);
370   return(result);
371 }
372
373 GC_INNER GC_bool GC_in_thread_creation = FALSE;
374                                 /* Protected by allocation lock. */
375
376 GC_INLINE void GC_record_stack_base(GC_vthread me,
377                                     const struct GC_stack_base *sb)
378 {
379   me -> stack_base = (ptr_t)sb->mem_base;
380 # ifdef IA64
381     me -> backing_store_end = (ptr_t)sb->reg_base;
382 # elif defined(I386)
383     me -> initial_stack_base = (ptr_t)sb->mem_base;
384 # endif
385   if (me -> stack_base == NULL)
386     ABORT("Bad stack base in GC_register_my_thread");
387 }
388
389 /* This may be called from DllMain, and hence operates under unusual    */
390 /* constraints.  In particular, it must be lock-free if                 */
391 /* GC_win32_dll_threads is set.  Always called from the thread being    */
392 /* added.  If GC_win32_dll_threads is not set, we already hold the      */
393 /* allocation lock except possibly during single-threaded startup code. */
394 STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
395                                              DWORD thread_id)
396 {
397   GC_vthread me;
398
399   /* The following should be a no-op according to the win32     */
400   /* documentation.  There is empirical evidence that it        */
401   /* isn't.             - HB                                    */
402 # if defined(MPROTECT_VDB) && !defined(CYGWIN32)
403     if (GC_auto_incremental
404 #       ifdef GWW_VDB
405           && !GC_gww_dirty_init()
406 #       endif
407         )
408       GC_set_write_fault_handler();
409 # endif
410
411 # ifndef GC_NO_THREADS_DISCOVERY
412     if (GC_win32_dll_threads) {
413       int i;
414       /* It appears to be unsafe to acquire a lock here, since this     */
415       /* code is apparently not preemptible on some systems.            */
416       /* (This is based on complaints, not on Microsoft's official      */
417       /* documentation, which says this should perform "only simple     */
418       /* initialization tasks".)                                        */
419       /* Hence we make do with nonblocking synchronization.             */
420       /* It has been claimed that DllMain is really only executed with  */
421       /* a particular system lock held, and thus careful use of locking */
422       /* around code that doesn't call back into the system libraries   */
423       /* might be OK.  But this hasn't been tested across all win32     */
424       /* variants.                                                      */
425       for (i = 0;
426            InterlockedExchange(&dll_thread_table[i].tm.long_in_use, 1) != 0;
427            i++) {
428         /* Compare-and-swap would make this cleaner, but that's not     */
429         /* supported before Windows 98 and NT 4.0.  In Windows 2000,    */
430         /* InterlockedExchange is supposed to be replaced by            */
431         /* InterlockedExchangePointer, but that's not really what I     */
432         /* want here.                                                   */
433         /* FIXME: We should eventually declare Win95 dead and use AO_   */
434         /* primitives here.                                             */
435         if (i == MAX_THREADS - 1)
436           ABORT("Too many threads");
437       }
438       /* Update GC_max_thread_index if necessary.  The following is     */
439       /* safe, and unlike CompareExchange-based solutions seems to work */
440       /* on all Windows95 and later platforms.                          */
441       /* Unfortunately, GC_max_thread_index may be temporarily out of   */
442       /* bounds, so readers have to compensate.                         */
443       while (i > GC_max_thread_index) {
444         InterlockedIncrement((IE_t)&GC_max_thread_index);
445       }
446       if (GC_max_thread_index >= MAX_THREADS) {
447         /* We overshot due to simultaneous increments.  */
448         /* Setting it to MAX_THREADS-1 is always safe.  */
449         GC_max_thread_index = MAX_THREADS - 1;
450       }
451       me = dll_thread_table + i;
452     } else
453 # endif
454   /* else */ /* Not using DllMain */ {
455     GC_ASSERT(I_HOLD_LOCK());
456     GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
457     me = GC_new_thread(thread_id);
458     GC_in_thread_creation = FALSE;
459     if (me == 0)
460       ABORT("Failed to allocate memory for thread registering");
461   }
462 # ifdef GC_PTHREADS
463     /* me can be NULL -> segfault */
464     me -> pthread_id = pthread_self();
465 # endif
466 # ifndef MSWINCE
467     /* GetCurrentThread() returns a pseudohandle (a const value).       */
468     if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
469                         GetCurrentProcess(),
470                         (HANDLE*)&(me -> handle),
471                         0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
472                         DUPLICATE_SAME_ACCESS)) {
473         ABORT_ARG1("DuplicateHandle failed",
474                    ": errcode= 0x%X", (unsigned)GetLastError());
475     }
476 # endif
477   me -> last_stack_min = ADDR_LIMIT;
478   GC_record_stack_base(me, sb);
479   /* Up until this point, GC_push_all_stacks considers this thread      */
480   /* invalid.                                                           */
481   /* Up until this point, this entry is viewed as reserved but invalid  */
482   /* by GC_delete_thread.                                               */
483   me -> id = thread_id;
484 # if defined(THREAD_LOCAL_ALLOC)
485     GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
486 # endif
487 # ifndef GC_NO_THREADS_DISCOVERY
488     if (GC_win32_dll_threads) {
489       if (GC_please_stop) {
490         AO_store(&GC_attached_thread, TRUE);
491         AO_nop_full(); /* Later updates must become visible after this. */
492       }
493       /* We'd like to wait here, but can't, since waiting in DllMain    */
494       /* provokes deadlocks.                                            */
495       /* Thus we force marking to be restarted instead.                 */
496     } else
497 # endif
498   /* else */ {
499     GC_ASSERT(!GC_please_stop);
500         /* Otherwise both we and the thread stopping code would be      */
501         /* holding the allocation lock.                                 */
502   }
503   return (GC_thread)(me);
504 }
505
506 /*
507  * GC_max_thread_index may temporarily be larger than MAX_THREADS.
508  * To avoid subscript errors, we check on access.
509  */
510 GC_INLINE LONG GC_get_max_thread_index(void)
511 {
512   LONG my_max = GC_max_thread_index;
513   if (my_max >= MAX_THREADS) return MAX_THREADS - 1;
514   return my_max;
515 }
516
517 /* Return the GC_thread corresponding to a thread id.  May be called    */
518 /* without a lock, but should be called in contexts in which the        */
519 /* requested thread cannot be asynchronously deleted, e.g. from the     */
520 /* thread itself.                                                       */
521 /* This version assumes that either GC_win32_dll_threads is set, or     */
522 /* we hold the allocator lock.                                          */
523 /* Also used (for assertion checking only) from thread_local_alloc.c.   */
524 STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
525 {
526 # ifndef GC_NO_THREADS_DISCOVERY
527     if (GC_win32_dll_threads) {
528       int i;
529       LONG my_max = GC_get_max_thread_index();
530       for (i = 0; i <= my_max &&
531                   (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
532                   || dll_thread_table[i].id != thread_id);
533            /* Must still be in_use, since nobody else can store our     */
534            /* thread_id.                                                */
535            i++) {
536         /* empty */
537       }
538       return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
539     } else
540 # endif
541   /* else */ {
542     GC_thread p = GC_threads[THREAD_TABLE_INDEX(thread_id)];
543
544     GC_ASSERT(I_HOLD_LOCK());
545     while (p != 0 && p -> id != thread_id) p = p -> tm.next;
546     return(p);
547   }
548 }
549
550 #ifdef LINT2
551 # define CHECK_LOOKUP_MY_THREAD(me) \
552         if (!(me)) ABORT("GC_lookup_thread_inner(GetCurrentThreadId) failed")
553 #else
554 # define CHECK_LOOKUP_MY_THREAD(me) /* empty */
555 #endif
556
557 /* Called by GC_finalize() (in case of an allocation failure observed). */
558 /* GC_reset_finalizer_nested() is the same as in pthread_support.c.     */
559 GC_INNER void GC_reset_finalizer_nested(void)
560 {
561   GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
562   CHECK_LOOKUP_MY_THREAD(me);
563   me->finalizer_nested = 0;
564 }
565
566 /* Checks and updates the thread-local level of finalizers recursion.   */
567 /* Returns NULL if GC_invoke_finalizers() should not be called by the   */
568 /* collector (to minimize the risk of a deep finalizers recursion),     */
569 /* otherwise returns a pointer to the thread-local finalizer_nested.    */
570 /* Called by GC_notify_or_invoke_finalizers() only (the lock is held).  */
571 /* GC_check_finalizer_nested() is the same as in pthread_support.c.     */
572 GC_INNER unsigned char *GC_check_finalizer_nested(void)
573 {
574   GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
575   unsigned nesting_level;
576   CHECK_LOOKUP_MY_THREAD(me);
577   nesting_level = me->finalizer_nested;
578   if (nesting_level) {
579     /* We are inside another GC_invoke_finalizers().            */
580     /* Skip some implicitly-called GC_invoke_finalizers()       */
581     /* depending on the nesting (recursion) level.              */
582     if (++me->finalizer_skipped < (1U << nesting_level)) return NULL;
583     me->finalizer_skipped = 0;
584   }
585   me->finalizer_nested = (unsigned char)(nesting_level + 1);
586   return &me->finalizer_nested;
587 }
588
589 #if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
590   /* This is called from thread-local GC_malloc(). */
591   GC_bool GC_is_thread_tsd_valid(void *tsd)
592   {
593     GC_thread me;
594     DCL_LOCK_STATE;
595
596     LOCK();
597     me = GC_lookup_thread_inner(GetCurrentThreadId());
598     UNLOCK();
599     return (word)tsd >= (word)(&me->tlfs)
600             && (word)tsd < (word)(&me->tlfs) + sizeof(me->tlfs);
601   }
602 #endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */
603
604 GC_API int GC_CALL GC_thread_is_registered(void)
605 {
606     DWORD thread_id = GetCurrentThreadId();
607     GC_thread me;
608     DCL_LOCK_STATE;
609
610     LOCK();
611     me = GC_lookup_thread_inner(thread_id);
612     UNLOCK();
613     return me != NULL;
614 }
615
616 GC_API void GC_CALL GC_register_altstack(void *stack GC_ATTR_UNUSED,
617                                          GC_word stack_size GC_ATTR_UNUSED,
618                                          void *altstack GC_ATTR_UNUSED,
619                                          GC_word altstack_size GC_ATTR_UNUSED)
620 {
621   /* TODO: Implement */
622 }
623
624 /* Make sure thread descriptor t is not protected by the VDB            */
625 /* implementation.                                                      */
626 /* Used to prevent write faults when the world is (partially) stopped,  */
627 /* since it may have been stopped with a system lock held, and that     */
628 /* lock may be required for fault handling.                             */
629 #if defined(MPROTECT_VDB)
630 # define UNPROTECT_THREAD(t) \
631     if (!GC_win32_dll_threads && GC_auto_incremental \
632         && t != &first_thread) { \
633       GC_ASSERT(SMALL_OBJ(GC_size(t))); \
634       GC_remove_protection(HBLKPTR(t), 1, FALSE); \
635     } else (void)0
636 #else
637 # define UNPROTECT_THREAD(t) (void)0
638 #endif
639
640 #ifdef CYGWIN32
641 # define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
642 #elif defined(GC_WIN32_PTHREADS) || defined(GC_PTHREADS_PARAMARK)
643 # include <pthread.h> /* to check for winpthreads */
644 # if defined(__WINPTHREADS_VERSION_MAJOR)
645 #   define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
646 # else
647 #   define GC_PTHREAD_PTRVAL(pthread_id) pthread_id.p
648 # endif
649 #endif
650
651 /* If a thread has been joined, but we have not yet             */
652 /* been notified, then there may be more than one thread        */
653 /* in the table with the same win32 id.                         */
654 /* This is OK, but we need a way to delete a specific one.      */
655 /* Assumes we hold the allocation lock unless                   */
656 /* GC_win32_dll_threads is set.  Does not actually free         */
657 /* GC_thread entry (only unlinks it).                           */
658 /* If GC_win32_dll_threads is set it should be called from the  */
659 /* thread being deleted.                                        */
660 STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
661 {
662 # ifndef MSWINCE
663     CloseHandle(t->handle);
664 # endif
665 # ifndef GC_NO_THREADS_DISCOVERY
666     if (GC_win32_dll_threads) {
667       /* This is intended to be lock-free.                              */
668       /* It is either called synchronously from the thread being        */
669       /* deleted, or by the joining thread.                             */
670       /* In this branch asynchronous changes to (*t) are possible.      */
671       /* It's not allowed to call GC_printf (and the friends) here,     */
672       /* see GC_stop_world() for the information.                       */
673       t -> stack_base = 0;
674       t -> id = 0;
675       AO_store_release(&t->tm.in_use, FALSE);
676     } else
677 # endif
678   /* else */ {
679     DWORD id = ((GC_thread)t) -> id;
680                 /* Cast away volatile qualifier, since we have lock.    */
681     int hv = THREAD_TABLE_INDEX(id);
682     GC_thread p = GC_threads[hv];
683     GC_thread prev = NULL;
684
685     GC_ASSERT(I_HOLD_LOCK());
686     while (p != (GC_thread)t) {
687       prev = p;
688       p = p -> tm.next;
689     }
690     if (prev == 0) {
691       GC_threads[hv] = p -> tm.next;
692     } else {
693       GC_ASSERT(prev != &first_thread);
694       prev -> tm.next = p -> tm.next;
695       GC_dirty(prev);
696     }
697   }
698 }
699
700 /* Delete a thread from GC_threads.  We assume it is there.     */
701 /* (The code intentionally traps if it wasn't.)  Assumes we     */
702 /* hold the allocation lock unless GC_win32_dll_threads is set. */
703 /* If GC_win32_dll_threads is set then it should be called from */
704 /* the thread being deleted.  It is also safe to delete the     */
705 /* main thread (unless GC_win32_dll_threads).                   */
706 STATIC void GC_delete_thread(DWORD id)
707 {
708   if (GC_win32_dll_threads) {
709     GC_vthread t = GC_lookup_thread_inner(id);
710
711     if (0 == t) {
712       WARN("Removing nonexistent thread, id = %" WARN_PRIdPTR "\n", id);
713     } else {
714       GC_delete_gc_thread_no_free(t);
715     }
716   } else {
717     int hv = THREAD_TABLE_INDEX(id);
718     GC_thread p = GC_threads[hv];
719     GC_thread prev = NULL;
720
721     GC_ASSERT(I_HOLD_LOCK());
722     while (p -> id != id) {
723       prev = p;
724       p = p -> tm.next;
725     }
726 #   ifndef MSWINCE
727       CloseHandle(p->handle);
728 #   endif
729     if (prev == 0) {
730       GC_threads[hv] = p -> tm.next;
731     } else {
732       GC_ASSERT(prev != &first_thread);
733       prev -> tm.next = p -> tm.next;
734       GC_dirty(prev);
735     }
736     if (EXPECT(p != &first_thread, TRUE)) {
737       GC_INTERNAL_FREE(p);
738     }
739   }
740 }
741
742 GC_API void GC_CALL GC_allow_register_threads(void)
743 {
744   /* Check GC is initialized and the current thread is registered. */
745   GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId()) != 0);
746 # if !defined(GC_ALWAYS_MULTITHREADED) && !defined(PARALLEL_MARK) \
747      && !defined(GC_NO_THREADS_DISCOVERY)
748       /* GC_init() does not call GC_init_parallel() in this case.   */
749     parallel_initialized = TRUE;
750 # endif
751   set_need_to_lock();
752 }
753
754 GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
755 {
756   GC_thread me;
757   DWORD thread_id = GetCurrentThreadId();
758   DCL_LOCK_STATE;
759
760   if (GC_need_to_lock == FALSE)
761     ABORT("Threads explicit registering is not previously enabled");
762
763   /* We lock here, since we want to wait for an ongoing GC.     */
764   LOCK();
765   me = GC_lookup_thread_inner(thread_id);
766   if (me == 0) {
767 #   ifdef GC_PTHREADS
768       me = GC_register_my_thread_inner(sb, thread_id);
769 #     if defined(CPPCHECK)
770         GC_noop1(me->flags);
771 #     endif
772       me -> flags |= DETACHED;
773           /* Treat as detached, since we do not need to worry about     */
774           /* pointer results.                                           */
775 #   else
776       GC_register_my_thread_inner(sb, thread_id);
777 #   endif
778     UNLOCK();
779     return GC_SUCCESS;
780   } else
781 #   ifdef GC_PTHREADS
782       /* else */ if ((me -> flags & FINISHED) != 0) {
783         GC_record_stack_base(me, sb);
784         me -> flags &= ~FINISHED; /* but not DETACHED */
785 #       ifdef THREAD_LOCAL_ALLOC
786           GC_init_thread_local((GC_tlfs)(&me->tlfs));
787 #       endif
788         UNLOCK();
789         return GC_SUCCESS;
790       } else
791 #   endif
792   /* else */ {
793     UNLOCK();
794     return GC_DUPLICATE;
795   }
796 }
797
798 /* Similar to that in pthread_support.c.        */
799 STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
800 {
801   GC_ASSERT(I_HOLD_LOCK());
802   if (GC_incremental && GC_collection_in_progress()) {
803     word old_gc_no = GC_gc_no;
804
805     /* Make sure that no part of our stack is still on the mark stack,  */
806     /* since it's about to be unmapped.                                 */
807     do {
808       ENTER_GC();
809       GC_in_thread_creation = TRUE;
810       GC_collect_a_little_inner(1);
811       GC_in_thread_creation = FALSE;
812       EXIT_GC();
813
814       UNLOCK();
815       Sleep(0); /* yield */
816       LOCK();
817     } while (GC_incremental && GC_collection_in_progress()
818              && (wait_for_all || old_gc_no == GC_gc_no));
819   }
820 }
821
822 GC_API int GC_CALL GC_unregister_my_thread(void)
823 {
824   DCL_LOCK_STATE;
825
826 # ifdef DEBUG_THREADS
827     GC_log_printf("Unregistering thread 0x%lx\n", (long)GetCurrentThreadId());
828 # endif
829
830   if (GC_win32_dll_threads) {
831 #   if defined(THREAD_LOCAL_ALLOC)
832       /* Can't happen: see GC_use_threads_discovery(). */
833       GC_ASSERT(FALSE);
834 #   else
835       /* FIXME: Should we just ignore this? */
836       GC_delete_thread(GetCurrentThreadId());
837 #   endif
838   } else {
839 #   if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
840       GC_thread me;
841 #   endif
842     DWORD thread_id = GetCurrentThreadId();
843
844     LOCK();
845     GC_wait_for_gc_completion(FALSE);
846 #   if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
847       me = GC_lookup_thread_inner(thread_id);
848       CHECK_LOOKUP_MY_THREAD(me);
849       GC_ASSERT(!KNOWN_FINISHED(me));
850 #   endif
851 #   if defined(THREAD_LOCAL_ALLOC)
852       GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
853       GC_destroy_thread_local(&(me->tlfs));
854 #   endif
855 #   ifdef GC_PTHREADS
856       if ((me -> flags & DETACHED) == 0) {
857         me -> flags |= FINISHED;
858       } else
859 #   endif
860     /* else */ {
861       GC_delete_thread(thread_id);
862     }
863 #   if defined(THREAD_LOCAL_ALLOC)
864       /* It is required to call remove_specific defined in specific.c. */
865       GC_remove_specific(GC_thread_key);
866 #   endif
867     UNLOCK();
868   }
869   return GC_SUCCESS;
870 }
871
872 /* Wrapper for functions that are likely to block for an appreciable    */
873 /* length of time.                                                      */
874
875 /* GC_do_blocking_inner() is nearly the same as in pthread_support.c    */
876 GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
877 {
878   struct blocking_data * d = (struct blocking_data *) data;
879   DWORD thread_id = GetCurrentThreadId();
880   GC_thread me;
881 # ifdef IA64
882     ptr_t stack_ptr = GC_save_regs_in_stack();
883 # endif
884   DCL_LOCK_STATE;
885
886   LOCK();
887   me = GC_lookup_thread_inner(thread_id);
888   CHECK_LOOKUP_MY_THREAD(me);
889   GC_ASSERT(me -> thread_blocked_sp == NULL);
890 # ifdef IA64
891     me -> backing_store_ptr = stack_ptr;
892 # endif
893   me -> thread_blocked_sp = (ptr_t) &d; /* save approx. sp */
894   /* Save context here if we want to support precise stack marking */
895   UNLOCK();
896   d -> client_data = (d -> fn)(d -> client_data);
897   LOCK();   /* This will block if the world is stopped. */
898 # if defined(CPPCHECK)
899     GC_noop1((word)me->thread_blocked_sp);
900 # endif
901   me -> thread_blocked_sp = NULL;
902   UNLOCK();
903 }
904
905 /* GC_call_with_gc_active() has the opposite to GC_do_blocking()        */
906 /* functionality.  It might be called from a user function invoked by   */
907 /* GC_do_blocking() to temporarily back allow calling any GC function   */
908 /* and/or manipulating pointers to the garbage collected heap.          */
909 GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
910                                              void * client_data)
911 {
912   struct GC_traced_stack_sect_s stacksect;
913   DWORD thread_id = GetCurrentThreadId();
914   GC_thread me;
915   DCL_LOCK_STATE;
916
917   LOCK();   /* This will block if the world is stopped.         */
918   me = GC_lookup_thread_inner(thread_id);
919   CHECK_LOOKUP_MY_THREAD(me);
920   /* Adjust our stack bottom pointer (this could happen unless  */
921   /* GC_get_stack_base() was used which returned GC_SUCCESS).   */
922   GC_ASSERT(me -> stack_base != NULL);
923   if ((word)me->stack_base < (word)(&stacksect)) {
924     me -> stack_base = (ptr_t)(&stacksect);
925 #   if defined(I386)
926       me -> initial_stack_base = me -> stack_base;
927 #   endif
928   }
929
930   if (me -> thread_blocked_sp == NULL) {
931     /* We are not inside GC_do_blocking() - do nothing more.    */
932     UNLOCK();
933     client_data = fn(client_data);
934     /* Prevent treating the above as a tail call.       */
935     GC_noop1(COVERT_DATAFLOW(&stacksect));
936     return client_data; /* result */
937   }
938
939   /* Setup new "stack section". */
940   stacksect.saved_stack_ptr = me -> thread_blocked_sp;
941 # ifdef IA64
942     /* This is the same as in GC_call_with_stack_base().        */
943     stacksect.backing_store_end = GC_save_regs_in_stack();
944     /* Unnecessarily flushes register stack,    */
945     /* but that probably doesn't hurt.          */
946     stacksect.saved_backing_store_ptr = me -> backing_store_ptr;
947 # endif
948   stacksect.prev = me -> traced_stack_sect;
949   me -> thread_blocked_sp = NULL;
950   me -> traced_stack_sect = &stacksect;
951
952   UNLOCK();
953   client_data = fn(client_data);
954   GC_ASSERT(me -> thread_blocked_sp == NULL);
955   GC_ASSERT(me -> traced_stack_sect == &stacksect);
956
957   /* Restore original "stack section".  */
958   LOCK();
959 # if defined(CPPCHECK)
960     GC_noop1((word)me->traced_stack_sect);
961 # endif
962   me -> traced_stack_sect = stacksect.prev;
963 # ifdef IA64
964     me -> backing_store_ptr = stacksect.saved_backing_store_ptr;
965 # endif
966   me -> thread_blocked_sp = stacksect.saved_stack_ptr;
967   UNLOCK();
968
969   return client_data; /* result */
970 }
971
972 GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
973                                        const struct GC_stack_base *sb)
974 {
975   GC_thread t = (GC_thread)gc_thread_handle;
976
977   GC_ASSERT(sb -> mem_base != NULL);
978   if (!EXPECT(GC_is_initialized, TRUE)) {
979     GC_ASSERT(NULL == t);
980     GC_stackbottom = (char *)sb->mem_base;
981 #   ifdef IA64
982       GC_register_stackbottom = (ptr_t)sb->reg_base;
983 #   endif
984     return;
985   }
986
987   GC_ASSERT(I_HOLD_LOCK());
988   if (NULL == t) { /* current thread? */
989     t = GC_lookup_thread_inner(GetCurrentThreadId());
990     CHECK_LOOKUP_MY_THREAD(t);
991   }
992   GC_ASSERT(!KNOWN_FINISHED(t));
993   GC_ASSERT(NULL == t -> thread_blocked_sp
994             && NULL == t -> traced_stack_sect); /* for now */
995   t -> stack_base = (ptr_t)sb->mem_base;
996   t -> last_stack_min = ADDR_LIMIT; /* reset the known minimum */
997 # ifdef IA64
998     t -> backing_store_end = (ptr_t)sb->reg_base;
999 # endif
1000 }
1001
1002 GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
1003 {
1004   DWORD thread_id = GetCurrentThreadId();
1005   GC_thread me;
1006   DCL_LOCK_STATE;
1007
1008   LOCK();
1009   me = GC_lookup_thread_inner(thread_id);
1010   CHECK_LOOKUP_MY_THREAD(me); /* the thread is assumed to be registered */
1011   sb -> mem_base = me -> stack_base;
1012 # ifdef IA64
1013     sb -> reg_base = me -> backing_store_end;
1014 # endif
1015   UNLOCK();
1016   return (void *)me; /* gc_thread_handle */
1017 }
1018
1019 #ifdef GC_PTHREADS
1020
1021   /* A quick-and-dirty cache of the mapping between pthread_t   */
1022   /* and win32 thread id.                                       */
1023 # define PTHREAD_MAP_SIZE 512
1024   DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE] = {0};
1025 # define PTHREAD_MAP_INDEX(pthread_id) \
1026                 ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
1027         /* It appears pthread_t is really a pointer type ... */
1028 # define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
1029       (void)(GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)] = (win32_id))
1030 # define GET_PTHREAD_MAP_CACHE(pthread_id) \
1031           GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)]
1032
1033   /* Return a GC_thread corresponding to a given pthread_t.     */
1034   /* Returns 0 if it's not there.                               */
1035   /* We assume that this is only called for pthread ids that    */
1036   /* have not yet terminated or are still joinable, and         */
1037   /* cannot be concurrently terminated.                         */
1038   /* Assumes we do NOT hold the allocation lock.                */
1039   STATIC GC_thread GC_lookup_pthread(pthread_t id)
1040   {
1041 #   ifndef GC_NO_THREADS_DISCOVERY
1042       if (GC_win32_dll_threads) {
1043         int i;
1044         LONG my_max = GC_get_max_thread_index();
1045
1046         for (i = 0; i <= my_max &&
1047                     (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
1048                     || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
1049                     /* Must still be in_use, since nobody else can      */
1050                     /* store our thread_id.                             */
1051              i++) {
1052           /* empty */
1053         }
1054         return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
1055       } else
1056 #   endif
1057     /* else */ {
1058       /* We first try the cache.  If that fails, we use a very slow     */
1059       /* approach.                                                      */
1060       DWORD win32_id = GET_PTHREAD_MAP_CACHE(id);
1061       int hv_guess = THREAD_TABLE_INDEX(win32_id);
1062       int hv;
1063       GC_thread p;
1064       DCL_LOCK_STATE;
1065
1066       LOCK();
1067       for (p = GC_threads[hv_guess]; 0 != p; p = p -> tm.next) {
1068         if (THREAD_EQUAL(p -> pthread_id, id))
1069           goto foundit;
1070       }
1071       for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
1072         for (p = GC_threads[hv]; 0 != p; p = p -> tm.next) {
1073           if (THREAD_EQUAL(p -> pthread_id, id))
1074             goto foundit;
1075         }
1076       }
1077       p = 0;
1078      foundit:
1079       UNLOCK();
1080       return p;
1081     }
1082   }
1083
1084 #endif /* GC_PTHREADS */
1085
1086 #ifdef CAN_HANDLE_FORK
1087     /* Similar to that in pthread_support.c but also rehashes the table */
1088     /* since hash map key (thread_id) differs from that in the parent.  */
1089     STATIC void GC_remove_all_threads_but_me(void)
1090     {
1091       int hv;
1092       GC_thread me = NULL;
1093       DWORD thread_id;
1094       pthread_t pthread_id = pthread_self(); /* same as in parent */
1095
1096       GC_ASSERT(!GC_win32_dll_threads);
1097       for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
1098         GC_thread p, next;
1099
1100         for (p = GC_threads[hv]; 0 != p; p = next) {
1101           next = p -> tm.next;
1102           if (THREAD_EQUAL(p -> pthread_id, pthread_id)
1103               && me == NULL) { /* ignore dead threads with the same id */
1104             me = p;
1105             p -> tm.next = 0;
1106           } else {
1107 #           ifdef THREAD_LOCAL_ALLOC
1108               if ((p -> flags & FINISHED) == 0) {
1109                 /* Cannot call GC_destroy_thread_local here (see the    */
1110                 /* corresponding comment in pthread_support.c).         */
1111                 GC_remove_specific_after_fork(GC_thread_key, p -> pthread_id);
1112               }
1113 #           endif
1114             if (&first_thread != p)
1115               GC_INTERNAL_FREE(p);
1116           }
1117         }
1118         GC_threads[hv] = NULL;
1119       }
1120
1121       /* Put "me" back to GC_threads.   */
1122       GC_ASSERT(me != NULL);
1123       thread_id = GetCurrentThreadId(); /* differs from that in parent */
1124       GC_threads[THREAD_TABLE_INDEX(thread_id)] = me;
1125
1126       /* Update Win32 thread Id and handle.     */
1127       me -> id = thread_id;
1128 #     ifndef MSWINCE
1129         if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
1130                         GetCurrentProcess(), (HANDLE *)&me->handle,
1131                         0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
1132                         DUPLICATE_SAME_ACCESS))
1133           ABORT("DuplicateHandle failed");
1134 #     endif
1135
1136 #     if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
1137         /* For Cygwin, we need to re-assign thread-local pointer to     */
1138         /* 'tlfs' (it is OK to call GC_destroy_thread_local and         */
1139         /* GC_free_internal before this action).                        */
1140         if (GC_setspecific(GC_thread_key, &me->tlfs) != 0)
1141           ABORT("GC_setspecific failed (in child)");
1142 #     endif
1143     }
1144
1145     static void fork_prepare_proc(void)
1146     {
1147       LOCK();
1148 #     ifdef PARALLEL_MARK
1149         if (GC_parallel)
1150           GC_wait_for_reclaim();
1151 #     endif
1152       GC_wait_for_gc_completion(TRUE);
1153 #     ifdef PARALLEL_MARK
1154         if (GC_parallel)
1155           GC_acquire_mark_lock();
1156 #     endif
1157     }
1158
1159     static void fork_parent_proc(void)
1160     {
1161 #     ifdef PARALLEL_MARK
1162         if (GC_parallel)
1163           GC_release_mark_lock();
1164 #     endif
1165       UNLOCK();
1166     }
1167
1168     static void fork_child_proc(void)
1169     {
1170 #     ifdef PARALLEL_MARK
1171         if (GC_parallel) {
1172           GC_release_mark_lock();
1173           GC_parallel = FALSE; /* or GC_markers_m1 = 0 */
1174                 /* Turn off parallel marking in the child, since we are */
1175                 /* probably just going to exec, and we would have to    */
1176                 /* restart mark threads.                                */
1177         }
1178 #     endif
1179       GC_remove_all_threads_but_me();
1180       UNLOCK();
1181     }
1182
1183   /* Routines for fork handling by client (no-op if pthread_atfork works). */
1184   GC_API void GC_CALL GC_atfork_prepare(void)
1185   {
1186     if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
1187     if (GC_handle_fork <= 0)
1188       fork_prepare_proc();
1189   }
1190
1191   GC_API void GC_CALL GC_atfork_parent(void)
1192   {
1193     if (GC_handle_fork <= 0)
1194       fork_parent_proc();
1195   }
1196
1197   GC_API void GC_CALL GC_atfork_child(void)
1198   {
1199     if (GC_handle_fork <= 0)
1200       fork_child_proc();
1201   }
1202 #endif /* CAN_HANDLE_FORK */
1203
1204 void GC_push_thread_structures(void)
1205 {
1206   GC_ASSERT(I_HOLD_LOCK());
1207 # ifndef GC_NO_THREADS_DISCOVERY
1208     if (GC_win32_dll_threads) {
1209       /* Unlike the other threads implementations, the thread table     */
1210       /* here contains no pointers to the collectible heap (note also   */
1211       /* that GC_PTHREADS is incompatible with DllMain-based thread     */
1212       /* registration).  Thus we have no private structures we need     */
1213       /* to preserve.                                                   */
1214     } else
1215 # endif
1216   /* else */ {
1217     GC_PUSH_ALL_SYM(GC_threads);
1218   }
1219 # if defined(THREAD_LOCAL_ALLOC)
1220     GC_PUSH_ALL_SYM(GC_thread_key);
1221     /* Just in case we ever use our own TLS implementation.     */
1222 # endif
1223 }
1224
1225 /* Suspend the given thread, if it's still active.      */
1226 STATIC void GC_suspend(GC_thread t)
1227 {
1228 # ifndef MSWINCE
1229     /* Apparently the Windows 95 GetOpenFileName call creates           */
1230     /* a thread that does not properly get cleaned up, and              */
1231     /* SuspendThread on its descriptor may provoke a crash.             */
1232     /* This reduces the probability of that event, though it still      */
1233     /* appears there's a race here.                                     */
1234     DWORD exitCode;
1235 # endif
1236   UNPROTECT_THREAD(t);
1237 # ifndef MSWINCE
1238     if (GetExitCodeThread(t -> handle, &exitCode) &&
1239         exitCode != STILL_ACTIVE) {
1240 #     ifdef GC_PTHREADS
1241         t -> stack_base = 0; /* prevent stack from being pushed */
1242 #     else
1243         /* this breaks pthread_join on Cygwin, which is guaranteed to  */
1244         /* only see user pthreads                                      */
1245         GC_ASSERT(GC_win32_dll_threads);
1246         GC_delete_gc_thread_no_free(t);
1247 #     endif
1248       return;
1249     }
1250 # endif
1251   GC_acquire_dirty_lock();
1252 # ifdef MSWINCE
1253     /* SuspendThread() will fail if thread is running kernel code.      */
1254     while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1)
1255       Sleep(10); /* in millis */
1256 # else
1257     if (SuspendThread(t -> handle) == (DWORD)-1)
1258       ABORT("SuspendThread failed");
1259 # endif /* !MSWINCE */
1260   t -> suspended = (unsigned char)TRUE;
1261   GC_release_dirty_lock();
1262   if (GC_on_thread_event)
1263     GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, THREAD_HANDLE(t));
1264 }
1265
1266 #if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
1267   GC_INNER GC_bool GC_write_disabled = FALSE;
1268                 /* TRUE only if GC_stop_world() acquired GC_write_cs.   */
1269 #endif
1270
1271 GC_INNER void GC_stop_world(void)
1272 {
1273   DWORD thread_id = GetCurrentThreadId();
1274
1275   if (!GC_thr_initialized)
1276     ABORT("GC_stop_world() called before GC_thr_init()");
1277   GC_ASSERT(I_HOLD_LOCK());
1278
1279   /* This code is the same as in pthread_stop_world.c */
1280 # ifdef PARALLEL_MARK
1281     if (GC_parallel) {
1282       GC_acquire_mark_lock();
1283       GC_ASSERT(GC_fl_builder_count == 0);
1284       /* We should have previously waited for it to become zero. */
1285     }
1286 # endif /* PARALLEL_MARK */
1287
1288 # if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
1289     GC_please_stop = TRUE;
1290 # endif
1291 # ifndef CYGWIN32
1292 #   ifndef MSWIN_XBOX1
1293       GC_ASSERT(!GC_write_disabled);
1294 #   endif
1295     EnterCriticalSection(&GC_write_cs);
1296 # endif
1297 # if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
1298     /* It's not allowed to call GC_printf() (and friends) here down to  */
1299     /* LeaveCriticalSection (same applies recursively to GC_suspend,    */
1300     /* GC_delete_gc_thread_no_free, GC_get_max_thread_index, GC_size    */
1301     /* and GC_remove_protection).                                       */
1302     GC_write_disabled = TRUE;
1303 # endif
1304 # ifndef GC_NO_THREADS_DISCOVERY
1305     if (GC_win32_dll_threads) {
1306       int i;
1307       int my_max;
1308       /* Any threads being created during this loop will end up setting */
1309       /* GC_attached_thread when they start.  This will force marking   */
1310       /* to restart.  This is not ideal, but hopefully correct.         */
1311       AO_store(&GC_attached_thread, FALSE);
1312       my_max = (int)GC_get_max_thread_index();
1313       for (i = 0; i <= my_max; i++) {
1314         GC_vthread t = dll_thread_table + i;
1315         if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
1316             && t -> id != thread_id) {
1317           GC_suspend((GC_thread)t);
1318         }
1319       }
1320     } else
1321 # endif
1322   /* else */ {
1323     GC_thread t;
1324     int i;
1325
1326     for (i = 0; i < THREAD_TABLE_SZ; i++) {
1327       for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1328         if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
1329             && !KNOWN_FINISHED(t) && t -> id != thread_id) {
1330           GC_suspend(t);
1331         }
1332       }
1333     }
1334   }
1335 # if defined(GC_ASSERTIONS) && (defined(MSWIN32) || defined(MSWINCE))
1336     GC_write_disabled = FALSE;
1337 # endif
1338 # ifndef CYGWIN32
1339     LeaveCriticalSection(&GC_write_cs);
1340 # endif
1341 # ifdef PARALLEL_MARK
1342     if (GC_parallel)
1343       GC_release_mark_lock();
1344 # endif
1345 }
1346
1347 GC_INNER void GC_start_world(void)
1348 {
1349 # ifdef GC_ASSERTIONS
1350     DWORD thread_id = GetCurrentThreadId();
1351 # endif
1352
1353   GC_ASSERT(I_HOLD_LOCK());
1354   if (GC_win32_dll_threads) {
1355     LONG my_max = GC_get_max_thread_index();
1356     int i;
1357
1358     for (i = 0; i <= my_max; i++) {
1359       GC_thread t = (GC_thread)(dll_thread_table + i);
1360       if (t -> suspended) {
1361         GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
1362         if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
1363           ABORT("ResumeThread failed");
1364         t -> suspended = FALSE;
1365         if (GC_on_thread_event)
1366           GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
1367       }
1368     }
1369   } else {
1370     GC_thread t;
1371     int i;
1372
1373     for (i = 0; i < THREAD_TABLE_SZ; i++) {
1374       for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1375         if (t -> suspended) {
1376           GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
1377           if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
1378             ABORT("ResumeThread failed");
1379           UNPROTECT_THREAD(t);
1380           t -> suspended = FALSE;
1381           if (GC_on_thread_event)
1382             GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
1383         }
1384       }
1385     }
1386   }
1387 # if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
1388     GC_please_stop = FALSE;
1389 # endif
1390 }
1391
1392 #ifdef MSWINCE
1393   /* The VirtualQuery calls below won't work properly on some old WinCE */
1394   /* versions, but since each stack is restricted to an aligned 64 KiB  */
1395   /* region of virtual memory we can just take the next lowest multiple */
1396   /* of 64 KiB.  The result of this macro must not be used as its       */
1397   /* argument later and must not be used as the lower bound for sp      */
1398   /* check (since the stack may be bigger than 64 KiB).                 */
1399 # define GC_wince_evaluate_stack_min(s) \
1400                         (ptr_t)(((word)(s) - 1) & ~(word)0xFFFF)
1401 #elif defined(GC_ASSERTIONS)
1402 # define GC_dont_query_stack_min FALSE
1403 #endif
1404
1405 /* A cache holding the results of the recent VirtualQuery call. */
1406 /* Protected by the allocation lock.                            */
1407 static ptr_t last_address = 0;
1408 static MEMORY_BASIC_INFORMATION last_info;
1409
1410 /* Probe stack memory region (starting at "s") to find out its  */
1411 /* lowest address (i.e. stack top).                             */
1412 /* S must be a mapped address inside the region, NOT the first  */
1413 /* unmapped address.                                            */
1414 STATIC ptr_t GC_get_stack_min(ptr_t s)
1415 {
1416   ptr_t bottom;
1417
1418   GC_ASSERT(I_HOLD_LOCK());
1419   if (s != last_address) {
1420     VirtualQuery(s, &last_info, sizeof(last_info));
1421     last_address = s;
1422   }
1423   do {
1424     bottom = (ptr_t)last_info.BaseAddress;
1425     VirtualQuery(bottom - 1, &last_info, sizeof(last_info));
1426     last_address = bottom - 1;
1427   } while ((last_info.Protect & PAGE_READWRITE)
1428            && !(last_info.Protect & PAGE_GUARD));
1429   return(bottom);
1430 }
1431
1432 /* Return true if the page at s has protections appropriate     */
1433 /* for a stack page.                                            */
1434 static GC_bool may_be_in_stack(ptr_t s)
1435 {
1436   GC_ASSERT(I_HOLD_LOCK());
1437   if (s != last_address) {
1438     VirtualQuery(s, &last_info, sizeof(last_info));
1439     last_address = s;
1440   }
1441   return (last_info.Protect & PAGE_READWRITE)
1442           && !(last_info.Protect & PAGE_GUARD);
1443 }
1444
1445 #if defined(I386)
1446   static BOOL isWow64;  /* Is running 32-bit code on Win64?     */
1447 #endif
1448
1449 STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
1450 {
1451   ptr_t sp, stack_min;
1452
1453   struct GC_traced_stack_sect_s *traced_stack_sect =
1454                                       thread -> traced_stack_sect;
1455   if (thread -> id == me) {
1456     GC_ASSERT(thread -> thread_blocked_sp == NULL);
1457     sp = GC_approx_sp();
1458   } else if ((sp = thread -> thread_blocked_sp) == NULL) {
1459               /* Use saved sp value for blocked threads. */
1460     /* For unblocked threads call GetThreadContext().   */
1461     CONTEXT context;
1462 #   if defined(I386)
1463 #     ifndef CONTEXT_EXCEPTION_ACTIVE
1464 #       define CONTEXT_EXCEPTION_ACTIVE    0x08000000
1465 #       define CONTEXT_EXCEPTION_REQUEST   0x40000000
1466 #       define CONTEXT_EXCEPTION_REPORTING 0x80000000
1467 #     endif
1468
1469       if (isWow64) {
1470         context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL
1471                                 | CONTEXT_EXCEPTION_REQUEST
1472                                 | CONTEXT_SEGMENTS;
1473       } else
1474 #   endif
1475     /* else */ {
1476       context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1477     }
1478     if (!GetThreadContext(THREAD_HANDLE(thread), &context))
1479       ABORT("GetThreadContext failed");
1480
1481     /* Push all registers that might point into the heap.  Frame        */
1482     /* pointer registers are included in case client code was           */
1483     /* compiled with the 'omit frame pointer' optimization.             */
1484 #   define PUSH1(reg) GC_push_one((word)context.reg)
1485 #   define PUSH2(r1,r2) (PUSH1(r1), PUSH1(r2))
1486 #   define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4))
1487 #   if defined(I386)
1488       PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
1489       /* WoW64 workaround. */
1490       if (isWow64
1491           && (context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0
1492           && (context.ContextFlags & (CONTEXT_EXCEPTION_ACTIVE
1493                                       /* | CONTEXT_SERVICE_ACTIVE */)) != 0) {
1494         LDT_ENTRY selector;
1495         PNT_TIB tib;
1496
1497         if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), context.SegFs,
1498                                     &selector))
1499           ABORT("GetThreadSelectorEntry failed");
1500         tib = (PNT_TIB)(selector.BaseLow
1501                         | (selector.HighWord.Bits.BaseMid << 16)
1502                         | (selector.HighWord.Bits.BaseHi << 24));
1503         /* GetThreadContext() might return stale register values, so    */
1504         /* we scan the entire stack region (down to the stack limit).   */
1505         /* There is no 100% guarantee that all the registers are pushed */
1506         /* but we do our best (the proper solution would be to fix it   */
1507         /* inside Windows OS).                                          */
1508         sp = (ptr_t)tib->StackLimit;
1509 #       ifdef DEBUG_THREADS
1510           GC_log_printf("TIB stack limit/base: %p .. %p\n",
1511                         (void *)tib->StackLimit, (void *)tib->StackBase);
1512 #       endif
1513         GC_ASSERT(!((word)thread->stack_base
1514                     COOLER_THAN (word)tib->StackBase));
1515         if (thread->stack_base != thread->initial_stack_base) {
1516           /* We are in a coroutine.     */
1517           if ((word)thread->stack_base <= (word)sp /* StackLimit */
1518               || (word)tib->StackBase < (word)thread->stack_base) {
1519             /* The coroutine stack is not within TIB stack.     */
1520             sp = (ptr_t)context.Esp;
1521             WARN("GetThreadContext might return stale register values"
1522                  " including ESP=%p\n", sp);
1523             /* TODO: Because of WoW64 bug, there is no guarantee that   */
1524             /* sp really points to the stack top but, for now, we do    */
1525             /* our best as the TIB stack limit/base cannot be used      */
1526             /* while we are inside a coroutine.                         */
1527           }
1528         }
1529       } else {
1530 #       ifdef DEBUG_THREADS
1531           {
1532             static GC_bool logged;
1533             if (isWow64 && !logged
1534                 && (context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) {
1535               GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n");
1536               logged = TRUE;
1537             }
1538           }
1539 #       endif
1540         sp = (ptr_t)context.Esp;
1541       }
1542 #   elif defined(X86_64)
1543       PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
1544       PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
1545       sp = (ptr_t)context.Rsp;
1546 #   elif defined(ARM32)
1547       PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11);
1548       PUSH1(R12);
1549       sp = (ptr_t)context.Sp;
1550 #   elif defined(AARCH64)
1551       PUSH4(X0,X1,X2,X3),PUSH4(X4,X5,X6,X7),PUSH4(X8,X9,X10,X11);
1552       PUSH4(X12,X13,X14,X15),PUSH4(X16,X17,X18,X19),PUSH4(X20,X21,X22,X23);
1553       PUSH4(X24,X25,X26,X27),PUSH1(X28);
1554       PUSH1(Lr);
1555       sp = (ptr_t)context.Sp;
1556 #   elif defined(SHx)
1557       PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
1558       PUSH2(R12,R13), PUSH1(R14);
1559       sp = (ptr_t)context.R15;
1560 #   elif defined(MIPS)
1561       PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
1562       PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
1563       PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
1564       PUSH4(IntT9,IntK0,IntK1,IntS8);
1565       sp = (ptr_t)context.IntSp;
1566 #   elif defined(PPC)
1567       PUSH4(Gpr0, Gpr3, Gpr4, Gpr5),  PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
1568       PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
1569       PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
1570       PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
1571       sp = (ptr_t)context.Gpr1;
1572 #   elif defined(ALPHA)
1573       PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
1574       PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
1575       PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
1576       PUSH4(IntT10,IntT11,IntT12,IntAt);
1577       sp = (ptr_t)context.IntSp;
1578 #   elif !defined(CPPCHECK)
1579 #     error Architecture is not supported
1580 #   endif
1581   } /* ! current thread */
1582
1583   /* Set stack_min to the lowest address in the thread stack,   */
1584   /* or to an address in the thread stack no larger than sp,    */
1585   /* taking advantage of the old value to avoid slow traversals */
1586   /* of large stacks.                                           */
1587   if (thread -> last_stack_min == ADDR_LIMIT) {
1588 #   ifdef MSWINCE
1589       if (GC_dont_query_stack_min) {
1590         stack_min = GC_wince_evaluate_stack_min(traced_stack_sect != NULL ?
1591                       (ptr_t)traced_stack_sect : thread -> stack_base);
1592         /* Keep last_stack_min value unmodified. */
1593       } else
1594 #   endif
1595     /* else */ {
1596       stack_min = GC_get_stack_min(traced_stack_sect != NULL ?
1597                       (ptr_t)traced_stack_sect : thread -> stack_base);
1598       UNPROTECT_THREAD(thread);
1599       thread -> last_stack_min = stack_min;
1600     }
1601   } else {
1602     /* First, adjust the latest known minimum stack address if we       */
1603     /* are inside GC_call_with_gc_active().                             */
1604     if (traced_stack_sect != NULL &&
1605         (word)thread->last_stack_min > (word)traced_stack_sect) {
1606       UNPROTECT_THREAD(thread);
1607       thread -> last_stack_min = (ptr_t)traced_stack_sect;
1608     }
1609
1610     if ((word)sp < (word)thread->stack_base
1611         && (word)sp >= (word)thread->last_stack_min) {
1612       stack_min = sp;
1613     } else {
1614       /* In the current thread it is always safe to use sp value.       */
1615       if (may_be_in_stack(thread -> id == me &&
1616                           (word)sp < (word)thread->last_stack_min ?
1617                           sp : thread -> last_stack_min)) {
1618         stack_min = (ptr_t)last_info.BaseAddress;
1619         /* Do not probe rest of the stack if sp is correct. */
1620         if ((word)sp < (word)stack_min
1621             || (word)sp >= (word)thread->stack_base)
1622           stack_min = GC_get_stack_min(thread -> last_stack_min);
1623       } else {
1624         /* Stack shrunk?  Is this possible? */
1625         stack_min = GC_get_stack_min(thread -> stack_base);
1626       }
1627       UNPROTECT_THREAD(thread);
1628       thread -> last_stack_min = stack_min;
1629     }
1630   }
1631
1632   GC_ASSERT(GC_dont_query_stack_min
1633             || stack_min == GC_get_stack_min(thread -> stack_base)
1634             || ((word)sp >= (word)stack_min
1635                 && (word)stack_min < (word)thread->stack_base
1636                 && (word)stack_min
1637                         > (word)GC_get_stack_min(thread -> stack_base)));
1638
1639   if ((word)sp >= (word)stack_min && (word)sp < (word)thread->stack_base) {
1640 #   ifdef DEBUG_THREADS
1641       GC_log_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
1642                     (int)thread->id, (void *)sp, (void *)thread->stack_base,
1643                     (int)me);
1644 #   endif
1645     GC_push_all_stack_sections(sp, thread->stack_base, traced_stack_sect);
1646   } else {
1647     /* If not current thread then it is possible for sp to point to     */
1648     /* the guarded (untouched yet) page just below the current          */
1649     /* stack_min of the thread.                                         */
1650     if (thread -> id == me || (word)sp >= (word)thread->stack_base
1651         || (word)(sp + GC_page_size) < (word)stack_min)
1652       WARN("Thread stack pointer %p out of range, pushing everything\n",
1653            sp);
1654 #   ifdef DEBUG_THREADS
1655       GC_log_printf("Pushing stack for 0x%x from (min) %p to %p from 0x%x\n",
1656                     (int)thread->id, (void *)stack_min,
1657                     (void *)thread->stack_base, (int)me);
1658 #   endif
1659     /* Push everything - ignore "traced stack section" data.            */
1660     GC_push_all_stack(stack_min, thread->stack_base);
1661   }
1662   return thread->stack_base - sp; /* stack grows down */
1663 }
1664
1665 GC_INNER void GC_push_all_stacks(void)
1666 {
1667   DWORD thread_id = GetCurrentThreadId();
1668   GC_bool found_me = FALSE;
1669 # ifndef SMALL_CONFIG
1670     unsigned nthreads = 0;
1671 # endif
1672   word total_size = 0;
1673 # ifndef GC_NO_THREADS_DISCOVERY
1674     if (GC_win32_dll_threads) {
1675       int i;
1676       LONG my_max = GC_get_max_thread_index();
1677
1678       for (i = 0; i <= my_max; i++) {
1679         GC_thread t = (GC_thread)(dll_thread_table + i);
1680         if (t -> tm.in_use && t -> stack_base) {
1681 #         ifndef SMALL_CONFIG
1682             ++nthreads;
1683 #         endif
1684           total_size += GC_push_stack_for(t, thread_id);
1685           if (t -> id == thread_id) found_me = TRUE;
1686         }
1687       }
1688     } else
1689 # endif
1690   /* else */ {
1691     int i;
1692     for (i = 0; i < THREAD_TABLE_SZ; i++) {
1693       GC_thread t;
1694       for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1695         if (!KNOWN_FINISHED(t) && t -> stack_base) {
1696 #         ifndef SMALL_CONFIG
1697             ++nthreads;
1698 #         endif
1699           total_size += GC_push_stack_for(t, thread_id);
1700           if (t -> id == thread_id) found_me = TRUE;
1701         }
1702       }
1703     }
1704   }
1705 # ifndef SMALL_CONFIG
1706     GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks%s\n", nthreads,
1707                           GC_win32_dll_threads ?
1708                                 " based on DllMain thread tracking" : "");
1709 # endif
1710   if (!found_me && !GC_in_thread_creation)
1711     ABORT("Collecting from unknown thread");
1712   GC_total_stacksize = total_size;
1713 }
1714
1715 #ifdef PARALLEL_MARK
1716
1717 # ifndef MAX_MARKERS
1718 #   define MAX_MARKERS 16
1719 # endif
1720
1721   static ptr_t marker_sp[MAX_MARKERS - 1]; /* The cold end of the stack */
1722                                            /* for markers.              */
1723 # ifdef IA64
1724     static ptr_t marker_bsp[MAX_MARKERS - 1];
1725 # endif
1726
1727   static ptr_t marker_last_stack_min[MAX_MARKERS - 1];
1728                                 /* Last known minimum (hottest) address */
1729                                 /* in stack (or ADDR_LIMIT if unset)    */
1730                                 /* for markers.                         */
1731
1732 #endif /* PARALLEL_MARK */
1733
1734 /* Find stack with the lowest address which overlaps the        */
1735 /* interval [start, limit).                                     */
1736 /* Return stack bounds in *lo and *hi.  If no such stack        */
1737 /* is found, both *hi and *lo will be set to an address         */
1738 /* higher than limit.                                           */
1739 GC_INNER void GC_get_next_stack(char *start, char *limit,
1740                                 char **lo, char **hi)
1741 {
1742   int i;
1743   char * current_min = ADDR_LIMIT;  /* Least in-range stack base      */
1744   ptr_t *plast_stack_min = NULL;    /* Address of last_stack_min      */
1745                                     /* field for thread corresponding */
1746                                     /* to current_min.                */
1747   GC_thread thread = NULL;          /* Either NULL or points to the   */
1748                                     /* thread's hash table entry      */
1749                                     /* containing *plast_stack_min.   */
1750
1751   /* First set current_min, ignoring limit. */
1752   if (GC_win32_dll_threads) {
1753     LONG my_max = GC_get_max_thread_index();
1754
1755     for (i = 0; i <= my_max; i++) {
1756       ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
1757
1758       if ((word)s > (word)start && (word)s < (word)current_min) {
1759         /* Update address of last_stack_min. */
1760         plast_stack_min = (ptr_t * /* no volatile */)
1761                             &dll_thread_table[i].last_stack_min;
1762         current_min = s;
1763 #       if defined(CPPCHECK)
1764           /* To avoid a warning that thread is always null.     */
1765           thread = (GC_thread)&dll_thread_table[i];
1766 #       endif
1767       }
1768     }
1769   } else {
1770     for (i = 0; i < THREAD_TABLE_SZ; i++) {
1771       GC_thread t;
1772
1773       for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
1774         ptr_t s = t -> stack_base;
1775
1776         if ((word)s > (word)start && (word)s < (word)current_min) {
1777           /* Update address of last_stack_min. */
1778           plast_stack_min = &t -> last_stack_min;
1779           thread = t; /* Remember current thread to unprotect. */
1780           current_min = s;
1781         }
1782       }
1783     }
1784 #   ifdef PARALLEL_MARK
1785       for (i = 0; i < GC_markers_m1; ++i) {
1786         ptr_t s = marker_sp[i];
1787 #       ifdef IA64
1788           /* FIXME: not implemented */
1789 #       endif
1790         if ((word)s > (word)start && (word)s < (word)current_min) {
1791           GC_ASSERT(marker_last_stack_min[i] != NULL);
1792           plast_stack_min = &marker_last_stack_min[i];
1793           current_min = s;
1794           thread = NULL; /* Not a thread's hash table entry. */
1795         }
1796       }
1797 #   endif
1798   }
1799
1800   *hi = current_min;
1801   if (current_min == ADDR_LIMIT) {
1802       *lo = ADDR_LIMIT;
1803       return;
1804   }
1805
1806   GC_ASSERT((word)current_min > (word)start && plast_stack_min != NULL);
1807 # ifdef MSWINCE
1808     if (GC_dont_query_stack_min) {
1809       *lo = GC_wince_evaluate_stack_min(current_min);
1810       /* Keep last_stack_min value unmodified. */
1811       return;
1812     }
1813 # endif
1814
1815   if ((word)current_min > (word)limit && !may_be_in_stack(limit)) {
1816     /* Skip the rest since the memory region at limit address is        */
1817     /* not a stack (so the lowest address of the found stack would      */
1818     /* be above the limit value anyway).                                */
1819     *lo = ADDR_LIMIT;
1820     return;
1821   }
1822
1823   /* Get the minimum address of the found stack by probing its memory   */
1824   /* region starting from the recent known minimum (if set).            */
1825   if (*plast_stack_min == ADDR_LIMIT
1826       || !may_be_in_stack(*plast_stack_min)) {
1827     /* Unsafe to start from last_stack_min value. */
1828     *lo = GC_get_stack_min(current_min);
1829   } else {
1830     /* Use the recent value to optimize search for min address. */
1831     *lo = GC_get_stack_min(*plast_stack_min);
1832   }
1833
1834   /* Remember current stack_min value. */
1835   if (thread != NULL) {
1836     UNPROTECT_THREAD(thread);
1837   }
1838   *plast_stack_min = *lo;
1839 }
1840
1841 #ifdef PARALLEL_MARK
1842
1843 # if defined(GC_PTHREADS) && !defined(GC_PTHREADS_PARAMARK)
1844     /* Use pthread-based parallel mark implementation.    */
1845
1846     /* Workaround a deadlock in winpthreads-3.0b internals (observed    */
1847     /* with MinGW 32/64).                                               */
1848 #   if !defined(__MINGW32__)
1849 #     define GC_PTHREADS_PARAMARK
1850 #   endif
1851 # endif
1852
1853 # if !defined(GC_PTHREADS_PARAMARK)
1854     STATIC HANDLE GC_marker_cv[MAX_MARKERS - 1] = {0};
1855                         /* Events with manual reset (one for each       */
1856                         /* mark helper).                                */
1857
1858     STATIC DWORD GC_marker_Id[MAX_MARKERS - 1] = {0};
1859                         /* This table is used for mapping helper        */
1860                         /* threads ID to mark helper index (linear      */
1861                         /* search is used since the mapping contains    */
1862                         /* only a few entries).                         */
1863 # endif
1864
1865   /* GC_mark_thread() is the same as in pthread_support.c */
1866 # ifdef GC_PTHREADS_PARAMARK
1867     STATIC void * GC_mark_thread(void * id)
1868 # elif defined(MSWINCE)
1869     STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
1870 # else
1871     STATIC unsigned __stdcall GC_mark_thread(void * id)
1872 # endif
1873   {
1874     word my_mark_no = 0;
1875
1876     if ((word)id == GC_WORD_MAX) return 0; /* to prevent a compiler warning */
1877     marker_sp[(word)id] = GC_approx_sp();
1878 #   ifdef IA64
1879       marker_bsp[(word)id] = GC_save_regs_in_stack();
1880 #   endif
1881 #   if !defined(GC_PTHREADS_PARAMARK)
1882       GC_marker_Id[(word)id] = GetCurrentThreadId();
1883 #   endif
1884
1885     /* Inform GC_start_mark_threads about completion of marker data init. */
1886     GC_acquire_mark_lock();
1887     if (0 == --GC_fl_builder_count) /* count may have a negative value */
1888       GC_notify_all_builder();
1889
1890     for (;; ++my_mark_no) {
1891       if (my_mark_no - GC_mark_no > (word)2) {
1892         /* resynchronize if we get far off, e.g. because GC_mark_no     */
1893         /* wrapped.                                                     */
1894         my_mark_no = GC_mark_no;
1895       }
1896 #     ifdef DEBUG_THREADS
1897         GC_log_printf("Starting mark helper for mark number %lu\n",
1898                       (unsigned long)my_mark_no);
1899 #     endif
1900       GC_help_marker(my_mark_no);
1901     }
1902   }
1903
1904 # ifndef GC_ASSERTIONS
1905 #   define SET_MARK_LOCK_HOLDER (void)0
1906 #   define UNSET_MARK_LOCK_HOLDER (void)0
1907 # endif
1908
1909   /* GC_mark_threads[] is unused here unlike that in pthread_support.c  */
1910
1911 # ifdef CAN_HANDLE_FORK
1912     static int available_markers_m1 = 0;
1913 # else
1914 #   define available_markers_m1 GC_markers_m1
1915 # endif
1916
1917 # ifdef GC_PTHREADS_PARAMARK
1918 #   include <pthread.h>
1919
1920 #   if defined(GC_ASSERTIONS) && !defined(NUMERIC_THREAD_ID)
1921 #     define NUMERIC_THREAD_ID(id) (unsigned long)(word)GC_PTHREAD_PTRVAL(id)
1922       /* Id not guaranteed to be unique. */
1923 #   endif
1924
1925 #   ifdef CAN_HANDLE_FORK
1926       static pthread_cond_t mark_cv;
1927                         /* initialized by GC_start_mark_threads_inner   */
1928 #   else
1929       static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
1930 #   endif
1931
1932     /* GC_start_mark_threads is the same as in pthread_support.c except */
1933     /* for thread stack that is assumed to be large enough.             */
1934
1935     GC_INNER void GC_start_mark_threads_inner(void)
1936     {
1937       int i;
1938       pthread_attr_t attr;
1939       pthread_t new_thread;
1940 #     ifndef NO_MARKER_SPECIAL_SIGMASK
1941         sigset_t set, oldset;
1942 #     endif
1943
1944       GC_ASSERT(I_DONT_HOLD_LOCK());
1945       if (available_markers_m1 <= 0) return;
1946                 /* Skip if parallel markers disabled or already started. */
1947 #     ifdef CAN_HANDLE_FORK
1948         if (GC_parallel) return;
1949
1950         /* Reset mark_cv state after forking (as in pthread_support.c). */
1951         {
1952           pthread_cond_t mark_cv_local = PTHREAD_COND_INITIALIZER;
1953           BCOPY(&mark_cv_local, &mark_cv, sizeof(mark_cv));
1954         }
1955 #     endif
1956
1957       GC_ASSERT(GC_fl_builder_count == 0);
1958       if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
1959       if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
1960         ABORT("pthread_attr_setdetachstate failed");
1961
1962 #     ifndef NO_MARKER_SPECIAL_SIGMASK
1963         /* Apply special signal mask to GC marker threads, and don't drop */
1964         /* user defined signals by GC marker threads.                     */
1965         if (sigfillset(&set) != 0)
1966           ABORT("sigfillset failed");
1967         if (pthread_sigmask(SIG_BLOCK, &set, &oldset) < 0) {
1968           WARN("pthread_sigmask set failed, no markers started,"
1969                " errno = %" WARN_PRIdPTR "\n", errno);
1970           GC_markers_m1 = 0;
1971           (void)pthread_attr_destroy(&attr);
1972           return;
1973         }
1974 #     endif /* !NO_MARKER_SPECIAL_SIGMASK */
1975
1976 #     ifdef CAN_HANDLE_FORK
1977         /* To have proper GC_parallel value in GC_help_marker.  */
1978         GC_markers_m1 = available_markers_m1;
1979 #     endif
1980       for (i = 0; i < available_markers_m1; ++i) {
1981         marker_last_stack_min[i] = ADDR_LIMIT;
1982         if (0 != pthread_create(&new_thread, &attr,
1983                                 GC_mark_thread, (void *)(word)i)) {
1984           WARN("Marker thread creation failed\n", 0);
1985           /* Don't try to create other marker threads.    */
1986           GC_markers_m1 = i;
1987           break;
1988         }
1989       }
1990
1991 #     ifndef NO_MARKER_SPECIAL_SIGMASK
1992         /* Restore previous signal mask.        */
1993         if (pthread_sigmask(SIG_SETMASK, &oldset, NULL) < 0) {
1994           WARN("pthread_sigmask restore failed, errno = %" WARN_PRIdPTR "\n",
1995                errno);
1996         }
1997 #     endif
1998
1999       (void)pthread_attr_destroy(&attr);
2000       GC_wait_for_markers_init();
2001       GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
2002     }
2003
2004 #   ifdef GC_ASSERTIONS
2005       STATIC unsigned long GC_mark_lock_holder = NO_THREAD;
2006 #     define SET_MARK_LOCK_HOLDER \
2007                 (void)(GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self()))
2008 #     define UNSET_MARK_LOCK_HOLDER \
2009                 do { \
2010                   GC_ASSERT(GC_mark_lock_holder \
2011                                 == NUMERIC_THREAD_ID(pthread_self())); \
2012                   GC_mark_lock_holder = NO_THREAD; \
2013                 } while (0)
2014 #   endif /* GC_ASSERTIONS */
2015
2016     static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
2017
2018     static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
2019
2020     /* GC_acquire/release_mark_lock(), GC_wait_builder/marker(),          */
2021     /* GC_wait_for_reclaim(), GC_notify_all_builder/marker() are the same */
2022     /* as in pthread_support.c except that GC_generic_lock() is not used. */
2023
2024 #   ifdef LOCK_STATS
2025       volatile AO_t GC_block_count = 0;
2026 #   endif
2027
2028     GC_INNER void GC_acquire_mark_lock(void)
2029     {
2030 #     if defined(NUMERIC_THREAD_ID_UNIQUE) && !defined(THREAD_SANITIZER)
2031         GC_ASSERT(GC_mark_lock_holder != NUMERIC_THREAD_ID(pthread_self()));
2032 #     endif
2033       if (pthread_mutex_lock(&mark_mutex) != 0) {
2034         ABORT("pthread_mutex_lock failed");
2035       }
2036 #     ifdef LOCK_STATS
2037         (void)AO_fetch_and_add1(&GC_block_count);
2038 #     endif
2039       /* GC_generic_lock(&mark_mutex); */
2040       SET_MARK_LOCK_HOLDER;
2041     }
2042
2043     GC_INNER void GC_release_mark_lock(void)
2044     {
2045       UNSET_MARK_LOCK_HOLDER;
2046       if (pthread_mutex_unlock(&mark_mutex) != 0) {
2047         ABORT("pthread_mutex_unlock failed");
2048       }
2049     }
2050
2051     /* Collector must wait for a freelist builders for 2 reasons:       */
2052     /* 1) Mark bits may still be getting examined without lock.         */
2053     /* 2) Partial free lists referenced only by locals may not be       */
2054     /* scanned correctly, e.g. if they contain "pointer-free" objects,  */
2055     /* since the free-list link may be ignored.                         */
2056     STATIC void GC_wait_builder(void)
2057     {
2058       UNSET_MARK_LOCK_HOLDER;
2059       if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
2060         ABORT("pthread_cond_wait failed");
2061       }
2062       GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
2063       SET_MARK_LOCK_HOLDER;
2064     }
2065
2066     GC_INNER void GC_wait_for_reclaim(void)
2067     {
2068       GC_acquire_mark_lock();
2069       while (GC_fl_builder_count > 0) {
2070         GC_wait_builder();
2071       }
2072       GC_release_mark_lock();
2073     }
2074
2075     GC_INNER void GC_notify_all_builder(void)
2076     {
2077       GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
2078       if (pthread_cond_broadcast(&builder_cv) != 0) {
2079         ABORT("pthread_cond_broadcast failed");
2080       }
2081     }
2082
2083     GC_INNER void GC_wait_marker(void)
2084     {
2085       GC_ASSERT(GC_parallel);
2086       UNSET_MARK_LOCK_HOLDER;
2087       if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
2088         ABORT("pthread_cond_wait failed");
2089       }
2090       GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
2091       SET_MARK_LOCK_HOLDER;
2092     }
2093
2094     GC_INNER void GC_notify_all_marker(void)
2095     {
2096       GC_ASSERT(GC_parallel);
2097       if (pthread_cond_broadcast(&mark_cv) != 0) {
2098         ABORT("pthread_cond_broadcast failed");
2099       }
2100     }
2101
2102 # else /* ! GC_PTHREADS_PARAMARK */
2103
2104 #   ifndef MARK_THREAD_STACK_SIZE
2105 #     define MARK_THREAD_STACK_SIZE 0   /* default value */
2106 #   endif
2107
2108     /* mark_mutex_event, builder_cv, mark_cv are initialized in GC_thr_init */
2109     static HANDLE mark_mutex_event = (HANDLE)0; /* Event with auto-reset.   */
2110     static HANDLE builder_cv = (HANDLE)0; /* Event with manual reset.       */
2111     static HANDLE mark_cv = (HANDLE)0; /* Event with manual reset.          */
2112
2113     GC_INNER void GC_start_mark_threads_inner(void)
2114     {
2115       int i;
2116
2117       GC_ASSERT(I_DONT_HOLD_LOCK());
2118       if (available_markers_m1 <= 0) return;
2119
2120       GC_ASSERT(GC_fl_builder_count == 0);
2121       /* Initialize GC_marker_cv[] fully before starting the    */
2122       /* first helper thread.                                   */
2123       for (i = 0; i < GC_markers_m1; ++i) {
2124         if ((GC_marker_cv[i] = CreateEvent(NULL /* attrs */,
2125                                         TRUE /* isManualReset */,
2126                                         FALSE /* initialState */,
2127                                         NULL /* name (A/W) */)) == (HANDLE)0)
2128           ABORT("CreateEvent failed");
2129       }
2130
2131       for (i = 0; i < GC_markers_m1; ++i) {
2132 #       if defined(MSWINCE) || defined(MSWIN_XBOX1)
2133           HANDLE handle;
2134           DWORD thread_id;
2135
2136           marker_last_stack_min[i] = ADDR_LIMIT;
2137           /* There is no _beginthreadex() in WinCE. */
2138           handle = CreateThread(NULL /* lpsa */,
2139                                 MARK_THREAD_STACK_SIZE /* ignored */,
2140                                 GC_mark_thread, (LPVOID)(word)i,
2141                                 0 /* fdwCreate */, &thread_id);
2142           if (handle == NULL) {
2143             WARN("Marker thread creation failed\n", 0);
2144             /* The most probable failure reason is "not enough memory". */
2145             /* Don't try to create other marker threads.                */
2146             break;
2147           } else {
2148             /* It's safe to detach the thread.  */
2149             CloseHandle(handle);
2150           }
2151 #       else
2152           GC_uintptr_t handle;
2153           unsigned thread_id;
2154
2155           marker_last_stack_min[i] = ADDR_LIMIT;
2156           handle = _beginthreadex(NULL /* security_attr */,
2157                                 MARK_THREAD_STACK_SIZE, GC_mark_thread,
2158                                 (void *)(word)i, 0 /* flags */, &thread_id);
2159           if (!handle || handle == (GC_uintptr_t)-1L) {
2160             WARN("Marker thread creation failed\n", 0);
2161             /* Don't try to create other marker threads.                */
2162             break;
2163           } else {/* We may detach the thread (if handle is of HANDLE type) */
2164             /* CloseHandle((HANDLE)handle); */
2165           }
2166 #       endif
2167       }
2168
2169       /* Adjust GC_markers_m1 (and free unused resources) if failed.    */
2170       while (GC_markers_m1 > i) {
2171         GC_markers_m1--;
2172         CloseHandle(GC_marker_cv[GC_markers_m1]);
2173       }
2174       GC_wait_for_markers_init();
2175       GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
2176       if (i == 0) {
2177         CloseHandle(mark_cv);
2178         CloseHandle(builder_cv);
2179         CloseHandle(mark_mutex_event);
2180       }
2181     }
2182
2183 #   ifdef GC_ASSERTIONS
2184       STATIC DWORD GC_mark_lock_holder = NO_THREAD;
2185 #     define SET_MARK_LOCK_HOLDER \
2186                 (void)(GC_mark_lock_holder = GetCurrentThreadId())
2187 #     define UNSET_MARK_LOCK_HOLDER \
2188                 do { \
2189                   GC_ASSERT(GC_mark_lock_holder == GetCurrentThreadId()); \
2190                   GC_mark_lock_holder = NO_THREAD; \
2191                 } while (0)
2192 #   endif /* GC_ASSERTIONS */
2193
2194     STATIC /* volatile */ LONG GC_mark_mutex_state = 0;
2195                                 /* Mutex state: 0 - unlocked,           */
2196                                 /* 1 - locked and no other waiters,     */
2197                                 /* -1 - locked and waiters may exist.   */
2198                                 /* Accessed by InterlockedExchange().   */
2199
2200     /* #define LOCK_STATS */
2201 #   ifdef LOCK_STATS
2202       volatile AO_t GC_block_count = 0;
2203       volatile AO_t GC_unlocked_count = 0;
2204 #   endif
2205
2206     GC_INNER void GC_acquire_mark_lock(void)
2207     {
2208 #     ifndef THREAD_SANITIZER
2209         GC_ASSERT(GC_mark_lock_holder != GetCurrentThreadId());
2210 #     endif
2211       if (InterlockedExchange(&GC_mark_mutex_state, 1 /* locked */) != 0) {
2212 #       ifdef LOCK_STATS
2213           (void)AO_fetch_and_add1(&GC_block_count);
2214 #       endif
2215         /* Repeatedly reset the state and wait until acquire the lock.  */
2216         while (InterlockedExchange(&GC_mark_mutex_state,
2217                                    -1 /* locked_and_has_waiters */) != 0) {
2218           if (WaitForSingleObject(mark_mutex_event, INFINITE) == WAIT_FAILED)
2219             ABORT("WaitForSingleObject failed");
2220         }
2221       }
2222 #     ifdef LOCK_STATS
2223         else {
2224           (void)AO_fetch_and_add1(&GC_unlocked_count);
2225         }
2226 #     endif
2227
2228       GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
2229       SET_MARK_LOCK_HOLDER;
2230     }
2231
2232     GC_INNER void GC_release_mark_lock(void)
2233     {
2234       UNSET_MARK_LOCK_HOLDER;
2235       if (InterlockedExchange(&GC_mark_mutex_state, 0 /* unlocked */) < 0) {
2236         /* wake a waiter */
2237         if (SetEvent(mark_mutex_event) == FALSE)
2238           ABORT("SetEvent failed");
2239       }
2240     }
2241
2242     /* In GC_wait_for_reclaim/GC_notify_all_builder() we emulate POSIX    */
2243     /* cond_wait/cond_broadcast() primitives with WinAPI Event object     */
2244     /* (working in "manual reset" mode).  This works here because         */
2245     /* GC_notify_all_builder() is always called holding lock on           */
2246     /* mark_mutex and the checked condition (GC_fl_builder_count == 0)    */
2247     /* is the only one for which broadcasting on builder_cv is performed. */
2248
2249     GC_INNER void GC_wait_for_reclaim(void)
2250     {
2251       GC_ASSERT(builder_cv != 0);
2252       for (;;) {
2253         GC_acquire_mark_lock();
2254         if (GC_fl_builder_count == 0)
2255           break;
2256         if (ResetEvent(builder_cv) == FALSE)
2257           ABORT("ResetEvent failed");
2258         GC_release_mark_lock();
2259         if (WaitForSingleObject(builder_cv, INFINITE) == WAIT_FAILED)
2260           ABORT("WaitForSingleObject failed");
2261       }
2262       GC_release_mark_lock();
2263     }
2264
2265     GC_INNER void GC_notify_all_builder(void)
2266     {
2267       GC_ASSERT(GC_mark_lock_holder == GetCurrentThreadId());
2268       GC_ASSERT(builder_cv != 0);
2269       GC_ASSERT(GC_fl_builder_count == 0);
2270       if (SetEvent(builder_cv) == FALSE)
2271         ABORT("SetEvent failed");
2272     }
2273
2274     /* mark_cv is used (for waiting) by a non-helper thread.    */
2275
2276     GC_INNER void GC_wait_marker(void)
2277     {
2278       HANDLE event = mark_cv;
2279       DWORD thread_id = GetCurrentThreadId();
2280       int i = GC_markers_m1;
2281
2282       while (i-- > 0) {
2283         if (GC_marker_Id[i] == thread_id) {
2284           event = GC_marker_cv[i];
2285           break;
2286         }
2287       }
2288
2289       if (ResetEvent(event) == FALSE)
2290         ABORT("ResetEvent failed");
2291       GC_release_mark_lock();
2292       if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED)
2293         ABORT("WaitForSingleObject failed");
2294       GC_acquire_mark_lock();
2295     }
2296
2297     GC_INNER void GC_notify_all_marker(void)
2298     {
2299       DWORD thread_id = GetCurrentThreadId();
2300       int i = GC_markers_m1;
2301
2302       while (i-- > 0) {
2303         /* Notify every marker ignoring self (for efficiency).  */
2304         if (SetEvent(GC_marker_Id[i] != thread_id ? GC_marker_cv[i] :
2305                      mark_cv) == FALSE)
2306           ABORT("SetEvent failed");
2307       }
2308     }
2309
2310 # endif /* ! GC_PTHREADS_PARAMARK */
2311
2312 #endif /* PARALLEL_MARK */
2313
2314   /* We have no DllMain to take care of new threads.  Thus we   */
2315   /* must properly intercept thread creation.                   */
2316
2317   typedef struct {
2318     LPTHREAD_START_ROUTINE start;
2319     LPVOID param;
2320   } thread_args;
2321
2322   STATIC void * GC_CALLBACK GC_win32_start_inner(struct GC_stack_base *sb,
2323                                                  void *arg)
2324   {
2325     void * ret;
2326     LPTHREAD_START_ROUTINE start = ((thread_args *)arg)->start;
2327     LPVOID param = ((thread_args *)arg)->param;
2328
2329     GC_register_my_thread(sb); /* This waits for an in-progress GC.     */
2330
2331 #   ifdef DEBUG_THREADS
2332       GC_log_printf("thread 0x%lx starting...\n", (long)GetCurrentThreadId());
2333 #   endif
2334
2335     GC_free(arg);
2336
2337     /* Clear the thread entry even if we exit with an exception.        */
2338     /* This is probably pointless, since an uncaught exception is       */
2339     /* supposed to result in the process being killed.                  */
2340 #   if !defined(__GNUC__) && !defined(NO_CRT)
2341       ret = NULL; /* to suppress "might be uninitialized" compiler warning */
2342       __try
2343 #   endif
2344     {
2345       ret = (void *)(word)(*start)(param);
2346     }
2347 #   if !defined(__GNUC__) && !defined(NO_CRT)
2348       __finally
2349 #   endif
2350     {
2351       GC_unregister_my_thread();
2352     }
2353
2354 #   ifdef DEBUG_THREADS
2355       GC_log_printf("thread 0x%lx returned from start routine\n",
2356                     (long)GetCurrentThreadId());
2357 #   endif
2358     return ret;
2359   }
2360
2361   STATIC DWORD WINAPI GC_win32_start(LPVOID arg)
2362   {
2363     return (DWORD)(word)GC_call_with_stack_base(GC_win32_start_inner, arg);
2364   }
2365
2366   GC_API HANDLE WINAPI GC_CreateThread(
2367                         LPSECURITY_ATTRIBUTES lpThreadAttributes,
2368                         GC_WIN32_SIZE_T dwStackSize,
2369                         LPTHREAD_START_ROUTINE lpStartAddress,
2370                         LPVOID lpParameter, DWORD dwCreationFlags,
2371                         LPDWORD lpThreadId)
2372   {
2373     if (!EXPECT(parallel_initialized, TRUE))
2374       GC_init_parallel();
2375                 /* make sure GC is initialized (i.e. main thread is     */
2376                 /* attached, tls initialized).                          */
2377
2378 #   ifdef DEBUG_THREADS
2379       GC_log_printf("About to create a thread from 0x%lx\n",
2380                     (long)GetCurrentThreadId());
2381 #   endif
2382     if (GC_win32_dll_threads) {
2383       return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
2384                           lpParameter, dwCreationFlags, lpThreadId);
2385     } else {
2386       thread_args *args =
2387                 (thread_args *)GC_malloc_uncollectable(sizeof(thread_args));
2388                 /* Handed off to and deallocated by child thread.       */
2389       HANDLE thread_h;
2390
2391       if (NULL == args) {
2392         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2393         return NULL;
2394       }
2395
2396       /* set up thread arguments */
2397       args -> start = lpStartAddress;
2398       args -> param = lpParameter;
2399       GC_dirty(args);
2400       REACHABLE_AFTER_DIRTY(lpParameter);
2401
2402       set_need_to_lock();
2403       thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
2404                               args, dwCreationFlags, lpThreadId);
2405       if (thread_h == 0) GC_free(args);
2406       return thread_h;
2407     }
2408   }
2409
2410   GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(DWORD dwExitCode)
2411   {
2412     GC_unregister_my_thread();
2413     ExitThread(dwExitCode);
2414   }
2415
2416 # if !defined(CYGWIN32) && !defined(MSWINCE) && !defined(MSWIN_XBOX1) \
2417      && !defined(NO_CRT)
2418     GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
2419                                   void *security, unsigned stack_size,
2420                                   unsigned (__stdcall *start_address)(void *),
2421                                   void *arglist, unsigned initflag,
2422                                   unsigned *thrdaddr)
2423     {
2424       if (!EXPECT(parallel_initialized, TRUE))
2425         GC_init_parallel();
2426                 /* make sure GC is initialized (i.e. main thread is     */
2427                 /* attached, tls initialized).                          */
2428 #     ifdef DEBUG_THREADS
2429         GC_log_printf("About to create a thread from 0x%lx\n",
2430                       (long)GetCurrentThreadId());
2431 #     endif
2432
2433       if (GC_win32_dll_threads) {
2434         return _beginthreadex(security, stack_size, start_address,
2435                               arglist, initflag, thrdaddr);
2436       } else {
2437         GC_uintptr_t thread_h;
2438         thread_args *args =
2439                 (thread_args *)GC_malloc_uncollectable(sizeof(thread_args));
2440                 /* Handed off to and deallocated by child thread.       */
2441
2442         if (NULL == args) {
2443           /* MSDN docs say _beginthreadex() returns 0 on error and sets */
2444           /* errno to either EAGAIN (too many threads) or EINVAL (the   */
2445           /* argument is invalid or the stack size is incorrect), so we */
2446           /* set errno to EAGAIN on "not enough memory".                */
2447           errno = EAGAIN;
2448           return 0;
2449         }
2450
2451         /* set up thread arguments */
2452         args -> start = (LPTHREAD_START_ROUTINE)start_address;
2453         args -> param = arglist;
2454         GC_dirty(args);
2455         REACHABLE_AFTER_DIRTY(arglist);
2456
2457         set_need_to_lock();
2458         thread_h = _beginthreadex(security, stack_size,
2459                         (unsigned (__stdcall *)(void *))GC_win32_start,
2460                         args, initflag, thrdaddr);
2461         if (thread_h == 0) GC_free(args);
2462         return thread_h;
2463       }
2464     }
2465
2466     GC_API void GC_CALL GC_endthreadex(unsigned retval)
2467     {
2468       GC_unregister_my_thread();
2469       _endthreadex(retval);
2470     }
2471 # endif /* !CYGWIN32 && !MSWINCE && !MSWIN_XBOX1 && !NO_CRT */
2472
2473 #ifdef GC_WINMAIN_REDIRECT
2474   /* This might be useful on WinCE.  Shouldn't be used with GC_DLL.     */
2475
2476 # if defined(MSWINCE) && defined(UNDER_CE)
2477 #   define WINMAIN_LPTSTR LPWSTR
2478 # else
2479 #   define WINMAIN_LPTSTR LPSTR
2480 # endif
2481
2482   /* This is defined in gc.h.   */
2483 # undef WinMain
2484
2485   /* Defined outside GC by an application.      */
2486   int WINAPI GC_WinMain(HINSTANCE, HINSTANCE, WINMAIN_LPTSTR, int);
2487
2488   typedef struct {
2489     HINSTANCE hInstance;
2490     HINSTANCE hPrevInstance;
2491     WINMAIN_LPTSTR lpCmdLine;
2492     int nShowCmd;
2493   } main_thread_args;
2494
2495   static DWORD WINAPI main_thread_start(LPVOID arg)
2496   {
2497     main_thread_args * args = (main_thread_args *) arg;
2498     return (DWORD)GC_WinMain(args->hInstance, args->hPrevInstance,
2499                              args->lpCmdLine, args->nShowCmd);
2500   }
2501
2502   STATIC void * GC_waitForSingleObjectInfinite(void * handle)
2503   {
2504     return (void *)(word)WaitForSingleObject((HANDLE)handle, INFINITE);
2505   }
2506
2507 # ifndef WINMAIN_THREAD_STACK_SIZE
2508 #   define WINMAIN_THREAD_STACK_SIZE 0  /* default value */
2509 # endif
2510
2511   int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2512                      WINMAIN_LPTSTR lpCmdLine, int nShowCmd)
2513   {
2514     DWORD exit_code = 1;
2515
2516     main_thread_args args = {
2517                 hInstance, hPrevInstance, lpCmdLine, nShowCmd
2518     };
2519     HANDLE thread_h;
2520     DWORD thread_id;
2521
2522     /* initialize everything */
2523     GC_INIT();
2524
2525     /* start the main thread */
2526     thread_h = GC_CreateThread(NULL /* lpsa */,
2527                         WINMAIN_THREAD_STACK_SIZE /* ignored on WinCE */,
2528                         main_thread_start, &args, 0 /* fdwCreate */,
2529                         &thread_id);
2530
2531     if (thread_h != NULL) {
2532       if ((DWORD)(word)GC_do_blocking(GC_waitForSingleObjectInfinite,
2533                                       (void *)thread_h) == WAIT_FAILED)
2534         ABORT("WaitForSingleObject(main_thread) failed");
2535       GetExitCodeThread (thread_h, &exit_code);
2536       CloseHandle (thread_h);
2537     } else {
2538       ABORT("GC_CreateThread(main_thread) failed");
2539     }
2540
2541 #   ifdef MSWINCE
2542       GC_deinit();
2543 #   endif
2544     return (int) exit_code;
2545   }
2546
2547 #endif /* GC_WINMAIN_REDIRECT */
2548
2549 GC_INNER void GC_thr_init(void)
2550 {
2551   struct GC_stack_base sb;
2552
2553   GC_ASSERT(I_HOLD_LOCK());
2554   if (GC_thr_initialized) return;
2555
2556   GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
2557 # ifdef GC_NO_THREADS_DISCOVERY
2558 #   define GC_main_thread GetCurrentThreadId()
2559 # else
2560     GC_main_thread = GetCurrentThreadId();
2561 # endif
2562   GC_thr_initialized = TRUE;
2563
2564 # ifdef CAN_HANDLE_FORK
2565     /* Prepare for forks if requested.  */
2566     if (GC_handle_fork) {
2567 #     ifdef CAN_CALL_ATFORK
2568         if (pthread_atfork(fork_prepare_proc, fork_parent_proc,
2569                            fork_child_proc) == 0) {
2570           /* Handlers successfully registered.  */
2571           GC_handle_fork = 1;
2572         } else
2573 #     endif
2574       /* else */ if (GC_handle_fork != -1)
2575         ABORT("pthread_atfork failed");
2576     }
2577 # endif
2578
2579 # if defined(I386)
2580     /* Set isWow64 flag. */
2581     {
2582       HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
2583       if (hK32) {
2584         FARPROC pfn = GetProcAddress(hK32, "IsWow64Process");
2585         if (pfn
2586             && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))pfn)(GetCurrentProcess(),
2587                                                       &isWow64))
2588           isWow64 = FALSE; /* IsWow64Process failed */
2589       }
2590     }
2591 # endif
2592
2593   /* Add the initial thread, so we can stop it. */
2594   sb.mem_base = GC_stackbottom;
2595   GC_ASSERT(sb.mem_base != NULL);
2596 # ifdef IA64
2597     sb.reg_base = GC_register_stackbottom;
2598 # endif
2599
2600 # if defined(PARALLEL_MARK)
2601     {
2602       char * markers_string = GETENV("GC_MARKERS");
2603       int markers;
2604
2605       if (markers_string != NULL) {
2606         markers = atoi(markers_string);
2607         if (markers <= 0 || markers > MAX_MARKERS) {
2608           WARN("Too big or invalid number of mark threads: %" WARN_PRIdPTR
2609                "; using maximum threads\n", (signed_word)markers);
2610           markers = MAX_MARKERS;
2611         }
2612       } else {
2613 #       ifdef MSWINCE
2614           /* There is no GetProcessAffinityMask() in WinCE.     */
2615           /* GC_sysinfo is already initialized.                 */
2616           markers = (int)GC_sysinfo.dwNumberOfProcessors;
2617 #       else
2618 #         ifdef _WIN64
2619             DWORD_PTR procMask = 0;
2620             DWORD_PTR sysMask;
2621 #         else
2622             DWORD procMask = 0;
2623             DWORD sysMask;
2624 #         endif
2625           int ncpu = 0;
2626           if (
2627 #           ifdef __cplusplus
2628               GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask)
2629 #           else
2630               /* Cast args to void* for compatibility with some old SDKs. */
2631               GetProcessAffinityMask(GetCurrentProcess(),
2632                                      (void *)&procMask, (void *)&sysMask)
2633 #           endif
2634               && procMask) {
2635             do {
2636               ncpu++;
2637             } while ((procMask &= procMask - 1) != 0);
2638           }
2639           markers = ncpu;
2640 #       endif
2641 #       if defined(GC_MIN_MARKERS) && !defined(CPPCHECK)
2642           /* This is primarily for testing on systems without getenv(). */
2643           if (markers < GC_MIN_MARKERS)
2644             markers = GC_MIN_MARKERS;
2645 #       endif
2646         if (markers > MAX_MARKERS)
2647           markers = MAX_MARKERS; /* silently limit the value */
2648       }
2649       available_markers_m1 = markers - 1;
2650     }
2651
2652     /* Check whether parallel mode could be enabled.    */
2653       if (GC_win32_dll_threads || available_markers_m1 <= 0) {
2654         /* Disable parallel marking. */
2655         GC_parallel = FALSE;
2656         GC_COND_LOG_PRINTF(
2657                 "Single marker thread, turning off parallel marking\n");
2658       } else {
2659 #       ifndef GC_PTHREADS_PARAMARK
2660           /* Initialize Win32 event objects for parallel marking.       */
2661           mark_mutex_event = CreateEvent(NULL /* attrs */,
2662                                 FALSE /* isManualReset */,
2663                                 FALSE /* initialState */, NULL /* name */);
2664           builder_cv = CreateEvent(NULL /* attrs */,
2665                                 TRUE /* isManualReset */,
2666                                 FALSE /* initialState */, NULL /* name */);
2667           mark_cv = CreateEvent(NULL /* attrs */, TRUE /* isManualReset */,
2668                                 FALSE /* initialState */, NULL /* name */);
2669           if (mark_mutex_event == (HANDLE)0 || builder_cv == (HANDLE)0
2670               || mark_cv == (HANDLE)0)
2671             ABORT("CreateEvent failed");
2672 #       endif
2673       }
2674 # endif /* PARALLEL_MARK */
2675
2676   GC_ASSERT(0 == GC_lookup_thread_inner(GC_main_thread));
2677   GC_register_my_thread_inner(&sb, GC_main_thread);
2678 # undef GC_main_thread
2679 }
2680
2681 #ifdef GC_PTHREADS
2682
2683   struct start_info {
2684     void *(*start_routine)(void *);
2685     void *arg;
2686     GC_bool detached;
2687   };
2688
2689   GC_API int GC_pthread_join(pthread_t pthread_id, void **retval)
2690   {
2691     int result;
2692 #   ifndef GC_WIN32_PTHREADS
2693       GC_thread t;
2694 #   endif
2695     DCL_LOCK_STATE;
2696
2697     GC_ASSERT(!GC_win32_dll_threads);
2698 #   ifdef DEBUG_THREADS
2699       GC_log_printf("thread %p(0x%lx) is joining thread %p\n",
2700                     (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2701                     (long)GetCurrentThreadId(),
2702                     (void *)GC_PTHREAD_PTRVAL(pthread_id));
2703 #   endif
2704
2705     /* Thread being joined might not have registered itself yet. */
2706     /* After the join, thread id may have been recycled.         */
2707     /* FIXME: It would be better if this worked more like        */
2708     /* pthread_support.c.                                        */
2709 #   ifndef GC_WIN32_PTHREADS
2710       while ((t = GC_lookup_pthread(pthread_id)) == 0)
2711         Sleep(10);
2712 #   endif
2713     result = pthread_join(pthread_id, retval);
2714     if (0 == result) {
2715 #     ifdef GC_WIN32_PTHREADS
2716         /* pthreads-win32 and winpthreads id are unique (not recycled). */
2717         GC_thread t = GC_lookup_pthread(pthread_id);
2718         if (NULL == t) ABORT("Thread not registered");
2719 #     endif
2720
2721       LOCK();
2722       if ((t -> flags & FINISHED) != 0) {
2723         GC_delete_gc_thread_no_free(t);
2724         GC_INTERNAL_FREE(t);
2725       }
2726       UNLOCK();
2727     }
2728
2729 #   ifdef DEBUG_THREADS
2730       GC_log_printf("thread %p(0x%lx) join with thread %p %s\n",
2731                     (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2732                     (long)GetCurrentThreadId(),
2733                     (void *)GC_PTHREAD_PTRVAL(pthread_id),
2734                     result != 0 ? "failed" : "succeeded");
2735 #   endif
2736     return result;
2737   }
2738
2739   /* Cygwin-pthreads calls CreateThread internally, but it's not easily */
2740   /* interceptable by us..., so intercept pthread_create instead.       */
2741   GC_API int GC_pthread_create(pthread_t *new_thread,
2742                                GC_PTHREAD_CREATE_CONST pthread_attr_t *attr,
2743                                void *(*start_routine)(void *), void *arg)
2744   {
2745     int result;
2746     struct start_info * si;
2747
2748     if (!EXPECT(parallel_initialized, TRUE))
2749       GC_init_parallel();
2750              /* make sure GC is initialized (i.e. main thread is attached) */
2751     GC_ASSERT(!GC_win32_dll_threads);
2752
2753       /* This is otherwise saved only in an area mmapped by the thread  */
2754       /* library, which isn't visible to the collector.                 */
2755       si = (struct start_info *)GC_malloc_uncollectable(
2756                                                 sizeof(struct start_info));
2757       if (NULL == si)
2758         return EAGAIN;
2759
2760       si -> start_routine = start_routine;
2761       si -> arg = arg;
2762       GC_dirty(si);
2763       REACHABLE_AFTER_DIRTY(arg);
2764       if (attr != 0 &&
2765           pthread_attr_getdetachstate(attr, &si->detached)
2766           == PTHREAD_CREATE_DETACHED) {
2767         si->detached = TRUE;
2768       }
2769
2770 #     ifdef DEBUG_THREADS
2771         GC_log_printf("About to create a thread from %p(0x%lx)\n",
2772                       (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2773                       (long)GetCurrentThreadId());
2774 #     endif
2775       set_need_to_lock();
2776       result = pthread_create(new_thread, attr, GC_pthread_start, si);
2777
2778       if (result) { /* failure */
2779           GC_free(si);
2780       }
2781       return(result);
2782   }
2783
2784   STATIC void * GC_CALLBACK GC_pthread_start_inner(struct GC_stack_base *sb,
2785                                                    void * arg)
2786   {
2787     struct start_info * si = (struct start_info *)arg;
2788     void * result;
2789     void *(*start)(void *);
2790     void *start_arg;
2791     DWORD thread_id = GetCurrentThreadId();
2792     pthread_t pthread_id = pthread_self();
2793     GC_thread me;
2794     DCL_LOCK_STATE;
2795
2796 #   ifdef DEBUG_THREADS
2797       GC_log_printf("thread %p(0x%x) starting...\n",
2798                     (void *)GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
2799 #   endif
2800
2801     GC_ASSERT(!GC_win32_dll_threads);
2802     /* If a GC occurs before the thread is registered, that GC will     */
2803     /* ignore this thread.  That's fine, since it will block trying to  */
2804     /* acquire the allocation lock, and won't yet hold interesting      */
2805     /* pointers.                                                        */
2806     LOCK();
2807     /* We register the thread here instead of in the parent, so that    */
2808     /* we don't need to hold the allocation lock during pthread_create. */
2809     me = GC_register_my_thread_inner(sb, thread_id);
2810     SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
2811     GC_ASSERT(me != &first_thread);
2812     me -> pthread_id = pthread_id;
2813     if (si->detached) me -> flags |= DETACHED;
2814     UNLOCK();
2815
2816     start = si -> start_routine;
2817     start_arg = si -> arg;
2818
2819     GC_free(si); /* was allocated uncollectible */
2820
2821     pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
2822     result = (*start)(start_arg);
2823     me -> status = result;
2824     GC_dirty(me);
2825     pthread_cleanup_pop(1);
2826
2827 #   ifdef DEBUG_THREADS
2828       GC_log_printf("thread %p(0x%x) returned from start routine\n",
2829                     (void *)GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
2830 #   endif
2831     return(result);
2832   }
2833
2834   STATIC void * GC_pthread_start(void * arg)
2835   {
2836     return GC_call_with_stack_base(GC_pthread_start_inner, arg);
2837   }
2838
2839   STATIC void GC_thread_exit_proc(void *arg)
2840   {
2841     GC_thread me = (GC_thread)arg;
2842     DCL_LOCK_STATE;
2843
2844     GC_ASSERT(!GC_win32_dll_threads);
2845 #   ifdef DEBUG_THREADS
2846       GC_log_printf("thread %p(0x%lx) called pthread_exit()\n",
2847                     (void *)GC_PTHREAD_PTRVAL(pthread_self()),
2848                     (long)GetCurrentThreadId());
2849 #   endif
2850
2851     LOCK();
2852     GC_wait_for_gc_completion(FALSE);
2853 #   if defined(THREAD_LOCAL_ALLOC)
2854       GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
2855       GC_destroy_thread_local(&(me->tlfs));
2856 #   endif
2857     if (me -> flags & DETACHED) {
2858       GC_delete_thread(GetCurrentThreadId());
2859     } else {
2860       /* deallocate it as part of join */
2861       me -> flags |= FINISHED;
2862     }
2863 #   if defined(THREAD_LOCAL_ALLOC)
2864       /* It is required to call remove_specific defined in specific.c. */
2865       GC_remove_specific(GC_thread_key);
2866 #   endif
2867     UNLOCK();
2868   }
2869
2870 # ifndef GC_NO_PTHREAD_SIGMASK
2871     /* Win32 pthread does not support sigmask.  */
2872     /* So, nothing required here...             */
2873     GC_API int GC_pthread_sigmask(int how, const sigset_t *set,
2874                                   sigset_t *oset)
2875     {
2876       return pthread_sigmask(how, set, oset);
2877     }
2878 # endif /* !GC_NO_PTHREAD_SIGMASK */
2879
2880   GC_API int GC_pthread_detach(pthread_t thread)
2881   {
2882     int result;
2883     GC_thread t;
2884     DCL_LOCK_STATE;
2885
2886     GC_ASSERT(!GC_win32_dll_threads);
2887     /* The thread might not have registered itself yet. */
2888     /* TODO: Wait for registration of the created thread in pthread_create. */
2889     while ((t = GC_lookup_pthread(thread)) == NULL)
2890       Sleep(10);
2891     result = pthread_detach(thread);
2892     if (result == 0) {
2893       LOCK();
2894       t -> flags |= DETACHED;
2895       /* Here the pthread thread id may have been recycled. */
2896       if ((t -> flags & FINISHED) != 0) {
2897         GC_delete_gc_thread_no_free(t);
2898         GC_INTERNAL_FREE(t);
2899       }
2900       UNLOCK();
2901     }
2902     return result;
2903   }
2904
2905 #elif !defined(GC_NO_THREADS_DISCOVERY)
2906     /* We avoid acquiring locks here, since this doesn't seem to be     */
2907     /* preemptible.  This may run with an uninitialized collector, in   */
2908     /* which case we don't do much.  This implies that no threads other */
2909     /* than the main one should be created with an uninitialized        */
2910     /* collector.  (The alternative of initializing the collector here  */
2911     /* seems dangerous, since DllMain is limited in what it can do.)    */
2912
2913 # ifdef GC_INSIDE_DLL
2914     /* Export only if needed by client. */
2915     GC_API
2916 # else
2917 #   define GC_DllMain DllMain
2918 # endif
2919   BOOL WINAPI GC_DllMain(HINSTANCE inst GC_ATTR_UNUSED, ULONG reason,
2920                          LPVOID reserved GC_ATTR_UNUSED)
2921   {
2922       DWORD thread_id;
2923
2924       /* Note that GC_use_threads_discovery should be called by the     */
2925       /* client application at start-up to activate automatic thread    */
2926       /* registration (it is the default GC behavior);                  */
2927       /* to always have automatic thread registration turned on, the GC */
2928       /* should be compiled with -D GC_DISCOVER_TASK_THREADS.           */
2929       if (!GC_win32_dll_threads && parallel_initialized) return TRUE;
2930
2931       switch (reason) {
2932        case DLL_THREAD_ATTACH:
2933 #       ifdef PARALLEL_MARK
2934           /* Don't register marker threads. */
2935           if (GC_parallel) {
2936             /* We could reach here only if parallel_initialized == FALSE. */
2937             break;
2938           }
2939 #       endif
2940         /* FALLTHRU */
2941        case DLL_PROCESS_ATTACH:
2942         /* This may run with the collector uninitialized. */
2943         thread_id = GetCurrentThreadId();
2944         if (parallel_initialized && GC_main_thread != thread_id) {
2945 #         ifdef PARALLEL_MARK
2946             ABORT("Cannot initialize parallel marker from DllMain");
2947 #         else
2948             struct GC_stack_base sb;
2949             /* Don't lock here. */
2950 #           ifdef GC_ASSERTIONS
2951               int sb_result =
2952 #           endif
2953                         GC_get_stack_base(&sb);
2954             GC_ASSERT(sb_result == GC_SUCCESS);
2955             GC_register_my_thread_inner(&sb, thread_id);
2956 #         endif
2957         } /* o.w. we already did it during GC_thr_init, called by GC_init */
2958         break;
2959
2960        case DLL_THREAD_DETACH:
2961         /* We are hopefully running in the context of the exiting thread. */
2962         GC_ASSERT(parallel_initialized);
2963         if (GC_win32_dll_threads) {
2964           GC_delete_thread(GetCurrentThreadId());
2965         }
2966         break;
2967
2968        case DLL_PROCESS_DETACH:
2969         if (GC_win32_dll_threads) {
2970           int i;
2971           int my_max = (int)GC_get_max_thread_index();
2972
2973           for (i = 0; i <= my_max; ++i) {
2974            if (AO_load(&(dll_thread_table[i].tm.in_use)))
2975              GC_delete_gc_thread_no_free(&dll_thread_table[i]);
2976           }
2977           GC_deinit();
2978         }
2979         break;
2980       }
2981       return TRUE;
2982   }
2983 #endif /* !GC_NO_THREADS_DISCOVERY && !GC_PTHREADS */
2984
2985 /* Perform all initializations, including those that    */
2986 /* may require allocation.                              */
2987 /* Called without allocation lock.                      */
2988 /* Must be called before a second thread is created.    */
2989 GC_INNER void GC_init_parallel(void)
2990 {
2991 # if defined(THREAD_LOCAL_ALLOC)
2992     GC_thread me;
2993     DCL_LOCK_STATE;
2994 # endif
2995
2996   if (parallel_initialized) return;
2997   parallel_initialized = TRUE;
2998   /* GC_init() calls us back, so set flag first.      */
2999
3000   if (!GC_is_initialized) GC_init();
3001 # if defined(CPPCHECK) && !defined(GC_NO_THREADS_DISCOVERY)
3002     GC_noop1((word)&GC_DllMain);
3003 # endif
3004   if (GC_win32_dll_threads) {
3005     set_need_to_lock();
3006         /* Cannot intercept thread creation.  Hence we don't know if    */
3007         /* other threads exist.  However, client is not allowed to      */
3008         /* create other threads before collector initialization.        */
3009         /* Thus it's OK not to lock before this.                        */
3010   }
3011   /* Initialize thread local free lists if used.        */
3012 # if defined(THREAD_LOCAL_ALLOC)
3013     LOCK();
3014     me = GC_lookup_thread_inner(GetCurrentThreadId());
3015     CHECK_LOOKUP_MY_THREAD(me);
3016     GC_init_thread_local(&me->tlfs);
3017     UNLOCK();
3018 # endif
3019 }
3020
3021 #if defined(USE_PTHREAD_LOCKS)
3022   /* Support for pthread locking code.          */
3023   /* pthread_mutex_trylock may not win here,    */
3024   /* due to builtin support for spinning first? */
3025
3026   GC_INNER void GC_lock(void)
3027   {
3028     pthread_mutex_lock(&GC_allocate_ml);
3029   }
3030 #endif /* USE_PTHREAD_LOCKS */
3031
3032 #if defined(THREAD_LOCAL_ALLOC)
3033
3034   /* Add thread-local allocation support.  VC++ uses __declspec(thread).  */
3035
3036   /* We must explicitly mark ptrfree and gcj free lists, since the free   */
3037   /* list links wouldn't otherwise be found.  We also set them in the     */
3038   /* normal free lists, since that involves touching less memory than if  */
3039   /* we scanned them normally.                                            */
3040   GC_INNER void GC_mark_thread_local_free_lists(void)
3041   {
3042     int i;
3043     GC_thread p;
3044
3045     for (i = 0; i < THREAD_TABLE_SZ; ++i) {
3046       for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
3047         if (!KNOWN_FINISHED(p)) {
3048 #         ifdef DEBUG_THREADS
3049             GC_log_printf("Marking thread locals for 0x%x\n", (int)p -> id);
3050 #         endif
3051           GC_mark_thread_local_fls_for(&(p->tlfs));
3052         }
3053       }
3054     }
3055   }
3056
3057 # if defined(GC_ASSERTIONS)
3058     /* Check that all thread-local free-lists are completely marked.    */
3059     /* also check that thread-specific-data structures are marked.      */
3060     void GC_check_tls(void)
3061     {
3062         int i;
3063         GC_thread p;
3064
3065         for (i = 0; i < THREAD_TABLE_SZ; ++i) {
3066           for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
3067             if (!KNOWN_FINISHED(p))
3068               GC_check_tls_for(&(p->tlfs));
3069           }
3070         }
3071 #       if defined(USE_CUSTOM_SPECIFIC)
3072           if (GC_thread_key != 0)
3073             GC_check_tsd_marks(GC_thread_key);
3074 #       endif
3075     }
3076 # endif /* GC_ASSERTIONS */
3077
3078 #endif /* THREAD_LOCAL_ALLOC ... */
3079
3080 # ifndef GC_NO_THREAD_REDIRECTS
3081     /* Restore thread calls redirection.        */
3082 #   define CreateThread GC_CreateThread
3083 #   define ExitThread GC_ExitThread
3084 #   undef _beginthreadex
3085 #   define _beginthreadex GC_beginthreadex
3086 #   undef _endthreadex
3087 #   define _endthreadex GC_endthreadex
3088 # endif /* !GC_NO_THREAD_REDIRECTS */
3089
3090 #endif /* GC_WIN32_THREADS */