e422e66ff0f0c7f49bee3bb41ca8be634c403b0b
[cacao.git] / src / mm / boehm-gc / win32_threads.c
1 #include "config.h"
2 #include "private/gc_priv.h"
3
4 #if defined(GC_WIN32_THREADS)
5
6 #include <windows.h>
7
8 #ifdef THREAD_LOCAL_ALLOC
9 # include "private/thread_local_alloc.h"
10 #endif /* THREAD_LOCAL_ALLOC */
11
12 /* Allocation lock declarations.        */
13 #if !defined(USE_PTHREAD_LOCKS)
14 # if defined(GC_DLL)
15     __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
16 # else
17     CRITICAL_SECTION GC_allocate_ml;
18 # endif
19   DWORD GC_lock_holder = NO_THREAD;
20         /* Thread id for current holder of allocation lock */
21 #else
22   pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
23   unsigned long GC_lock_holder = NO_THREAD;
24 #endif
25
26 #ifdef GC_PTHREADS
27 # include <errno.h>
28
29 /* GC_DLL should not normally be defined, especially since we often do turn */
30 /* on THREAD_LOCAL_ALLOC, which is currently incompatible.                  */
31 /* It might be possible to get GC_DLL and DllMain-based thread registration */
32 /* to work with Cygwin, but if you try you are on your own.                 */
33 #ifdef GC_DLL
34 # error GC_DLL untested with Cygwin
35 #endif
36
37  /* Cygwin-specific forward decls */
38 # undef pthread_create 
39 # undef pthread_sigmask 
40 # undef pthread_join 
41 # undef pthread_detach
42 # undef dlopen 
43
44 # ifdef DEBUG_THREADS
45 #   ifdef CYGWIN32
46 #     define DEBUG_CYGWIN_THREADS 1
47 #     define DEBUG_WIN32_PTHREADS 0
48 #   else
49 #     define DEBUG_WIN32_PTHREADS 1
50 #     define DEBUG_CYGWIN_THREADS 0
51 #   endif
52 # else
53 #   define DEBUG_CYGWIN_THREADS 0
54 #   define DEBUG_WIN32_PTHREADS 0
55 # endif
56
57   void * GC_pthread_start(void * arg);
58   void GC_thread_exit_proc(void *arg);
59
60 # include <pthread.h>
61
62 #else
63
64 # ifdef DEBUG_THREADS
65 #   define DEBUG_WIN32_THREADS 1
66 # else
67 #   define DEBUG_WIN32_THREADS 0
68 # endif
69
70 # undef CreateThread
71 # undef ExitThread
72 # undef _beginthreadex
73 # undef _endthreadex
74 # undef _beginthread
75 # ifdef DEBUG_THREADS
76 #   define DEBUG_WIN32_THREADS 1
77 # else
78 #   define DEBUG_WIN32_THREADS 0
79 # endif
80
81 # include <process.h>  /* For _beginthreadex, _endthreadex */
82
83 #endif
84
85 #if defined(GC_DLL) && !defined(MSWINCE)
86   static GC_bool GC_win32_dll_threads = FALSE;
87   /* This code operates in two distinct modes, depending on     */
88   /* the setting of GC_win32_dll_threads.  If                   */
89   /* GC_win32_dll_threads is set, all threads in the process    */
90   /* are implicitly registered with the GC by DllMain.          */
91   /* No explicit registration is required, and attempts at      */
92   /* explicit registration are ignored.  This mode is           */
93   /* very different from the Posix operation of the collector.  */
94   /* In this mode access to the thread table is lock-free.      */
95   /* Hence there is a static limit on the number of threads.    */
96   
97   /* If GC_win32_dll_threads is FALSE, or the collector is      */
98   /* built without GC_DLL defined, things operate in a way      */
99   /* that is very similar to Posix platforms, and new threads   */
100   /* must be registered with the collector, e.g. by using       */
101   /* preprocessor-based interception of the thread primitives.  */
102   /* In this case, we use a real data structure for the thread  */
103   /* table.  Note that there is no equivalent of linker-based   */
104   /* call interception, since we don't have ELF-like            */
105   /* facilities.  The Windows analog appears to be "API         */
106   /* hooking", which really seems to be a standard way to       */
107   /* do minor binary rewriting (?).  I'd prefer not to have     */
108   /* the basic collector rely on such facilities, but an        */
109   /* optional package that intercepts thread calls this way     */
110   /* would probably be nice.                                    */
111
112   /* GC_win32_dll_threads must be set at initialization time,   */
113   /* i.e. before any collector or thread calls.  We make it a   */
114   /* "dynamic" option only to avoid multiple library versions.  */
115 #else
116 # define GC_win32_dll_threads FALSE
117 #endif
118
119 /* We have two versions of the thread table.  Which one */
120 /* we us depends on whether or not GC_win32_dll_threads */
121 /* is set.  Note that before initialization, we don't   */
122 /* add any entries to either table, even if DllMain is  */
123 /* called.  The main thread will be added on            */
124 /* initialization.                                      */
125
126 /* The type of the first argument to InterlockedExchange.       */
127 /* Documented to be LONG volatile *, but at least gcc likes     */
128 /* this better.                                                 */
129 typedef LONG * IE_t;
130
131 GC_bool GC_thr_initialized = FALSE;
132
133 GC_bool GC_need_to_lock = FALSE;
134
135 static GC_bool parallel_initialized = FALSE;
136
137 void GC_init_parallel(void);
138
139 #ifdef GC_DLL
140   /* Turn on GC_win32_dll_threads       */
141   GC_API void GC_use_DllMain(void)
142   {
143 #     ifdef THREAD_LOCAL_ALLOC
144           ABORT("Cannot use thread local allocation with DllMain-based "
145                 "thread registration.");
146           /* Thread-local allocation really wants to lock at thread     */
147           /* entry and exit.                                            */
148 #     endif
149       GC_ASSERT(!parallel_initialized);
150       GC_win32_dll_threads = TRUE;
151       GC_init_parallel();
152   }
153 #else
154   GC_API void GC_use_DllMain(void)
155   {
156       ABORT("GC not configured as DLL");
157   }
158 #endif
159
160 DWORD GC_main_thread = 0;
161
162 struct GC_Thread_Rep {
163   union {
164     AO_t tm_in_use;     /* Updated without lock.                */
165                         /* We assert that unused                */
166                         /* entries have invalid ids of          */
167                         /* zero and zero stack fields.          */
168                         /* Used only with GC_win32_dll_threads. */
169     struct GC_Thread_Rep * tm_next;
170                         /* Hash table link without              */
171                         /* GC_win32_dll_threads.                */
172                         /* More recently allocated threads      */
173                         /* with a given pthread id come         */
174                         /* first.  (All but the first are       */
175                         /* guaranteed to be dead, but we may    */
176                         /* not yet have registered the join.)   */
177   } table_management;
178 # define in_use table_management.tm_in_use
179 # define next table_management.tm_next
180   DWORD id;
181   HANDLE handle;
182   ptr_t stack_base;     /* The cold end of the stack.   */
183                         /* 0 ==> entry not valid.       */
184                         /* !in_use ==> stack_base == 0  */
185   GC_bool suspended;
186
187 # ifdef GC_PTHREADS
188     void *status; /* hold exit value until join in case it's a pointer */
189     pthread_t pthread_id;
190     short flags;                /* Protected by GC lock.        */
191 #       define FINISHED 1       /* Thread has exited.   */
192 #       define DETACHED 2       /* Thread is intended to be detached.   */
193 #   define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
194 # else
195 #   define KNOWN_FINISHED(t) 0
196 # endif
197 # ifdef THREAD_LOCAL_ALLOC
198     struct thread_local_freelists tlfs;
199 # endif
200 };
201
202 typedef struct GC_Thread_Rep * GC_thread;
203 typedef volatile struct GC_Thread_Rep * GC_vthread;
204
205 /*
206  * We assumed that volatile ==> memory ordering, at least among
207  * volatiles.  This code should consistently use atomic_ops.
208  */
209
210 volatile GC_bool GC_please_stop = FALSE;
211
212 /*
213  * We track thread attachments while the world is supposed to be stopped.
214  * Unfortunately, we can't stop them from starting, since blocking in
215  * DllMain seems to cause the world to deadlock.  Thus we have to recover
216  * If we notice this in the middle of marking.
217  */
218
219 AO_t GC_attached_thread = FALSE;
220 /* Return TRUE if an thread was attached since we last asked or */
221 /* since GC_attached_thread was explicitly reset.               */
222 GC_bool GC_started_thread_while_stopped(void)
223 {
224   AO_t result;
225
226   if (GC_win32_dll_threads) {
227     AO_nop_full();      /* Prior heap reads need to complete earlier. */
228     result = AO_load(&GC_attached_thread);
229     if (result) {
230       AO_store(&GC_attached_thread, FALSE);
231     }
232     return ((GC_bool)result);
233   } else {
234     return FALSE;
235   }
236 }
237
238 /* Thread table used if GC_win32_dll_threads is set.    */
239 /* This is a fixed size array.                          */
240 /* Since we use runtime conditionals, both versions     */
241 /* are always defined.                                  */
242 # ifndef MAX_THREADS
243 #   define MAX_THREADS 512
244 #  endif
245   /* Things may get quite slow for large numbers of threads,    */
246   /* since we look them up with sequential search.              */
247
248   volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
249
250   volatile LONG GC_max_thread_index = 0;
251                         /* Largest index in dll_thread_table    */
252                         /* that was ever used.                  */
253
254 /* And now the version used if GC_win32_dll_threads is not set. */
255 /* This is a chained hash table, with much of the code borrowed */
256 /* From the Posix implementation.                               */
257 # define THREAD_TABLE_SZ 256    /* Must be power of 2   */
258   GC_thread GC_threads[THREAD_TABLE_SZ];
259   
260
261 /* Add a thread to GC_threads.  We assume it wasn't already there.      */
262 /* Caller holds allocation lock.                                        */
263 /* Unlike the pthreads version, the id field is set by the caller.      */
264 GC_thread GC_new_thread(DWORD id)
265 {
266     word hv = ((word)id) % THREAD_TABLE_SZ;
267     GC_thread result;
268     /* It may not be safe to allocate when we register the first thread. */
269     static struct GC_Thread_Rep first_thread;
270     static GC_bool first_thread_used = FALSE;
271     
272     GC_ASSERT(I_HOLD_LOCK());
273     if (!first_thread_used) {
274         result = &first_thread;
275         first_thread_used = TRUE;
276     } else {
277         GC_ASSERT(!GC_win32_dll_threads);
278         result = (struct GC_Thread_Rep *)
279                  GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
280 #       ifdef GC_PTHREADS
281           /* result can be NULL -> segfault */
282           GC_ASSERT(result -> flags == 0);
283 #       endif
284     }
285     if (result == 0) return(0);
286     /* result -> id = id; Done by caller.       */
287     result -> next = GC_threads[hv];
288     GC_threads[hv] = result;
289 #   ifdef GC_PTHREADS
290       GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);
291 #   endif
292     return(result);
293 }
294
295 extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
296
297 #if defined(GWW_VDB) && defined(MPROTECT_VDB)
298   extern GC_bool GC_gww_dirty_init(void);
299   /* Defined in os_dep.c.  Returns TRUE if GetWriteWatch is available.  */
300   /* may be called repeatedly.                                          */
301 #endif
302
303 GC_bool GC_in_thread_creation = FALSE;  /* Protected by allocation lock. */
304
305 /*
306  * This may be called from DllMain, and hence operates under unusual
307  * constraints.  In particular, it must be lock-free if GC_win32_dll_threads
308  * is set.  Always called from the thread being added.
309  * If GC_win32_dll_threads is not set, we already hold the allocation lock,
310  * except possibly during single-threaded start-up code.
311  */
312 static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
313                                              DWORD thread_id)
314 {
315   GC_vthread me;
316
317   /* The following should be a noop according to the win32      */
318   /* documentation.  There is empirical evidence that it        */
319   /* isn't.             - HB                                    */
320 # if defined(MPROTECT_VDB)
321 #   if defined(GWW_VDB)
322       if (GC_incremental && !GC_gww_dirty_init())
323         SetUnhandledExceptionFilter(GC_write_fault_handler);
324 #   else
325       if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
326 #   endif
327 # endif
328
329   if (GC_win32_dll_threads) {
330     int i;
331     /* It appears to be unsafe to acquire a lock here, since this       */
332     /* code is apparently not preeemptible on some systems.             */
333     /* (This is based on complaints, not on Microsoft's official        */
334     /* documentation, which says this should perform "only simple       */
335     /* initialization tasks".)                                          */
336     /* Hence we make do with nonblocking synchronization.               */
337     /* It has been claimed that DllMain is really only executed with    */
338     /* a particular system lock held, and thus careful use of locking   */
339     /* around code that doesn't call back into the system libraries     */
340     /* might be OK.  But this hasn't been tested across all win32       */
341     /* variants.                                                        */
342                 /* cast away volatile qualifier */
343     for (i = 0; InterlockedExchange((IE_t)&dll_thread_table[i].in_use,1) != 0;
344          i++) {
345       /* Compare-and-swap would make this cleaner, but that's not       */
346       /* supported before Windows 98 and NT 4.0.  In Windows 2000,      */
347       /* InterlockedExchange is supposed to be replaced by              */
348       /* InterlockedExchangePointer, but that's not really what I       */
349       /* want here.                                                     */
350       /* FIXME: We should eventually declare Win95 dead and use AO_     */
351       /* primitives here.                                               */
352       if (i == MAX_THREADS - 1)
353         ABORT("too many threads");
354     }
355     /* Update GC_max_thread_index if necessary.  The following is safe, */
356     /* and unlike CompareExchange-based solutions seems to work on all  */
357     /* Windows95 and later platforms.                                   */
358     /* Unfortunately, GC_max_thread_index may be temporarily out of     */
359     /* bounds, so readers have to compensate.                           */
360     while (i > GC_max_thread_index) {
361       InterlockedIncrement((IE_t)&GC_max_thread_index);
362     }
363     if (GC_max_thread_index >= MAX_THREADS) {
364       /* We overshot due to simultaneous increments.    */
365       /* Setting it to MAX_THREADS-1 is always safe.    */
366       GC_max_thread_index = MAX_THREADS - 1;
367     }
368     me = dll_thread_table + i;
369   } else /* Not using DllMain */ {
370     GC_ASSERT(I_HOLD_LOCK());
371     GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
372     me = GC_new_thread(thread_id);
373     GC_in_thread_creation = FALSE;
374   }
375 # ifdef GC_PTHREADS
376     /* me can be NULL -> segfault */
377     me -> pthread_id = pthread_self();
378 # endif
379
380   if (!DuplicateHandle(GetCurrentProcess(),
381                         GetCurrentThread(),
382                         GetCurrentProcess(),
383                         (HANDLE*)&(me -> handle),
384                         0,
385                         0,
386                         DUPLICATE_SAME_ACCESS)) {
387         DWORD last_error = GetLastError();
388         GC_err_printf("Last error code: %d\n", last_error);
389         ABORT("DuplicateHandle failed");
390   }
391   me -> stack_base = sb -> mem_base;
392   /* Up until this point, GC_push_all_stacks considers this thread      */
393   /* invalid.                                                           */
394   /* Up until this point, this entry is viewed as reserved but invalid  */
395   /* by GC_delete_thread.                                               */
396   me -> id = thread_id;
397 # if defined(THREAD_LOCAL_ALLOC)
398       GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
399 # endif
400   if (me -> stack_base == NULL) 
401       ABORT("Bad stack base in GC_register_my_thread_inner");
402   if (GC_win32_dll_threads) {
403     if (GC_please_stop) {
404       AO_store(&GC_attached_thread, TRUE);
405       AO_nop_full();  // Later updates must become visible after this.
406     }
407     /* We'd like to wait here, but can't, since waiting in DllMain      */
408     /* provokes deadlocks.                                              */
409     /* Thus we force marking to be restarted instead.                   */
410   } else {
411     GC_ASSERT(!GC_please_stop);
412         /* Otherwise both we and the thread stopping code would be      */
413         /* holding the allocation lock.                                 */
414   }
415   return (GC_thread)(me);
416 }
417
418 /*
419  * GC_max_thread_index may temporarily be larger than MAX_THREADS.
420  * To avoid subscript errors, we check on access.
421  */
422 #ifdef __GNUC__
423 __inline__
424 #endif
425 LONG GC_get_max_thread_index()
426 {
427   LONG my_max = GC_max_thread_index;
428
429   if (my_max >= MAX_THREADS) return MAX_THREADS-1;
430   return my_max;
431 }
432
433 /* Return the GC_thread corresponding to a thread id.  May be called    */
434 /* without a lock, but should be called in contexts in which the        */
435 /* requested thread cannot be asynchronously deleted, e.g. from the     */
436 /* thread itself.                                                       */
437 /* This version assumes that either GC_win32_dll_threads is set, or     */
438 /* we hold the allocator lock.                                          */
439 /* Also used (for assertion checking only) from thread_local_alloc.c.   */
440 GC_thread GC_lookup_thread_inner(DWORD thread_id) {
441   if (GC_win32_dll_threads) {
442     int i;
443     LONG my_max = GC_get_max_thread_index();
444     for (i = 0;
445        i <= my_max &&
446        (!AO_load_acquire(&(dll_thread_table[i].in_use))
447         || dll_thread_table[i].id != thread_id);
448        /* Must still be in_use, since nobody else can store our thread_id. */
449        i++) {}
450     if (i > my_max) {
451       return 0;
452     } else {
453       return (GC_thread)(dll_thread_table + i);
454     }
455   } else {
456     word hv = ((word)thread_id) % THREAD_TABLE_SZ;
457     register GC_thread p = GC_threads[hv];
458     
459     GC_ASSERT(I_HOLD_LOCK());
460     while (p != 0 && p -> id != thread_id) p = p -> next;
461     return(p);
462   }
463 }
464
465 /* A version of the above that acquires the lock if necessary.  Note    */
466 /* that the identically named function for pthreads is different, and   */
467 /* just assumes we hold the lock.                                       */
468 /* Also used (for assertion checking only) from thread_local_alloc.c.   */
469 static GC_thread GC_lookup_thread(DWORD thread_id)
470 {
471   if (GC_win32_dll_threads) {
472     return GC_lookup_thread_inner(thread_id);
473   } else {
474     GC_thread result;
475     LOCK();
476     result = GC_lookup_thread_inner(thread_id);
477     UNLOCK();
478     return result;
479   }
480 }
481
482 /* If a thread has been joined, but we have not yet             */
483 /* been notified, then there may be more than one thread        */
484 /* in the table with the same win32 id.                         */
485 /* This is OK, but we need a way to delete a specific one.      */
486 /* Assumes we hold the allocation lock unless                   */
487 /* GC_win32_dll_threads is set.                                 */
488 /* If GC_win32_dll_threads is set it should be called from the  */
489 /* thread being deleted.                                        */
490 void GC_delete_gc_thread(GC_vthread gc_id)
491 {
492   CloseHandle(gc_id->handle);
493   if (GC_win32_dll_threads) {
494     /* This is intended to be lock-free.                                */
495     /* It is either called synchronously from the thread being deleted, */
496     /* or by the joining thread.                                        */
497     /* In this branch asynchronosu changes to *gc_id are possible.      */
498     gc_id -> stack_base = 0;
499     gc_id -> id = 0;
500 #   ifdef CYGWIN32
501       gc_id -> pthread_id = 0;
502 #   endif /* CYGWIN32 */
503 #   ifdef GC_WIN32_PTHREADS
504       gc_id -> pthread_id.p = NULL;
505 #   endif /* GC_WIN32_PTHREADS */
506     AO_store_release(&(gc_id->in_use), FALSE);
507   } else {
508     /* Cast away volatile qualifier, since we have lock. */
509     GC_thread gc_nvid = (GC_thread)gc_id;
510     DWORD id = gc_nvid -> id;
511     word hv = ((word)id) % THREAD_TABLE_SZ;
512     register GC_thread p = GC_threads[hv];
513     register GC_thread prev = 0;
514
515     GC_ASSERT(I_HOLD_LOCK());
516     while (p != gc_nvid) {
517         prev = p;
518         p = p -> next;
519     }
520     if (prev == 0) {
521         GC_threads[hv] = p -> next;
522     } else {
523         prev -> next = p -> next;
524     }
525     GC_INTERNAL_FREE(p);
526   }
527 }
528
529 /* Delete a thread from GC_threads.  We assume it is there.     */
530 /* (The code intentionally traps if it wasn't.)                 */
531 /* Assumes we hold the allocation lock unless                   */
532 /* GC_win32_dll_threads is set.                                 */
533 /* If GC_win32_dll_threads is set it should be called from the  */
534 /* thread being deleted.                                        */
535 void GC_delete_thread(DWORD id)
536 {
537   if (GC_win32_dll_threads) {
538     GC_thread t = GC_lookup_thread_inner(id);
539
540     if (0 == t) {
541       WARN("Removing nonexistent thread %ld\n", (GC_word)id);
542     } else {
543       GC_delete_gc_thread(t);
544     }
545   } else {
546     word hv = ((word)id) % THREAD_TABLE_SZ;
547     register GC_thread p = GC_threads[hv];
548     register GC_thread prev = 0;
549     
550     GC_ASSERT(I_HOLD_LOCK());
551     while (p -> id != id) {
552         prev = p;
553         p = p -> next;
554     }
555     CloseHandle(p->handle);
556     if (prev == 0) {
557         GC_threads[hv] = p -> next;
558     } else {
559         prev -> next = p -> next;
560     }
561     GC_INTERNAL_FREE(p);
562   }
563 }
564
565 GC_API int GC_register_my_thread(struct GC_stack_base *sb) {
566   DWORD t = GetCurrentThreadId();
567
568   if (0 == GC_lookup_thread(t)) {
569     /* We lock here, since we want to wait for an ongoing GC.   */
570     LOCK();
571     GC_register_my_thread_inner(sb, t);
572     UNLOCK();
573     return GC_SUCCESS;
574   } else {
575     return GC_DUPLICATE;
576   }
577 }
578
579 GC_API int GC_unregister_my_thread(void)
580 {
581     DWORD t = GetCurrentThreadId();
582
583 #   if defined(THREAD_LOCAL_ALLOC)
584       LOCK();
585       {
586         GC_thread me = GC_lookup_thread_inner(t);
587         GC_destroy_thread_local(&(me->tlfs));
588       }
589       UNLOCK();
590 #   endif
591     if (GC_win32_dll_threads) {
592       /* Should we just ignore this? */
593       GC_delete_thread(t);
594     } else {
595       LOCK();
596       GC_delete_thread(t);
597       UNLOCK();
598     }
599     return GC_SUCCESS;
600 }
601
602
603 #ifdef GC_PTHREADS
604
605 /* A quick-and-dirty cache of the mapping between pthread_t     */
606 /* and win32 thread id.                                         */
607 #define PTHREAD_MAP_SIZE 512
608 DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE];
609 #define HASH(pthread_id) ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
610         /* It appears pthread_t is really a pointer type ... */
611 #define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
612         GC_pthread_map_cache[HASH(pthread_id)] = (win32_id);
613 #define GET_PTHREAD_MAP_CACHE(pthread_id) \
614         GC_pthread_map_cache[HASH(pthread_id)]
615
616 /* Return a GC_thread corresponding to a given pthread_t.       */
617 /* Returns 0 if it's not there.                                 */
618 /* We assume that this is only called for pthread ids that      */
619 /* have not yet terminated or are still joinable, and           */
620 /* cannot be concurrently terminated.                           */
621 /* Assumes we do NOT hold the allocation lock.                  */
622 static GC_thread GC_lookup_pthread(pthread_t id)
623 {
624   if (GC_win32_dll_threads) {
625     int i;
626     LONG my_max = GC_get_max_thread_index();
627
628     for (i = 0;
629          i <= my_max &&
630          (!AO_load_acquire(&(dll_thread_table[i].in_use))
631           || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
632        /* Must still be in_use, since nobody else can store our thread_id. */
633        i++);
634     if (i > my_max) return 0;
635     return (GC_thread)(dll_thread_table + i);
636   } else {
637     /* We first try the cache.  If that fails, we use a very slow       */
638     /* approach.                                                        */
639     int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ;
640     int hv;
641     GC_thread p;
642
643     LOCK();
644     for (p = GC_threads[hv_guess]; 0 != p; p = p -> next) {
645       if (THREAD_EQUAL(p -> pthread_id, id))
646         goto foundit; 
647     }
648     for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
649       for (p = GC_threads[hv]; 0 != p; p = p -> next) {
650         if (THREAD_EQUAL(p -> pthread_id, id))
651           goto foundit; 
652       }
653     }
654     p = 0;
655    foundit:
656     UNLOCK();
657     return p;
658   }
659 }
660
661 #endif /* GC_PTHREADS */
662
663 void GC_push_thread_structures(void)
664 {
665   GC_ASSERT(I_HOLD_LOCK());
666   if (GC_win32_dll_threads) {
667     /* Unlike the other threads implementations, the thread table here  */
668     /* contains no pointers to the collectable heap.  Thus we have      */
669     /* no private structures we need to preserve.                       */
670 #   ifdef GC_PTHREADS 
671     { int i; /* pthreads may keep a pointer in the thread exit value */
672       LONG my_max = GC_get_max_thread_index();
673
674       for (i = 0; i <= my_max; i++)
675         if (dll_thread_table[i].in_use)
676           GC_push_all((ptr_t)&(dll_thread_table[i].status),
677                       (ptr_t)(&(dll_thread_table[i].status)+1));
678     }
679 #   endif
680   } else {
681     GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
682   }
683 # if defined(THREAD_LOCAL_ALLOC)
684     GC_push_all((ptr_t)(&GC_thread_key),
685       (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
686     /* Just in case we ever use our own TLS implementation.     */
687 # endif
688 }
689
690 /* Suspend the given thread, if it's still active.      */
691 void GC_suspend(GC_thread t)
692 {
693 # ifdef MSWINCE
694     /* SuspendThread will fail if thread is running kernel code */
695       while (SuspendThread(t -> handle) == (DWORD)-1)
696         Sleep(10);
697 # else
698     /* Apparently the Windows 95 GetOpenFileName call creates   */
699     /* a thread that does not properly get cleaned up, and              */
700     /* SuspendThread on its descriptor may provoke a crash.             */
701     /* This reduces the probability of that event, though it still      */
702     /* appears there's a race here.                                     */
703     DWORD exitCode; 
704     if (GetExitCodeThread(t -> handle, &exitCode) &&
705         exitCode != STILL_ACTIVE) {
706       t -> stack_base = 0; /* prevent stack from being pushed */
707 #     ifndef GC_PTHREADS
708         /* this breaks pthread_join on Cygwin, which is guaranteed to  */
709         /* only see user pthreads                                      */
710         GC_ASSERT(GC_win32_dll_threads);
711         GC_delete_gc_thread(t);
712 #     endif
713       return;
714     }
715     if (SuspendThread(t -> handle) == (DWORD)-1)
716       ABORT("SuspendThread failed");
717 # endif
718    t -> suspended = TRUE;
719 }
720
721 /* Defined in misc.c */
722 #ifndef CYGWIN32
723   extern CRITICAL_SECTION GC_write_cs;
724 #endif
725
726 void GC_stop_world(void)
727 {
728   DWORD thread_id = GetCurrentThreadId();
729   int i;
730
731   if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
732   GC_ASSERT(I_HOLD_LOCK());
733
734   GC_please_stop = TRUE;
735 # ifndef CYGWIN32
736     EnterCriticalSection(&GC_write_cs);
737 # endif
738   if (GC_win32_dll_threads) {
739     /* Any threads being created during this loop will end up setting   */
740     /* GC_attached_thread when they start.  This will force marking to  */
741     /* restart.                                                         */
742     /* This is not ideal, but hopefully correct.                        */
743     GC_attached_thread = FALSE;
744     for (i = 0; i <= GC_get_max_thread_index(); i++) {
745       GC_vthread t = dll_thread_table + i;
746       if (t -> stack_base != 0
747           && t -> id != thread_id) {
748           GC_suspend((GC_thread)t);
749       }
750     }
751   } else {
752       GC_thread t;
753       int i;
754
755       for (i = 0; i < THREAD_TABLE_SZ; i++) {
756         for (t = GC_threads[i]; t != 0; t = t -> next) {
757           if (t -> stack_base != 0
758           && !KNOWN_FINISHED(t)
759           && t -> id != thread_id) {
760             GC_suspend(t);
761           }
762         }
763       }
764   }
765 # ifndef CYGWIN32
766     LeaveCriticalSection(&GC_write_cs);
767 # endif    
768 }
769
770 void GC_start_world(void)
771 {
772   DWORD thread_id = GetCurrentThreadId();
773   int i;
774   LONG my_max = GC_get_max_thread_index();
775
776   GC_ASSERT(I_HOLD_LOCK());
777   if (GC_win32_dll_threads) {
778     for (i = 0; i <= my_max; i++) {
779       GC_thread t = (GC_thread)(dll_thread_table + i);
780       if (t -> stack_base != 0 && t -> suspended
781           && t -> id != thread_id) {
782         if (ResumeThread(t -> handle) == (DWORD)-1)
783           ABORT("ResumeThread failed");
784         t -> suspended = FALSE;
785       }
786     }
787   } else {
788     GC_thread t;
789     int i;
790
791     for (i = 0; i < THREAD_TABLE_SZ; i++) {
792       for (t = GC_threads[i]; t != 0; t = t -> next) {
793         if (t -> stack_base != 0 && t -> suspended
794             && t -> id != thread_id) {
795           if (ResumeThread(t -> handle) == (DWORD)-1)
796             ABORT("ResumeThread failed");
797           t -> suspended = FALSE;
798         }
799       }
800     }
801   }
802   GC_please_stop = FALSE;
803 }
804
805 # ifdef MSWINCE
806     /* The VirtualQuery calls below won't work properly on WinCE, but   */
807     /* since each stack is restricted to an aligned 64K region of       */
808     /* virtual memory we can just take the next lowest multiple of 64K. */
809 #   define GC_get_stack_min(s) \
810         ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
811 # else
812     static ptr_t GC_get_stack_min(ptr_t s)
813     {
814         ptr_t bottom;
815         MEMORY_BASIC_INFORMATION info;
816         VirtualQuery(s, &info, sizeof(info));
817         do {
818             bottom = info.BaseAddress;
819             VirtualQuery(bottom - 1, &info, sizeof(info));
820         } while ((info.Protect & PAGE_READWRITE)
821                  && !(info.Protect & PAGE_GUARD));
822         return(bottom);
823     }
824 # endif
825
826 void GC_push_stack_for(GC_thread thread)
827 {
828     int dummy;
829     ptr_t sp, stack_min;
830     DWORD me = GetCurrentThreadId();
831
832     if (thread -> stack_base) {
833       if (thread -> id == me) {
834         sp = (ptr_t) &dummy;
835       } else {
836         CONTEXT context;
837         context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
838         if (!GetThreadContext(thread -> handle, &context))
839           ABORT("GetThreadContext failed");
840
841         /* Push all registers that might point into the heap.  Frame    */
842         /* pointer registers are included in case client code was       */
843         /* compiled with the 'omit frame pointer' optimisation.         */
844 #       define PUSH1(reg) GC_push_one((word)context.reg)
845 #       define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
846 #       define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
847 #       if defined(I386)
848           PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
849           sp = (ptr_t)context.Esp;
850 #       elif defined(X86_64)
851           PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
852           PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
853           sp = (ptr_t)context.Rsp;
854 #       elif defined(ARM32)
855           PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
856           sp = (ptr_t)context.Sp;
857 #       elif defined(SHx)
858           PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
859           PUSH2(R12,R13), PUSH1(R14);
860           sp = (ptr_t)context.R15;
861 #       elif defined(MIPS)
862           PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
863           PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
864           PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
865           PUSH4(IntT9,IntK0,IntK1,IntS8);
866           sp = (ptr_t)context.IntSp;
867 #       elif defined(PPC)
868           PUSH4(Gpr0, Gpr3, Gpr4, Gpr5),  PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
869           PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
870           PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
871           PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
872           sp = (ptr_t)context.Gpr1;
873 #       elif defined(ALPHA)
874           PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
875           PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
876           PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
877           PUSH4(IntT10,IntT11,IntT12,IntAt);
878           sp = (ptr_t)context.IntSp;
879 #       else
880 #         error "architecture is not supported"
881 #       endif
882       } /* ! current thread */
883
884       stack_min = GC_get_stack_min(thread->stack_base);
885
886       if (sp >= stack_min && sp < thread->stack_base) {
887 #       if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \
888            || DEBUG_CYGWIN_THREADS
889           GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n",
890                     sp, thread -> stack_base, thread -> id, me);
891 #       endif
892         GC_push_all_stack(sp, thread->stack_base);
893       } else {
894         WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
895              (unsigned long)(size_t)sp);
896         GC_push_all_stack(stack_min, thread->stack_base);
897       }
898     } /* thread looks live */
899 }
900
901 void GC_push_all_stacks(void)
902 {
903   DWORD me = GetCurrentThreadId();
904   GC_bool found_me = FALSE;
905   size_t nthreads = 0;
906   
907   if (GC_win32_dll_threads) {
908     int i;
909     LONG my_max = GC_get_max_thread_index();
910
911     for (i = 0; i <= my_max; i++) {
912       GC_thread t = (GC_thread)(dll_thread_table + i);
913       if (t -> in_use) {
914         ++nthreads;
915         GC_push_stack_for(t);
916         if (t -> id == me) found_me = TRUE;
917       }
918     }
919   } else {
920     GC_thread t;
921     int i;
922
923     for (i = 0; i < THREAD_TABLE_SZ; i++) {
924       for (t = GC_threads[i]; t != 0; t = t -> next) {
925         ++nthreads;
926         if (!KNOWN_FINISHED(t)) GC_push_stack_for(t);
927         if (t -> id == me) found_me = TRUE;
928       }
929     }
930   }
931   if (GC_print_stats == VERBOSE) {
932     GC_log_printf("Pushed %d thread stacks ", nthreads);
933     if (GC_win32_dll_threads) {
934         GC_log_printf("based on DllMain thread tracking\n");
935     } else {
936         GC_log_printf("\n");
937     }
938   }
939   if (!found_me && !GC_in_thread_creation)
940     ABORT("Collecting from unknown thread.");
941 }
942
943 void GC_get_next_stack(char *start, char **lo, char **hi)
944 {
945     int i;
946 #   define ADDR_LIMIT (char *)(-1L)
947     char * current_min = ADDR_LIMIT;
948
949     if (GC_win32_dll_threads) {
950       LONG my_max = GC_get_max_thread_index();
951   
952       for (i = 0; i <= my_max; i++) {
953         ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
954
955         if (0 != s && s > start && s < current_min) {
956             current_min = s;
957         }
958       }
959     } else {
960       for (i = 0; i < THREAD_TABLE_SZ; i++) {
961         GC_thread t;
962
963         for (t = GC_threads[i]; t != 0; t = t -> next) {
964           ptr_t s = (ptr_t)(t -> stack_base);
965
966           if (0 != s && s > start && s < current_min) {
967             current_min = s;
968           }
969         }
970       }
971     }
972     *hi = current_min;
973     if (current_min == ADDR_LIMIT) {
974         *lo = ADDR_LIMIT;
975         return;
976     }
977     *lo = GC_get_stack_min(current_min);
978     if (*lo < start) *lo = start;
979 }
980
981 #ifndef GC_PTHREADS
982
983 /* We have no DllMain to take care of new threads.  Thus we     */
984 /* must properly intercept thread creation.                     */
985
986 typedef struct {
987     LPTHREAD_START_ROUTINE start;
988     LPVOID param;
989 } thread_args;
990
991 static DWORD WINAPI thread_start(LPVOID arg);
992
993 void * GC_win32_start_inner(struct GC_stack_base *sb, LPVOID arg)
994 {
995     void * ret;
996     thread_args *args = (thread_args *)arg;
997
998 #   if DEBUG_WIN32_THREADS
999       GC_printf("thread 0x%x starting...\n", GetCurrentThreadId());
1000 #   endif
1001
1002     GC_register_my_thread(sb); /* This waits for an in-progress GC. */
1003
1004     /* Clear the thread entry even if we exit with an exception.        */
1005     /* This is probably pointless, since an uncaught exception is       */
1006     /* supposed to result in the process being killed.                  */
1007 #ifndef __GNUC__
1008     __try {
1009 #endif /* __GNUC__ */
1010         ret = (void *)(size_t)args->start (args->param);
1011 #ifndef __GNUC__
1012     } __finally {
1013 #endif /* __GNUC__ */
1014         GC_unregister_my_thread();
1015         GC_free(args);
1016 #ifndef __GNUC__
1017     }
1018 #endif /* __GNUC__ */
1019
1020 #   if DEBUG_WIN32_THREADS
1021       GC_printf("thread 0x%x returned from start routine.\n",
1022                 GetCurrentThreadId());
1023 #   endif
1024     return ret;
1025 }
1026
1027 DWORD WINAPI GC_win32_start(LPVOID arg)
1028 {
1029     return (DWORD)(size_t)GC_call_with_stack_base(GC_win32_start_inner, arg);
1030 }
1031
1032 GC_API HANDLE WINAPI GC_CreateThread(
1033     LPSECURITY_ATTRIBUTES lpThreadAttributes, 
1034     DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
1035     LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
1036 {
1037     HANDLE thread_h = NULL;
1038
1039     thread_args *args;
1040
1041     if (!parallel_initialized) GC_init_parallel();
1042                 /* make sure GC is initialized (i.e. main thread is attached,
1043                    tls initialized) */
1044
1045 #   if DEBUG_WIN32_THREADS
1046       GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
1047 #   endif
1048     if (GC_win32_dll_threads) {
1049       return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
1050                         lpParameter, dwCreationFlags, lpThreadId);
1051     } else {
1052       args = GC_malloc_uncollectable(sizeof(thread_args)); 
1053         /* Handed off to and deallocated by child thread.       */
1054       if (0 == args) {
1055         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1056         return NULL;
1057       }
1058
1059       /* set up thread arguments */
1060         args -> start = lpStartAddress;
1061         args -> param = lpParameter;
1062
1063       GC_need_to_lock = TRUE;
1064       thread_h = CreateThread(lpThreadAttributes,
1065                               dwStackSize, GC_win32_start,
1066                               args, dwCreationFlags,
1067                               lpThreadId);
1068       if( thread_h == 0 ) GC_free( args );
1069       return thread_h;
1070     }
1071 }
1072
1073 void WINAPI GC_ExitThread(DWORD dwExitCode)
1074 {
1075   GC_unregister_my_thread();
1076   ExitThread(dwExitCode);
1077 }
1078
1079 uintptr_t GC_beginthreadex(
1080     void *security, unsigned stack_size,
1081     unsigned ( __stdcall *start_address )( void * ),
1082     void *arglist, unsigned initflag, unsigned *thrdaddr)
1083 {
1084     uintptr_t thread_h;
1085
1086     thread_args *args;
1087
1088     if (!parallel_initialized) GC_init_parallel();
1089                 /* make sure GC is initialized (i.e. main thread is attached,
1090                    tls initialized) */
1091 #   if DEBUG_WIN32_THREADS
1092       GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
1093 #   endif
1094
1095     if (GC_win32_dll_threads) {
1096       return _beginthreadex(security, stack_size, start_address,
1097                             arglist, initflag, thrdaddr);
1098     } else {
1099       args = GC_malloc_uncollectable(sizeof(thread_args)); 
1100         /* Handed off to and deallocated by child thread.       */
1101       if (0 == args) {
1102         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1103         return (uintptr_t)(-1L);
1104       }
1105
1106       /* set up thread arguments */
1107         args -> start = (LPTHREAD_START_ROUTINE)start_address;
1108         args -> param = arglist;
1109
1110       GC_need_to_lock = TRUE;
1111       thread_h = _beginthreadex(security, stack_size,
1112                  (unsigned (__stdcall *) (void *))GC_win32_start,
1113                                 args, initflag, thrdaddr);
1114       if( thread_h == 0 ) GC_free( args );
1115       return thread_h;
1116     }
1117 }
1118
1119 void GC_endthreadex(unsigned retval)
1120 {
1121   GC_unregister_my_thread();
1122   _endthreadex(retval);
1123 }
1124
1125 #endif /* !GC_PTHREADS */
1126
1127 #ifdef MSWINCE
1128
1129 typedef struct {
1130     HINSTANCE hInstance;
1131     HINSTANCE hPrevInstance;
1132     LPWSTR lpCmdLine;
1133     int nShowCmd;
1134 } main_thread_args;
1135
1136 DWORD WINAPI main_thread_start(LPVOID arg);
1137
1138 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
1139                    LPWSTR lpCmdLine, int nShowCmd)
1140 {
1141     DWORD exit_code = 1;
1142
1143     main_thread_args args = {
1144         hInstance, hPrevInstance, lpCmdLine, nShowCmd
1145     };
1146     HANDLE thread_h;
1147     DWORD thread_id;
1148
1149     /* initialize everything */
1150     GC_init();
1151
1152     /* start the main thread */
1153     thread_h = GC_CreateThread(
1154         NULL, 0, main_thread_start, &args, 0, &thread_id);
1155
1156     if (thread_h != NULL)
1157     {
1158         WaitForSingleObject (thread_h, INFINITE);
1159         GetExitCodeThread (thread_h, &exit_code);
1160         CloseHandle (thread_h);
1161     }
1162
1163     GC_deinit();
1164     DeleteCriticalSection(&GC_allocate_ml);
1165
1166     return (int) exit_code;
1167 }
1168
1169 DWORD WINAPI main_thread_start(LPVOID arg)
1170 {
1171     main_thread_args * args = (main_thread_args *) arg;
1172
1173     return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
1174                                args->lpCmdLine, args->nShowCmd);
1175 }
1176
1177 # else /* !MSWINCE */
1178
1179 /* Called by GC_init() - we hold the allocation lock.   */
1180 void GC_thr_init(void) {
1181     struct GC_stack_base sb;
1182     int sb_result;
1183
1184     GC_ASSERT(I_HOLD_LOCK());
1185     if (GC_thr_initialized) return;
1186     GC_main_thread = GetCurrentThreadId();
1187     GC_thr_initialized = TRUE;
1188
1189     /* Add the initial thread, so we can stop it.       */
1190     sb_result = GC_get_stack_base(&sb);
1191     GC_ASSERT(sb_result == GC_SUCCESS);
1192     GC_register_my_thread(&sb);
1193 }
1194
1195 #ifdef GC_PTHREADS
1196
1197 struct start_info {
1198     void *(*start_routine)(void *);
1199     void *arg;
1200     GC_bool detached;
1201 };
1202
1203 int GC_pthread_join(pthread_t pthread_id, void **retval) {
1204     int result;
1205     int i;
1206     GC_thread joinee;
1207
1208 #   if DEBUG_CYGWIN_THREADS
1209       GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
1210                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
1211 #   endif
1212 #   if DEBUG_WIN32_PTHREADS
1213       GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
1214                 (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
1215 #   endif
1216
1217     if (!parallel_initialized) GC_init_parallel();
1218     /* Thread being joined might not have registered itself yet. */
1219     /* After the join,thread id may have been recycled.          */
1220     /* FIXME: It would be better if this worked more like        */
1221     /* pthread_support.c.                                        */
1222
1223     #ifndef GC_WIN32_PTHREADS
1224       while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10);
1225     #endif
1226
1227     result = pthread_join(pthread_id, retval);
1228
1229     #ifdef GC_WIN32_PTHREADS
1230       /* win32_pthreads id are unique */
1231       joinee = GC_lookup_pthread(pthread_id);
1232     #endif
1233
1234     if (!GC_win32_dll_threads) {
1235       LOCK();
1236       GC_delete_gc_thread(joinee);
1237       UNLOCK();
1238     } /* otherwise dllmain handles it.  */
1239
1240 #   if DEBUG_CYGWIN_THREADS
1241       GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
1242                  (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
1243 #   endif
1244 #   if DEBUG_WIN32_PTHREADS
1245       GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
1246                 (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
1247 #   endif
1248
1249     return result;
1250 }
1251
1252 /* Cygwin-pthreads calls CreateThread internally, but it's not
1253  * easily interceptible by us..
1254  *   so intercept pthread_create instead
1255  */
1256 int
1257 GC_pthread_create(pthread_t *new_thread,
1258                   const pthread_attr_t *attr,
1259                   void *(*start_routine)(void *), void *arg) {
1260     int result;
1261     struct start_info * si;
1262
1263     if (!parallel_initialized) GC_init_parallel();
1264                 /* make sure GC is initialized (i.e. main thread is attached) */
1265     if (GC_win32_dll_threads) {
1266       return pthread_create(new_thread, attr, start_routine, arg);
1267     }
1268     
1269     /* This is otherwise saved only in an area mmapped by the thread */
1270     /* library, which isn't visible to the collector.            */
1271     si = GC_malloc_uncollectable(sizeof(struct start_info)); 
1272     if (0 == si) return(EAGAIN);
1273
1274     si -> start_routine = start_routine;
1275     si -> arg = arg;
1276     if (attr != 0 &&
1277         pthread_attr_getdetachstate(attr, &si->detached)
1278         == PTHREAD_CREATE_DETACHED) {
1279       si->detached = TRUE;
1280     }
1281
1282 #   if DEBUG_CYGWIN_THREADS
1283       GC_printf("About to create a thread from 0x%x(0x%x)\n",
1284                 (int)pthread_self(), GetCurrentThreadId);
1285 #   endif
1286 #   if DEBUG_WIN32_PTHREADS
1287       GC_printf("About to create a thread from 0x%x(0x%x)\n",
1288                 (int)(pthread_self()).p, GetCurrentThreadId());
1289 #   endif
1290     GC_need_to_lock = TRUE;
1291     result = pthread_create(new_thread, attr, GC_pthread_start, si); 
1292
1293     if (result) { /* failure */
1294         GC_free(si);
1295     } 
1296
1297     return(result);
1298 }
1299
1300 void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg)
1301 {
1302     struct start_info * si = arg;
1303     void * result;
1304     void *(*start)(void *);
1305     void *start_arg;
1306     DWORD thread_id = GetCurrentThreadId();
1307     pthread_t pthread_id = pthread_self();
1308     GC_thread me;
1309     GC_bool detached;
1310     int i;
1311
1312 #   if DEBUG_CYGWIN_THREADS
1313       GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id,
1314                                                   thread_id);
1315 #   endif
1316 #   if DEBUG_WIN32_PTHREADS
1317       GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p,
1318                                                   thread_id);
1319 #   endif
1320
1321     GC_ASSERT(!GC_win32_dll_threads);
1322     /* If a GC occurs before the thread is registered, that GC will     */
1323     /* ignore this thread.  That's fine, since it will block trying to  */
1324     /* acquire the allocation lock, and won't yet hold interesting      */
1325     /* pointers.                                                        */
1326     LOCK();
1327     /* We register the thread here instead of in the parent, so that    */
1328     /* we don't need to hold the allocation lock during pthread_create. */
1329     me = GC_register_my_thread_inner(sb, thread_id);
1330     SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
1331     UNLOCK();
1332
1333     start = si -> start_routine;
1334     start_arg = si -> arg;
1335     if (si-> detached) me -> flags |= DETACHED;
1336     me -> pthread_id = pthread_id;
1337
1338     GC_free(si); /* was allocated uncollectable */
1339
1340     pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
1341     result = (*start)(start_arg);
1342     me -> status = result;
1343     pthread_cleanup_pop(1);
1344
1345 #   if DEBUG_CYGWIN_THREADS
1346       GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
1347                 (int)pthread_self(),GetCurrentThreadId());
1348 #   endif
1349 #   if DEBUG_WIN32_PTHREADS
1350       GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
1351                 (int)(pthread_self()).p, GetCurrentThreadId());
1352 #   endif
1353
1354     return(result);
1355 }
1356
1357 void * GC_pthread_start(void * arg)
1358 {
1359     return GC_call_with_stack_base(GC_pthread_start_inner, arg);
1360 }
1361
1362 void GC_thread_exit_proc(void *arg)
1363 {
1364     GC_thread me = (GC_thread)arg;
1365     int i;
1366
1367     GC_ASSERT(!GC_win32_dll_threads);
1368 #   if DEBUG_CYGWIN_THREADS
1369       GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
1370                 (int)pthread_self(),GetCurrentThreadId());
1371 #   endif
1372 #   if DEBUG_WIN32_PTHREADS
1373       GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
1374                 (int)(pthread_self()).p,GetCurrentThreadId());
1375 #   endif
1376
1377     LOCK();
1378 #   if defined(THREAD_LOCAL_ALLOC)
1379       GC_destroy_thread_local(&(me->tlfs));
1380 #   endif
1381     if (me -> flags & DETACHED) {
1382       GC_delete_thread(GetCurrentThreadId());
1383     } else {
1384       /* deallocate it as part of join */
1385       me -> flags |= FINISHED;
1386     }
1387     UNLOCK();
1388 }
1389
1390 #ifndef GC_WIN32_PTHREADS
1391 /* win32 pthread does not support sigmask */
1392 /* nothing required here... */
1393 int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1394   if (!parallel_initialized) GC_init_parallel();
1395   return pthread_sigmask(how, set, oset);
1396 }
1397 #endif
1398
1399 int GC_pthread_detach(pthread_t thread)
1400 {
1401     int result;
1402     GC_thread thread_gc_id;
1403     
1404     if (!parallel_initialized) GC_init_parallel();
1405     LOCK();
1406     thread_gc_id = GC_lookup_pthread(thread);
1407     UNLOCK();
1408     result = pthread_detach(thread);
1409     if (result == 0) {
1410       LOCK();
1411       thread_gc_id -> flags |= DETACHED;
1412       /* Here the pthread thread id may have been recycled. */
1413       if (thread_gc_id -> flags & FINISHED) {
1414         GC_delete_gc_thread(thread_gc_id);
1415       }
1416       UNLOCK();
1417     }
1418     return result;
1419 }
1420
1421 #else /* !GC_PTHREADS */
1422
1423 /*
1424  * We avoid acquiring locks here, since this doesn't seem to be preemptable.
1425  * This may run with an uninitialized collector, in which case we don't do much.
1426  * This implies that no threads other than the main one should be created
1427  * with an uninitialized collector.  (The alternative of initializing
1428  * the collector here seems dangerous, since DllMain is limited in what it
1429  * can do.)
1430  */
1431 #ifdef GC_DLL
1432 GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
1433 {
1434   struct GC_stack_base sb;
1435   DWORD thread_id;
1436   int sb_result;
1437   static int entry_count = 0;
1438
1439   if (parallel_initialized && !GC_win32_dll_threads) return TRUE;
1440
1441   switch (reason) {
1442    case DLL_THREAD_ATTACH:
1443     GC_ASSERT(entry_count == 0 || parallel_initialized);
1444     ++entry_count; /* and fall through: */
1445    case DLL_PROCESS_ATTACH:
1446     /* This may run with the collector uninitialized. */
1447     thread_id = GetCurrentThreadId();
1448     if (parallel_initialized && GC_main_thread != thread_id) {
1449         /* Don't lock here.     */
1450         sb_result = GC_get_stack_base(&sb);
1451         GC_ASSERT(sb_result == GC_SUCCESS);
1452 #       ifdef THREAD_LOCAL_ALLOC
1453           ABORT("Cannot initialize thread local cache from DllMain");
1454 #       endif
1455         GC_register_my_thread_inner(&sb, thread_id);
1456     } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
1457     break;
1458
1459    case DLL_THREAD_DETACH:
1460     /* We are hopefully running in the context of the exiting thread.   */
1461     GC_ASSERT(parallel_initialized);
1462     if (!GC_win32_dll_threads) return TRUE;
1463     GC_delete_thread(GetCurrentThreadId());
1464     break;
1465
1466    case DLL_PROCESS_DETACH:
1467     {
1468       int i;
1469
1470       if (!GC_win32_dll_threads) return TRUE;
1471       for (i = 0; i <= GC_get_max_thread_index(); ++i)
1472       {
1473           if (AO_load(&(dll_thread_table[i].in_use)))
1474             GC_delete_gc_thread(dll_thread_table + i);
1475       }
1476
1477       GC_deinit();
1478       DeleteCriticalSection(&GC_allocate_ml);
1479     }
1480     break;
1481
1482   }
1483   return TRUE;
1484 }
1485 #endif /* GC_DLL */
1486 #endif /* !GC_PTHREADS */
1487
1488 # endif /* !MSWINCE */
1489
1490 /* Perform all initializations, including those that    */
1491 /* may require allocation.                              */
1492 /* Called without allocation lock.                      */
1493 /* Must be called before a second thread is created.    */
1494 void GC_init_parallel(void)
1495 {
1496     if (parallel_initialized) return;
1497     parallel_initialized = TRUE;
1498     /* GC_init() calls us back, so set flag first.      */
1499     
1500     if (!GC_is_initialized) GC_init();
1501     if (GC_win32_dll_threads) {
1502       GC_need_to_lock = TRUE;
1503         /* Cannot intercept thread creation.  Hence we don't know if    */
1504         /* other threads exist.  However, client is not allowed to      */
1505         /* create other threads before collector initialization.        */
1506         /* Thus it's OK not to lock before this.                        */
1507     }
1508     /* Initialize thread local free lists if used.      */
1509 #   if defined(THREAD_LOCAL_ALLOC)
1510       LOCK();
1511       GC_init_thread_local(&(GC_lookup_thread(GetCurrentThreadId())->tlfs));
1512       UNLOCK();
1513 #   endif
1514 }
1515
1516 #if defined(USE_PTHREAD_LOCKS)
1517   /* Support for pthread locking code.          */
1518   /* Pthread_mutex_try_lock may not win here,   */
1519   /* due to builtinsupport for spinning first?  */
1520
1521 volatile GC_bool GC_collecting = 0;
1522                         /* A hint that we're in the collector and       */
1523                         /* holding the allocation lock for an           */
1524                         /* extended period.                             */
1525
1526 void GC_lock(void)
1527 {
1528     pthread_mutex_lock(&GC_allocate_ml);
1529 }
1530 #endif /* USE_PTHREAD ... */
1531
1532 # if defined(THREAD_LOCAL_ALLOC)
1533
1534 /* Add thread-local allocation support.  Microsoft uses __declspec(thread) */
1535
1536 /* We must explicitly mark ptrfree and gcj free lists, since the free   */
1537 /* list links wouldn't otherwise be found.  We also set them in the     */
1538 /* normal free lists, since that involves touching less memory than if  */
1539 /* we scanned them normally.                                            */
1540 void GC_mark_thread_local_free_lists(void)
1541 {
1542     int i;
1543     GC_thread p;
1544     
1545     for (i = 0; i < THREAD_TABLE_SZ; ++i) {
1546       for (p = GC_threads[i]; 0 != p; p = p -> next) {
1547         GC_mark_thread_local_fls_for(&(p->tlfs));
1548       }
1549     }
1550 }
1551
1552 #if defined(GC_ASSERTIONS)
1553     /* Check that all thread-local free-lists are completely marked.    */
1554     /* also check that thread-specific-data structures are marked.      */
1555     void GC_check_tls(void) {
1556         int i;
1557         GC_thread p;
1558         
1559         for (i = 0; i < THREAD_TABLE_SZ; ++i) {
1560           for (p = GC_threads[i]; 0 != p; p = p -> next) {
1561             GC_check_tls_for(&(p->tlfs));
1562           }
1563         }
1564 #       if defined(USE_CUSTOM_SPECIFIC)
1565           if (GC_thread_key != 0)
1566             GC_check_tsd_marks(GC_thread_key);
1567 #       endif 
1568     }
1569 #endif /* GC_ASSERTIONS */
1570
1571 #endif /* THREAD_LOCAL_ALLOC ... */
1572
1573 #endif /* GC_WIN32_THREADS */