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