TIVI-153: Add as dependency for Iputils
[profile/ivi/gc.git] / win32_threads.c
1 #include "private/gc_priv.h"
2
3 #if defined(GC_WIN32_THREADS)
4
5 #include <windows.h>
6
7 #ifdef THREAD_LOCAL_ALLOC
8 # include "private/thread_local_alloc.h"
9 #endif /* THREAD_LOCAL_ALLOC */
10
11 /* Allocation lock declarations.        */
12 #if !defined(USE_PTHREAD_LOCKS)
13 # if defined(GC_DLL)
14     __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
15 # else
16     CRITICAL_SECTION GC_allocate_ml;
17 # endif
18   DWORD GC_lock_holder = NO_THREAD;
19         /* Thread id for current holder of allocation lock */
20 #else
21   pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
22   unsigned long GC_lock_holder = NO_THREAD;
23 #endif
24
25 #ifdef GC_PTHREADS
26 # include <errno.h>
27
28 /* GC_DLL should not normally be defined, especially since we often do turn */
29 /* on THREAD_LOCAL_ALLOC, which is currently incompatible.                  */
30 /* It might be possible to get GC_DLL and DllMain-based thread registration */
31 /* to work with Cygwin, but if you try you are on your own.                 */
32 #ifdef GC_DLL
33 # error GC_DLL untested with Cygwin
34 #endif
35
36  /* Cygwin-specific forward decls */
37 # undef pthread_create 
38 # undef pthread_sigmask 
39 # undef pthread_join 
40 # undef pthread_detach
41 # undef dlopen 
42
43 # ifdef DEBUG_THREADS
44 #   ifdef CYGWIN32
45 #     define DEBUG_CYGWIN_THREADS 1
46 #     define DEBUG_WIN32_PTHREADS 0
47 #   else
48 #     define DEBUG_WIN32_PTHREADS 1
49 #     define DEBUG_CYGWIN_THREADS 0
50 #   endif
51 # else
52 #   define DEBUG_CYGWIN_THREADS 0
53 #   define DEBUG_WIN32_PTHREADS 0
54 # endif
55
56   void * GC_pthread_start(void * arg);
57   void GC_thread_exit_proc(void *arg);
58
59 # include <pthread.h>
60
61 #else
62
63 # ifdef DEBUG_THREADS
64 #   define DEBUG_WIN32_THREADS 1
65 # else
66 #   define DEBUG_WIN32_THREADS 0
67 # endif
68
69 # undef CreateThread
70 # undef ExitThread
71 # undef _beginthreadex
72 # undef _endthreadex
73 # undef _beginthread
74 # ifdef DEBUG_THREADS
75 #   define DEBUG_WIN32_THREADS 1
76 # else
77 #   define DEBUG_WIN32_THREADS 0
78 # endif
79
80 # include <process.h>  /* For _beginthreadex, _endthreadex */
81
82 #endif
83
84 #if defined(GC_DLL) && !defined(MSWINCE)
85   static GC_bool GC_win32_dll_threads = FALSE;
86   /* This code operates in two distinct modes, depending on     */
87   /* the setting of GC_win32_dll_threads.  If                   */
88   /* GC_win32_dll_threads is set, all threads in the process    */
89   /* are implicitly registered with the GC by DllMain.          */
90   /* No explicit registration is required, and attempts at      */
91   /* explicit registration are ignored.  This mode is           */
92   /* very different from the Posix operation of the collector.  */
93   /* In this mode access to the thread table is lock-free.      */
94   /* Hence there is a static limit on the number of threads.    */
95   
96   /* If GC_win32_dll_threads is FALSE, or the collector is      */
97   /* built without GC_DLL defined, things operate in a way      */
98   /* that is very similar to Posix platforms, and new threads   */
99   /* must be registered with the collector, e.g. by using       */
100   /* preprocessor-based interception of the thread primitives.  */
101   /* In this case, we use a real data structure for the thread  */
102   /* table.  Note that there is no equivalent of linker-based   */
103   /* call interception, since we don't have ELF-like            */
104   /* facilities.  The Windows analog appears to be "API         */
105   /* hooking", which really seems to be a standard way to       */
106   /* do minor binary rewriting (?).  I'd prefer not to have     */
107   /* the basic collector rely on such facilities, but an        */
108   /* optional package that intercepts thread calls this way     */
109   /* would probably be nice.                                    */
110
111   /* GC_win32_dll_threads must be set at initialization time,   */
112   /* i.e. before any collector or thread calls.  We make it a   */
113   /* "dynamic" option only to avoid multiple library versions.  */
114 #else
115 # define GC_win32_dll_threads FALSE
116 #endif
117
118 /* We have two versions of the thread table.  Which one */
119 /* we us depends on whether or not GC_win32_dll_threads */
120 /* is set.  Note that before initialization, we don't   */
121 /* add any entries to either table, even if DllMain is  */
122 /* called.  The main thread will be added on            */
123 /* initialization.                                      */
124
125 /* The type of the first argument to InterlockedExchange.       */
126 /* Documented to be LONG volatile *, but at least gcc likes     */
127 /* this better.                                                 */
128 typedef LONG * IE_t;
129
130 GC_bool GC_thr_initialized = FALSE;
131
132 GC_bool GC_need_to_lock = FALSE;
133
134 static GC_bool parallel_initialized = FALSE;
135
136 void GC_init_parallel(void);
137
138 #ifdef GC_DLL
139   /* Turn on GC_win32_dll_threads       */
140   GC_API void GC_use_DllMain(void)
141   {
142 #     ifdef THREAD_LOCAL_ALLOC
143           ABORT("Cannot use thread local allocation with DllMain-based "
144                 "thread registration.");
145           /* Thread-local allocation really wants to lock at thread     */
146           /* entry and exit.                                            */
147 #     endif
148       GC_ASSERT(!parallel_initialized);
149       GC_win32_dll_threads = TRUE;
150       GC_init_parallel();
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   CloseHandle(gc_id->handle);
492   if (GC_win32_dll_threads) {
493     /* This is intended to be lock-free.                                */
494     /* It is either called synchronously from the thread being deleted, */
495     /* or by the joining thread.                                        */
496     /* In this branch asynchronosu changes to *gc_id are possible.      */
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     CloseHandle(p->handle);
555     if (prev == 0) {
556         GC_threads[hv] = p -> next;
557     } else {
558         prev -> next = p -> next;
559     }
560     GC_INTERNAL_FREE(p);
561   }
562 }
563
564 GC_API int GC_register_my_thread(struct GC_stack_base *sb) {
565   DWORD t = GetCurrentThreadId();
566
567   if (0 == GC_lookup_thread(t)) {
568     /* We lock here, since we want to wait for an ongoing GC.   */
569     LOCK();
570     GC_register_my_thread_inner(sb, t);
571     UNLOCK();
572     return GC_SUCCESS;
573   } else {
574     return GC_DUPLICATE;
575   }
576 }
577
578 GC_API int GC_unregister_my_thread(void)
579 {
580     DWORD t = GetCurrentThreadId();
581
582 #   if defined(THREAD_LOCAL_ALLOC)
583       LOCK();
584       {
585         GC_thread me = GC_lookup_thread_inner(t);
586         GC_destroy_thread_local(&(me->tlfs));
587       }
588       UNLOCK();
589 #   endif
590     if (GC_win32_dll_threads) {
591       /* Should we just ignore this? */
592       GC_delete_thread(t);
593     } else {
594       LOCK();
595       GC_delete_thread(t);
596       UNLOCK();
597     }
598     return GC_SUCCESS;
599 }
600
601
602 #ifdef GC_PTHREADS
603
604 /* A quick-and-dirty cache of the mapping between pthread_t     */
605 /* and win32 thread id.                                         */
606 #define PTHREAD_MAP_SIZE 512
607 DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE];
608 #define HASH(pthread_id) ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
609         /* It appears pthread_t is really a pointer type ... */
610 #define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
611         GC_pthread_map_cache[HASH(pthread_id)] = (win32_id);
612 #define GET_PTHREAD_MAP_CACHE(pthread_id) \
613         GC_pthread_map_cache[HASH(pthread_id)]
614
615 /* Return a GC_thread corresponding to a given pthread_t.       */
616 /* Returns 0 if it's not there.                                 */
617 /* We assume that this is only called for pthread ids that      */
618 /* have not yet terminated or are still joinable, and           */
619 /* cannot be concurrently terminated.                           */
620 /* Assumes we do NOT hold the allocation lock.                  */
621 static GC_thread GC_lookup_pthread(pthread_t id)
622 {
623   if (GC_win32_dll_threads) {
624     int i;
625     LONG my_max = GC_get_max_thread_index();
626
627     for (i = 0;
628          i <= my_max &&
629          (!AO_load_acquire(&(dll_thread_table[i].in_use))
630           || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
631        /* Must still be in_use, since nobody else can store our thread_id. */
632        i++);
633     if (i > my_max) return 0;
634     return (GC_thread)(dll_thread_table + i);
635   } else {
636     /* We first try the cache.  If that fails, we use a very slow       */
637     /* approach.                                                        */
638     int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ;
639     int hv;
640     GC_thread p;
641
642     LOCK();
643     for (p = GC_threads[hv_guess]; 0 != p; p = p -> next) {
644       if (THREAD_EQUAL(p -> pthread_id, id))
645         goto foundit; 
646     }
647     for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
648       for (p = GC_threads[hv]; 0 != p; p = p -> next) {
649         if (THREAD_EQUAL(p -> pthread_id, id))
650           goto foundit; 
651       }
652     }
653     p = 0;
654    foundit:
655     UNLOCK();
656     return p;
657   }
658 }
659
660 #endif /* GC_PTHREADS */
661
662 void GC_push_thread_structures(void)
663 {
664   GC_ASSERT(I_HOLD_LOCK());
665   if (GC_win32_dll_threads) {
666     /* Unlike the other threads implementations, the thread table here  */
667     /* contains no pointers to the collectable heap.  Thus we have      */
668     /* no private structures we need to preserve.                       */
669 #   ifdef GC_PTHREADS 
670     { int i; /* pthreads may keep a pointer in the thread exit value */
671       LONG my_max = GC_get_max_thread_index();
672
673       for (i = 0; i <= my_max; i++)
674         if (dll_thread_table[i].in_use)
675           GC_push_all((ptr_t)&(dll_thread_table[i].status),
676                       (ptr_t)(&(dll_thread_table[i].status)+1));
677     }
678 #   endif
679   } else {
680     GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
681   }
682 # if defined(THREAD_LOCAL_ALLOC)
683     GC_push_all((ptr_t)(&GC_thread_key),
684       (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
685     /* Just in case we ever use our own TLS implementation.     */
686 # endif
687 }
688
689 /* Suspend the given thread, if it's still active.      */
690 void GC_suspend(GC_thread t)
691 {
692 # ifdef MSWINCE
693     /* SuspendThread will fail if thread is running kernel code */
694       while (SuspendThread(t -> handle) == (DWORD)-1)
695         Sleep(10);
696 # else
697     /* Apparently the Windows 95 GetOpenFileName call creates   */
698     /* a thread that does not properly get cleaned up, and              */
699     /* SuspendThread on its descriptor may provoke a crash.             */
700     /* This reduces the probability of that event, though it still      */
701     /* appears there's a race here.                                     */
702     DWORD exitCode; 
703     if (GetExitCodeThread(t -> handle, &exitCode) &&
704         exitCode != STILL_ACTIVE) {
705       t -> stack_base = 0; /* prevent stack from being pushed */
706 #     ifndef GC_PTHREADS
707         /* this breaks pthread_join on Cygwin, which is guaranteed to  */
708         /* only see user pthreads                                      */
709         GC_ASSERT(GC_win32_dll_threads);
710         GC_delete_gc_thread(t);
711 #     endif
712       return;
713     }
714     if (SuspendThread(t -> handle) == (DWORD)-1)
715       ABORT("SuspendThread failed");
716 # endif
717    t -> suspended = TRUE;
718 }
719
720 /* Defined in misc.c */
721 #ifndef CYGWIN32
722   extern CRITICAL_SECTION GC_write_cs;
723 #endif
724
725 void GC_stop_world(void)
726 {
727   DWORD thread_id = GetCurrentThreadId();
728   int i;
729
730   if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
731   GC_ASSERT(I_HOLD_LOCK());
732
733   GC_please_stop = TRUE;
734 # ifndef CYGWIN32
735     EnterCriticalSection(&GC_write_cs);
736 # endif
737   if (GC_win32_dll_threads) {
738     /* Any threads being created during this loop will end up setting   */
739     /* GC_attached_thread when they start.  This will force marking to  */
740     /* restart.                                                         */
741     /* This is not ideal, but hopefully correct.                        */
742     GC_attached_thread = FALSE;
743     for (i = 0; i <= GC_get_max_thread_index(); i++) {
744       GC_vthread t = dll_thread_table + i;
745       if (t -> stack_base != 0
746           && t -> id != thread_id) {
747           GC_suspend((GC_thread)t);
748       }
749     }
750   } else {
751       GC_thread t;
752       int i;
753
754       for (i = 0; i < THREAD_TABLE_SZ; i++) {
755         for (t = GC_threads[i]; t != 0; t = t -> next) {
756           if (t -> stack_base != 0
757           && !KNOWN_FINISHED(t)
758           && t -> id != thread_id) {
759             GC_suspend(t);
760           }
761         }
762       }
763   }
764 # ifndef CYGWIN32
765     LeaveCriticalSection(&GC_write_cs);
766 # endif    
767 }
768
769 void GC_start_world(void)
770 {
771   DWORD thread_id = GetCurrentThreadId();
772   int i;
773   LONG my_max = GC_get_max_thread_index();
774
775   GC_ASSERT(I_HOLD_LOCK());
776   if (GC_win32_dll_threads) {
777     for (i = 0; i <= my_max; i++) {
778       GC_thread t = (GC_thread)(dll_thread_table + i);
779       if (t -> stack_base != 0 && t -> suspended
780           && t -> id != thread_id) {
781         if (ResumeThread(t -> handle) == (DWORD)-1)
782           ABORT("ResumeThread failed");
783         t -> suspended = FALSE;
784       }
785     }
786   } else {
787     GC_thread t;
788     int i;
789
790     for (i = 0; i < THREAD_TABLE_SZ; i++) {
791       for (t = GC_threads[i]; t != 0; t = t -> next) {
792         if (t -> stack_base != 0 && t -> suspended
793             && t -> id != thread_id) {
794           if (ResumeThread(t -> handle) == (DWORD)-1)
795             ABORT("ResumeThread failed");
796           t -> suspended = FALSE;
797         }
798       }
799     }
800   }
801   GC_please_stop = FALSE;
802 }
803
804 # ifdef MSWINCE
805     /* The VirtualQuery calls below won't work properly on WinCE, but   */
806     /* since each stack is restricted to an aligned 64K region of       */
807     /* virtual memory we can just take the next lowest multiple of 64K. */
808 #   define GC_get_stack_min(s) \
809         ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
810 # else
811     static ptr_t GC_get_stack_min(ptr_t s)
812     {
813         ptr_t bottom;
814         MEMORY_BASIC_INFORMATION info;
815         VirtualQuery(s, &info, sizeof(info));
816         do {
817             bottom = info.BaseAddress;
818             VirtualQuery(bottom - 1, &info, sizeof(info));
819         } while ((info.Protect & PAGE_READWRITE)
820                  && !(info.Protect & PAGE_GUARD));
821         return(bottom);
822     }
823 # endif
824
825 void GC_push_stack_for(GC_thread thread)
826 {
827     int dummy;
828     ptr_t sp, stack_min;
829     DWORD me = GetCurrentThreadId();
830
831     if (thread -> stack_base) {
832       if (thread -> id == me) {
833         sp = (ptr_t) &dummy;
834       } else {
835         CONTEXT context;
836         context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
837         if (!GetThreadContext(thread -> handle, &context))
838           ABORT("GetThreadContext failed");
839
840         /* Push all registers that might point into the heap.  Frame    */
841         /* pointer registers are included in case client code was       */
842         /* compiled with the 'omit frame pointer' optimisation.         */
843 #       define PUSH1(reg) GC_push_one((word)context.reg)
844 #       define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
845 #       define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
846 #       if defined(I386)
847           PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
848           sp = (ptr_t)context.Esp;
849 #       elif defined(X86_64)
850           PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
851           PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
852           sp = (ptr_t)context.Rsp;
853 #       elif defined(ARM32)
854           PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
855           sp = (ptr_t)context.Sp;
856 #       elif defined(SHx)
857           PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
858           PUSH2(R12,R13), PUSH1(R14);
859           sp = (ptr_t)context.R15;
860 #       elif defined(MIPS)
861           PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
862           PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
863           PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
864           PUSH4(IntT9,IntK0,IntK1,IntS8);
865           sp = (ptr_t)context.IntSp;
866 #       elif defined(PPC)
867           PUSH4(Gpr0, Gpr3, Gpr4, Gpr5),  PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
868           PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
869           PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
870           PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
871           sp = (ptr_t)context.Gpr1;
872 #       elif defined(ALPHA)
873           PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
874           PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
875           PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
876           PUSH4(IntT10,IntT11,IntT12,IntAt);
877           sp = (ptr_t)context.IntSp;
878 #       else
879 #         error "architecture is not supported"
880 #       endif
881       } /* ! current thread */
882
883       stack_min = GC_get_stack_min(thread->stack_base);
884
885       if (sp >= stack_min && sp < thread->stack_base) {
886 #       if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \
887            || DEBUG_CYGWIN_THREADS
888           GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n",
889                     sp, thread -> stack_base, thread -> id, me);
890 #       endif
891         GC_push_all_stack(sp, thread->stack_base);
892       } else {
893         WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
894              (unsigned long)(size_t)sp);
895         GC_push_all_stack(stack_min, thread->stack_base);
896       }
897     } /* thread looks live */
898 }
899
900 void GC_push_all_stacks(void)
901 {
902   DWORD me = GetCurrentThreadId();
903   GC_bool found_me = FALSE;
904   size_t nthreads = 0;
905   
906   if (GC_win32_dll_threads) {
907     int i;
908     LONG my_max = GC_get_max_thread_index();
909
910     for (i = 0; i <= my_max; i++) {
911       GC_thread t = (GC_thread)(dll_thread_table + i);
912       if (t -> in_use) {
913         ++nthreads;
914         GC_push_stack_for(t);
915         if (t -> id == me) found_me = TRUE;
916       }
917     }
918   } else {
919     GC_thread t;
920     int i;
921
922     for (i = 0; i < THREAD_TABLE_SZ; i++) {
923       for (t = GC_threads[i]; t != 0; t = t -> next) {
924         ++nthreads;
925         if (!KNOWN_FINISHED(t)) GC_push_stack_for(t);
926         if (t -> id == me) found_me = TRUE;
927       }
928     }
929   }
930   if (GC_print_stats == VERBOSE) {
931     GC_log_printf("Pushed %d thread stacks ", nthreads);
932     if (GC_win32_dll_threads) {
933         GC_log_printf("based on DllMain thread tracking\n");
934     } else {
935         GC_log_printf("\n");
936     }
937   }
938   if (!found_me && !GC_in_thread_creation)
939     ABORT("Collecting from unknown thread.");
940 }
941
942 void GC_get_next_stack(char *start, char **lo, char **hi)
943 {
944     int i;
945 #   define ADDR_LIMIT (char *)(-1L)
946     char * current_min = ADDR_LIMIT;
947
948     if (GC_win32_dll_threads) {
949       LONG my_max = GC_get_max_thread_index();
950   
951       for (i = 0; i <= my_max; i++) {
952         ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
953
954         if (0 != s && s > start && s < current_min) {
955             current_min = s;
956         }
957       }
958     } else {
959       for (i = 0; i < THREAD_TABLE_SZ; i++) {
960         GC_thread t;
961
962         for (t = GC_threads[i]; t != 0; t = t -> next) {
963           ptr_t s = (ptr_t)(t -> stack_base);
964
965           if (0 != s && s > start && s < current_min) {
966             current_min = s;
967           }
968         }
969       }
970     }
971     *hi = current_min;
972     if (current_min == ADDR_LIMIT) {
973         *lo = ADDR_LIMIT;
974         return;
975     }
976     *lo = GC_get_stack_min(current_min);
977     if (*lo < start) *lo = start;
978 }
979
980 #ifndef GC_PTHREADS
981
982 /* We have no DllMain to take care of new threads.  Thus we     */
983 /* must properly intercept thread creation.                     */
984
985 typedef struct {
986     LPTHREAD_START_ROUTINE start;
987     LPVOID param;
988 } thread_args;
989
990 static DWORD WINAPI thread_start(LPVOID arg);
991
992 void * GC_win32_start_inner(struct GC_stack_base *sb, LPVOID arg)
993 {
994     void * ret;
995     thread_args *args = (thread_args *)arg;
996
997 #   if DEBUG_WIN32_THREADS
998       GC_printf("thread 0x%x starting...\n", GetCurrentThreadId());
999 #   endif
1000
1001     GC_register_my_thread(sb); /* This waits for an in-progress GC. */
1002
1003     /* Clear the thread entry even if we exit with an exception.        */
1004     /* This is probably pointless, since an uncaught exception is       */
1005     /* supposed to result in the process being killed.                  */
1006 #ifndef __GNUC__
1007     __try {
1008 #endif /* __GNUC__ */
1009         ret = (void *)(size_t)args->start (args->param);
1010 #ifndef __GNUC__
1011     } __finally {
1012 #endif /* __GNUC__ */
1013         GC_unregister_my_thread();
1014         GC_free(args);
1015 #ifndef __GNUC__
1016     }
1017 #endif /* __GNUC__ */
1018
1019 #   if DEBUG_WIN32_THREADS
1020       GC_printf("thread 0x%x returned from start routine.\n",
1021                 GetCurrentThreadId());
1022 #   endif
1023     return ret;
1024 }
1025
1026 DWORD WINAPI GC_win32_start(LPVOID arg)
1027 {
1028     return (DWORD)(size_t)GC_call_with_stack_base(GC_win32_start_inner, arg);
1029 }
1030
1031 GC_API HANDLE WINAPI GC_CreateThread(
1032     LPSECURITY_ATTRIBUTES lpThreadAttributes, 
1033     DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
1034     LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
1035 {
1036     HANDLE thread_h = NULL;
1037
1038     thread_args *args;
1039
1040     if (!parallel_initialized) GC_init_parallel();
1041                 /* make sure GC is initialized (i.e. main thread is attached,
1042                    tls initialized) */
1043
1044 #   if DEBUG_WIN32_THREADS
1045       GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
1046 #   endif
1047     if (GC_win32_dll_threads) {
1048       return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
1049                         lpParameter, dwCreationFlags, lpThreadId);
1050     } else {
1051       args = GC_malloc_uncollectable(sizeof(thread_args)); 
1052         /* Handed off to and deallocated by child thread.       */
1053       if (0 == args) {
1054         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1055         return NULL;
1056       }
1057
1058       /* set up thread arguments */
1059         args -> start = lpStartAddress;
1060         args -> param = lpParameter;
1061
1062       GC_need_to_lock = TRUE;
1063       thread_h = CreateThread(lpThreadAttributes,
1064                               dwStackSize, GC_win32_start,
1065                               args, dwCreationFlags,
1066                               lpThreadId);
1067       if( thread_h == 0 ) GC_free( args );
1068       return thread_h;
1069     }
1070 }
1071
1072 void WINAPI GC_ExitThread(DWORD dwExitCode)
1073 {
1074   GC_unregister_my_thread();
1075   ExitThread(dwExitCode);
1076 }
1077
1078 uintptr_t GC_beginthreadex(
1079     void *security, unsigned stack_size,
1080     unsigned ( __stdcall *start_address )( void * ),
1081     void *arglist, unsigned initflag, unsigned *thrdaddr)
1082 {
1083     uintptr_t thread_h;
1084
1085     thread_args *args;
1086
1087     if (!parallel_initialized) GC_init_parallel();
1088                 /* make sure GC is initialized (i.e. main thread is attached,
1089                    tls initialized) */
1090 #   if DEBUG_WIN32_THREADS
1091       GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
1092 #   endif
1093
1094     if (GC_win32_dll_threads) {
1095       return _beginthreadex(security, stack_size, start_address,
1096                             arglist, initflag, thrdaddr);
1097     } else {
1098       args = GC_malloc_uncollectable(sizeof(thread_args)); 
1099         /* Handed off to and deallocated by child thread.       */
1100       if (0 == args) {
1101         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1102         return (uintptr_t)(-1L);
1103       }
1104
1105       /* set up thread arguments */
1106         args -> start = (LPTHREAD_START_ROUTINE)start_address;
1107         args -> param = arglist;
1108
1109       GC_need_to_lock = TRUE;
1110       thread_h = _beginthreadex(security, stack_size,
1111                  (unsigned (__stdcall *) (void *))GC_win32_start,
1112                                 args, initflag, thrdaddr);
1113       if( thread_h == 0 ) GC_free( args );
1114       return thread_h;
1115     }
1116 }
1117
1118 void GC_endthreadex(unsigned retval)
1119 {
1120   GC_unregister_my_thread();
1121   _endthreadex(retval);
1122 }
1123
1124 #endif /* !GC_PTHREADS */
1125
1126 #ifdef MSWINCE
1127
1128 typedef struct {
1129     HINSTANCE hInstance;
1130     HINSTANCE hPrevInstance;
1131     LPWSTR lpCmdLine;
1132     int nShowCmd;
1133 } main_thread_args;
1134
1135 DWORD WINAPI main_thread_start(LPVOID arg);
1136
1137 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
1138                    LPWSTR lpCmdLine, int nShowCmd)
1139 {
1140     DWORD exit_code = 1;
1141
1142     main_thread_args args = {
1143         hInstance, hPrevInstance, lpCmdLine, nShowCmd
1144     };
1145     HANDLE thread_h;
1146     DWORD thread_id;
1147
1148     /* initialize everything */
1149     GC_init();
1150
1151     /* start the main thread */
1152     thread_h = GC_CreateThread(
1153         NULL, 0, main_thread_start, &args, 0, &thread_id);
1154
1155     if (thread_h != NULL)
1156     {
1157         WaitForSingleObject (thread_h, INFINITE);
1158         GetExitCodeThread (thread_h, &exit_code);
1159         CloseHandle (thread_h);
1160     }
1161
1162     GC_deinit();
1163     DeleteCriticalSection(&GC_allocate_ml);
1164
1165     return (int) exit_code;
1166 }
1167
1168 DWORD WINAPI main_thread_start(LPVOID arg)
1169 {
1170     main_thread_args * args = (main_thread_args *) arg;
1171
1172     return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
1173                                args->lpCmdLine, args->nShowCmd);
1174 }
1175
1176 # else /* !MSWINCE */
1177
1178 /* Called by GC_init() - we hold the allocation lock.   */
1179 void GC_thr_init(void) {
1180     struct GC_stack_base sb;
1181     int sb_result;
1182
1183     GC_ASSERT(I_HOLD_LOCK());
1184     if (GC_thr_initialized) return;
1185     GC_main_thread = GetCurrentThreadId();
1186     GC_thr_initialized = TRUE;
1187
1188     /* Add the initial thread, so we can stop it.       */
1189     sb_result = GC_get_stack_base(&sb);
1190     GC_ASSERT(sb_result == GC_SUCCESS);
1191     GC_register_my_thread(&sb);
1192 }
1193
1194 #ifdef GC_PTHREADS
1195
1196 struct start_info {
1197     void *(*start_routine)(void *);
1198     void *arg;
1199     GC_bool detached;
1200 };
1201
1202 int GC_pthread_join(pthread_t pthread_id, void **retval) {
1203     int result;
1204     int i;
1205     GC_thread joinee;
1206
1207 #   if DEBUG_CYGWIN_THREADS
1208       GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
1209                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
1210 #   endif
1211 #   if DEBUG_WIN32_PTHREADS
1212       GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
1213                 (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
1214 #   endif
1215
1216     if (!parallel_initialized) GC_init_parallel();
1217     /* Thread being joined might not have registered itself yet. */
1218     /* After the join,thread id may have been recycled.          */
1219     /* FIXME: It would be better if this worked more like        */
1220     /* pthread_support.c.                                        */
1221
1222     #ifndef GC_WIN32_PTHREADS
1223       while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10);
1224     #endif
1225
1226     result = pthread_join(pthread_id, retval);
1227
1228     #ifdef GC_WIN32_PTHREADS
1229       /* win32_pthreads id are unique */
1230       joinee = GC_lookup_pthread(pthread_id);
1231     #endif
1232
1233     if (!GC_win32_dll_threads) {
1234       LOCK();
1235       GC_delete_gc_thread(joinee);
1236       UNLOCK();
1237     } /* otherwise dllmain handles it.  */
1238
1239 #   if DEBUG_CYGWIN_THREADS
1240       GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
1241                  (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
1242 #   endif
1243 #   if DEBUG_WIN32_PTHREADS
1244       GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
1245                 (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
1246 #   endif
1247
1248     return result;
1249 }
1250
1251 /* Cygwin-pthreads calls CreateThread internally, but it's not
1252  * easily interceptible by us..
1253  *   so intercept pthread_create instead
1254  */
1255 int
1256 GC_pthread_create(pthread_t *new_thread,
1257                   const pthread_attr_t *attr,
1258                   void *(*start_routine)(void *), void *arg) {
1259     int result;
1260     struct start_info * si;
1261
1262     if (!parallel_initialized) GC_init_parallel();
1263                 /* make sure GC is initialized (i.e. main thread is attached) */
1264     if (GC_win32_dll_threads) {
1265       return pthread_create(new_thread, attr, start_routine, arg);
1266     }
1267     
1268     /* This is otherwise saved only in an area mmapped by the thread */
1269     /* library, which isn't visible to the collector.            */
1270     si = GC_malloc_uncollectable(sizeof(struct start_info)); 
1271     if (0 == si) return(EAGAIN);
1272
1273     si -> start_routine = start_routine;
1274     si -> arg = arg;
1275     if (attr != 0 &&
1276         pthread_attr_getdetachstate(attr, &si->detached)
1277         == PTHREAD_CREATE_DETACHED) {
1278       si->detached = TRUE;
1279     }
1280
1281 #   if DEBUG_CYGWIN_THREADS
1282       GC_printf("About to create a thread from 0x%x(0x%x)\n",
1283                 (int)pthread_self(), GetCurrentThreadId);
1284 #   endif
1285 #   if DEBUG_WIN32_PTHREADS
1286       GC_printf("About to create a thread from 0x%x(0x%x)\n",
1287                 (int)(pthread_self()).p, GetCurrentThreadId());
1288 #   endif
1289     GC_need_to_lock = TRUE;
1290     result = pthread_create(new_thread, attr, GC_pthread_start, si); 
1291
1292     if (result) { /* failure */
1293         GC_free(si);
1294     } 
1295
1296     return(result);
1297 }
1298
1299 void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg)
1300 {
1301     struct start_info * si = arg;
1302     void * result;
1303     void *(*start)(void *);
1304     void *start_arg;
1305     DWORD thread_id = GetCurrentThreadId();
1306     pthread_t pthread_id = pthread_self();
1307     GC_thread me;
1308     GC_bool detached;
1309     int i;
1310
1311 #   if DEBUG_CYGWIN_THREADS
1312       GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id,
1313                                                   thread_id);
1314 #   endif
1315 #   if DEBUG_WIN32_PTHREADS
1316       GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p,
1317                                                   thread_id);
1318 #   endif
1319
1320     GC_ASSERT(!GC_win32_dll_threads);
1321     /* If a GC occurs before the thread is registered, that GC will     */
1322     /* ignore this thread.  That's fine, since it will block trying to  */
1323     /* acquire the allocation lock, and won't yet hold interesting      */
1324     /* pointers.                                                        */
1325     LOCK();
1326     /* We register the thread here instead of in the parent, so that    */
1327     /* we don't need to hold the allocation lock during pthread_create. */
1328     me = GC_register_my_thread_inner(sb, thread_id);
1329     SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
1330     UNLOCK();
1331
1332     start = si -> start_routine;
1333     start_arg = si -> arg;
1334     if (si-> detached) me -> flags |= DETACHED;
1335     me -> pthread_id = pthread_id;
1336
1337     GC_free(si); /* was allocated uncollectable */
1338
1339     pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
1340     result = (*start)(start_arg);
1341     me -> status = result;
1342     pthread_cleanup_pop(1);
1343
1344 #   if DEBUG_CYGWIN_THREADS
1345       GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
1346                 (int)pthread_self(),GetCurrentThreadId());
1347 #   endif
1348 #   if DEBUG_WIN32_PTHREADS
1349       GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
1350                 (int)(pthread_self()).p, GetCurrentThreadId());
1351 #   endif
1352
1353     return(result);
1354 }
1355
1356 void * GC_pthread_start(void * arg)
1357 {
1358     return GC_call_with_stack_base(GC_pthread_start_inner, arg);
1359 }
1360
1361 void GC_thread_exit_proc(void *arg)
1362 {
1363     GC_thread me = (GC_thread)arg;
1364     int i;
1365
1366     GC_ASSERT(!GC_win32_dll_threads);
1367 #   if DEBUG_CYGWIN_THREADS
1368       GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
1369                 (int)pthread_self(),GetCurrentThreadId());
1370 #   endif
1371 #   if DEBUG_WIN32_PTHREADS
1372       GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
1373                 (int)(pthread_self()).p,GetCurrentThreadId());
1374 #   endif
1375
1376     LOCK();
1377 #   if defined(THREAD_LOCAL_ALLOC)
1378       GC_destroy_thread_local(&(me->tlfs));
1379 #   endif
1380     if (me -> flags & DETACHED) {
1381       GC_delete_thread(GetCurrentThreadId());
1382     } else {
1383       /* deallocate it as part of join */
1384       me -> flags |= FINISHED;
1385     }
1386     UNLOCK();
1387 }
1388
1389 #ifndef GC_WIN32_PTHREADS
1390 /* win32 pthread does not support sigmask */
1391 /* nothing required here... */
1392 int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
1393   if (!parallel_initialized) GC_init_parallel();
1394   return pthread_sigmask(how, set, oset);
1395 }
1396 #endif
1397
1398 int GC_pthread_detach(pthread_t thread)
1399 {
1400     int result;
1401     GC_thread thread_gc_id;
1402     
1403     if (!parallel_initialized) GC_init_parallel();
1404     LOCK();
1405     thread_gc_id = GC_lookup_pthread(thread);
1406     UNLOCK();
1407     result = pthread_detach(thread);
1408     if (result == 0) {
1409       LOCK();
1410       thread_gc_id -> flags |= DETACHED;
1411       /* Here the pthread thread id may have been recycled. */
1412       if (thread_gc_id -> flags & FINISHED) {
1413         GC_delete_gc_thread(thread_gc_id);
1414       }
1415       UNLOCK();
1416     }
1417     return result;
1418 }
1419
1420 #else /* !GC_PTHREADS */
1421
1422 /*
1423  * We avoid acquiring locks here, since this doesn't seem to be preemptable.
1424  * This may run with an uninitialized collector, in which case we don't do much.
1425  * This implies that no threads other than the main one should be created
1426  * with an uninitialized collector.  (The alternative of initializing
1427  * the collector here seems dangerous, since DllMain is limited in what it
1428  * can do.)
1429  */
1430 #ifdef GC_DLL
1431 GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
1432 {
1433   struct GC_stack_base sb;
1434   DWORD thread_id;
1435   int sb_result;
1436   static int entry_count = 0;
1437
1438   if (parallel_initialized && !GC_win32_dll_threads) return TRUE;
1439
1440   switch (reason) {
1441    case DLL_THREAD_ATTACH:
1442     GC_ASSERT(entry_count == 0 || parallel_initialized);
1443     ++entry_count; /* and fall through: */
1444    case DLL_PROCESS_ATTACH:
1445     /* This may run with the collector uninitialized. */
1446     thread_id = GetCurrentThreadId();
1447     if (parallel_initialized && GC_main_thread != thread_id) {
1448         /* Don't lock here.     */
1449         sb_result = GC_get_stack_base(&sb);
1450         GC_ASSERT(sb_result == GC_SUCCESS);
1451 #       ifdef THREAD_LOCAL_ALLOC
1452           ABORT("Cannot initialize thread local cache from DllMain");
1453 #       endif
1454         GC_register_my_thread_inner(&sb, thread_id);
1455     } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
1456     break;
1457
1458    case DLL_THREAD_DETACH:
1459     /* We are hopefully running in the context of the exiting thread.   */
1460     GC_ASSERT(parallel_initialized);
1461     if (!GC_win32_dll_threads) return TRUE;
1462     GC_delete_thread(GetCurrentThreadId());
1463     break;
1464
1465    case DLL_PROCESS_DETACH:
1466     {
1467       int i;
1468
1469       if (!GC_win32_dll_threads) return TRUE;
1470       for (i = 0; i <= GC_get_max_thread_index(); ++i)
1471       {
1472           if (AO_load(&(dll_thread_table[i].in_use)))
1473             GC_delete_gc_thread(dll_thread_table + i);
1474       }
1475
1476       GC_deinit();
1477       DeleteCriticalSection(&GC_allocate_ml);
1478     }
1479     break;
1480
1481   }
1482   return TRUE;
1483 }
1484 #endif /* GC_DLL */
1485 #endif /* !GC_PTHREADS */
1486
1487 # endif /* !MSWINCE */
1488
1489 /* Perform all initializations, including those that    */
1490 /* may require allocation.                              */
1491 /* Called without allocation lock.                      */
1492 /* Must be called before a second thread is created.    */
1493 void GC_init_parallel(void)
1494 {
1495     if (parallel_initialized) return;
1496     parallel_initialized = TRUE;
1497     /* GC_init() calls us back, so set flag first.      */
1498     
1499     if (!GC_is_initialized) GC_init();
1500     if (GC_win32_dll_threads) {
1501       GC_need_to_lock = TRUE;
1502         /* Cannot intercept thread creation.  Hence we don't know if    */
1503         /* other threads exist.  However, client is not allowed to      */
1504         /* create other threads before collector initialization.        */
1505         /* Thus it's OK not to lock before this.                        */
1506     }
1507     /* Initialize thread local free lists if used.      */
1508 #   if defined(THREAD_LOCAL_ALLOC)
1509       LOCK();
1510       GC_init_thread_local(&(GC_lookup_thread(GetCurrentThreadId())->tlfs));
1511       UNLOCK();
1512 #   endif
1513 }
1514
1515 #if defined(USE_PTHREAD_LOCKS)
1516   /* Support for pthread locking code.          */
1517   /* Pthread_mutex_try_lock may not win here,   */
1518   /* due to builtinsupport for spinning first?  */
1519
1520 volatile GC_bool GC_collecting = 0;
1521                         /* A hint that we're in the collector and       */
1522                         /* holding the allocation lock for an           */
1523                         /* extended period.                             */
1524
1525 void GC_lock(void)
1526 {
1527     pthread_mutex_lock(&GC_allocate_ml);
1528 }
1529 #endif /* USE_PTHREAD ... */
1530
1531 # if defined(THREAD_LOCAL_ALLOC)
1532
1533 /* Add thread-local allocation support.  Microsoft uses __declspec(thread) */
1534
1535 /* We must explicitly mark ptrfree and gcj free lists, since the free   */
1536 /* list links wouldn't otherwise be found.  We also set them in the     */
1537 /* normal free lists, since that involves touching less memory than if  */
1538 /* we scanned them normally.                                            */
1539 void GC_mark_thread_local_free_lists(void)
1540 {
1541     int i;
1542     GC_thread p;
1543     
1544     for (i = 0; i < THREAD_TABLE_SZ; ++i) {
1545       for (p = GC_threads[i]; 0 != p; p = p -> next) {
1546         GC_mark_thread_local_fls_for(&(p->tlfs));
1547       }
1548     }
1549 }
1550
1551 #if defined(GC_ASSERTIONS)
1552     /* Check that all thread-local free-lists are completely marked.    */
1553     /* also check that thread-specific-data structures are marked.      */
1554     void GC_check_tls(void) {
1555         int i;
1556         GC_thread p;
1557         
1558         for (i = 0; i < THREAD_TABLE_SZ; ++i) {
1559           for (p = GC_threads[i]; 0 != p; p = p -> next) {
1560             GC_check_tls_for(&(p->tlfs));
1561           }
1562         }
1563 #       if defined(USE_CUSTOM_SPECIFIC)
1564           if (GC_thread_key != 0)
1565             GC_check_tsd_marks(GC_thread_key);
1566 #       endif 
1567     }
1568 #endif /* GC_ASSERTIONS */
1569
1570 #endif /* THREAD_LOCAL_ALLOC ... */
1571
1572 #endif /* GC_WIN32_THREADS */