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