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