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