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