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