-@@ -527,22 +566,11 @@
-
- LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
-
--#ifdef GC_DLL
--
--/*
-- * This isn't generally safe, since DllMain is not premptible.
-- * If another thread holds the lock while this runs we're in trouble.
-- * Pontus Rydin suggests wrapping the thread start routine instead.
-+/* threadAttach/threadDetach routines used by both CYGWIN and DLL
-+ * implementation, since both recieve explicit notification on thread
-+ * creation/destruction.
- */
--BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
--{
-- switch (reason) {
-- case DLL_PROCESS_ATTACH:
-- InitializeCriticalSection(&GC_allocate_ml);
-- GC_init(); /* Force initialization before thread attach. */
-- /* fall through */
-- case DLL_THREAD_ATTACH:
-- {
-+static void threadAttach() {
- int i;
- /* It appears to be unsafe to acquire a lock here, since this */
- /* code is apparently not preeemptible on some systems. */
-@@ -554,14 +582,11 @@
- /* The following should be a noop according to the win32 */
- /* documentation. There is empirical evidence that it */
- /* isn't. - HB */
--# ifdef MPROTECT_VDB
-+# if defined(MPROTECT_VDB)
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
- # endif
--
-- for (i = 0;
- /* cast away volatile qualifier */
-- InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
-- i++) {
-+ for (i = 0; InterlockedExchange((LONG*)&thread_table[i].in_use,1) != 0; i++) {
- /* Compare-and-swap would make this cleaner, but that's not */
- /* supported before Windows 98 and NT 4.0. In Windows 2000, */
- /* InterlockedExchange is supposed to be replaced by */
-@@ -571,11 +596,13 @@
- ABORT("too many threads");
- }
- thread_table[i].id = GetCurrentThreadId();
-+# ifdef CYGWIN32
-+ thread_table[i].pthread_id = pthread_self();
-+# endif
- if (!DuplicateHandle(GetCurrentProcess(),
- GetCurrentThread(),
- GetCurrentProcess(),
-- /* cast away volatile qualifier */
-- (HANDLE *) &thread_table[i].handle,
-+ (HANDLE*)&thread_table[i].handle,
- 0,
- 0,
- DUPLICATE_SAME_ACCESS)) {
-@@ -584,33 +611,226 @@
- ABORT("DuplicateHandle failed");
- }
- thread_table[i].stack = GC_get_stack_base();
-+ if (thread_table[i].stack == NULL)
-+ ABORT("Failed to find stack base in threadAttach");
- /* If this thread is being created while we are trying to stop */
- /* the world, wait here. Hopefully this can't happen on any */
- /* systems that don't allow us to block here. */
- while (GC_please_stop) Sleep(20);
-- }
-- break;
-- case DLL_THREAD_DETACH:
-- {
-+}
-+
-+static void threadDetach(DWORD thread_id) {
- int i;
-- DWORD thread_id = GetCurrentThreadId();
-+
- LOCK();
- for (i = 0;
- i < MAX_THREADS &&
-- (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
-+ !thread_table[i].in_use || thread_table[i].id != thread_id;
- i++) {}
-- if (i >= MAX_THREADS) {
-+ if (i >= MAX_THREADS ) {
- WARN("thread %ld not found on detach", (GC_word)thread_id);
-- } else {
-+ }
-+ else {
- thread_table[i].stack = 0;
- thread_table[i].in_use = FALSE;
- CloseHandle(thread_table[i].handle);
- /* cast away volatile qualifier */
-- BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
-+ BZERO((void *)&thread_table[i].context, sizeof(CONTEXT));
-+ }
-+ UNLOCK();
-+}
-+
-+#ifdef CYGWIN32
-+
-+/* Called by GC_init() - we hold the allocation lock. */
-+void GC_thr_init() {
-+ if (GC_thr_initialized) return;
-+ GC_thr_initialized = TRUE;
-+
-+#if 0
-+ /* this might already be handled in GC_init... */
-+ InitializeCriticalSection(&GC_allocate_ml);
-+#endif
-+
-+ /* Add the initial thread, so we can stop it. */
-+ threadAttach();
-+}
-+
-+struct start_info {
-+ void *(*start_routine)(void *);
-+ void *arg;
-+};
-+
-+int GC_pthread_join(pthread_t pthread_id, void **retval) {
-+ int result;
-+ int i;
-+
-+# if DEBUG_CYGWIN_THREADS
-+ GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",(int)pthread_self(),
-+ GetCurrentThreadId(), (int)pthread_id);
-+# endif
-+
-+ /* Can't do any table lookups here, because thread being joined
-+ might not have registered itself yet */
-+
-+ result = pthread_join(pthread_id, retval);
-+
-+ LOCK();
-+ for (i = 0; !thread_table[i].in_use || thread_table[i].pthread_id != pthread_id;
-+ i++) {
-+ if (i == MAX_THREADS - 1) {
-+ GC_printf1("Failed to find thread 0x%x in pthread_join()\n", pthread_id);
-+ ABORT("thread not found on detach");
-+ }
- }
- UNLOCK();
-+ threadDetach(thread_table[i].id);
-+
-+# if DEBUG_CYGWIN_THREADS
-+ GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
-+ (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
-+# endif
-+
-+ return result;
-+}
-+
-+/* Cygwin-pthreads calls CreateThread internally, but it's not
-+ * easily interceptible by us..
-+ * so intercept pthread_create instead
-+ */
-+int
-+GC_pthread_create(pthread_t *new_thread,
-+ const pthread_attr_t *attr,
-+ void *(*start_routine)(void *), void *arg) {
-+ int result;
-+ struct start_info * si;
-+
-+ if (!GC_is_initialized) GC_init();
-+ /* make sure GC is initialized (i.e. main thread is attached) */
-+
-+ /* This is otherwise saved only in an area mmapped by the thread */
-+ /* library, which isn't visible to the collector. */
-+ si = GC_malloc_uncollectable(sizeof(struct start_info));
-+ if (0 == si) return(EAGAIN);
-+
-+ si -> start_routine = start_routine;
-+ si -> arg = arg;
-+
-+# if DEBUG_CYGWIN_THREADS
-+ GC_printf2("About to create a thread from 0x%x(0x%x)\n",(int)pthread_self(),
-+ GetCurrentThreadId);
-+# endif
-+ result = pthread_create(new_thread, attr, GC_start_routine, si);
-+
-+ if (result) { /* failure */
-+ GC_free(si);
-+ }
-+
-+ return(result);
-+}
-+
-+void * GC_start_routine(void * arg)
-+{
-+ struct start_info * si = arg;
-+ void * result;
-+ void *(*start)(void *);
-+ void *start_arg;
-+ pthread_t pthread_id;
-+ int i;
-+
-+# if DEBUG_CYGWIN_THREADS
-+ GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
-+ GetCurrentThreadId());
-+# endif
-+
-+ /* If a GC occurs before the thread is registered, that GC will */
-+ /* ignore this thread. That's fine, since it will block trying to */
-+ /* acquire the allocation lock, and won't yet hold interesting */
-+ /* pointers. */
-+ LOCK();
-+ /* We register the thread here instead of in the parent, so that */
-+ /* we don't need to hold the allocation lock during pthread_create. */
-+ threadAttach();
-+ UNLOCK();
-+
-+ start = si -> start_routine;
-+ start_arg = si -> arg;
-+ pthread_id = pthread_self();
-+
-+ GC_free(si); /* was allocated uncollectable */
-+
-+ pthread_cleanup_push(GC_thread_exit_proc, pthread_id);
-+ result = (*start)(start_arg);
-+ pthread_cleanup_pop(0);
-+
-+# if DEBUG_CYGWIN_THREADS
-+ GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
-+ (int)pthread_self(),GetCurrentThreadId());
-+# endif
-+
-+ LOCK();
-+ for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
-+ if (i == MAX_THREADS - 1)
-+ ABORT("thread not found on exit");
-+ }
-+ thread_table[i].status = result;
-+ UNLOCK();
-+
-+ return(result);
-+}
-+
-+void GC_thread_exit_proc(void *arg)
-+{
-+ pthread_t pthread_id = (pthread_t)arg;
-+ int i;
-+
-+# if DEBUG_CYGWIN_THREADS
-+ GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
-+ (int)pthread_self(),GetCurrentThreadId());
-+# endif
-+
-+ LOCK();
-+ for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
-+ if (i == MAX_THREADS - 1)
-+ ABORT("thread not found on exit");
- }
-+ UNLOCK();
-+
-+#if 0
-+ /* TODO: we need a way to get the exit value after a pthread_exit so we can stash it safely away */
-+ thread_table[i].status = ???
-+#endif
-+}
-+
-+/* nothing required here... */
-+int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
-+ return pthread_sigmask(how, set, oset);
-+}
-+int GC_pthread_detach(pthread_t thread) {
-+ return pthread_detach(thread);
-+}
-+#else /* !CYGWIN32 */
-+
-+/*
-+ * We avoid acquiring locks here, since this doesn't seem to be preemptable.
-+ * Pontus Rydin suggests wrapping the thread start routine instead.
-+ */
-+#ifdef GC_DLL
-+BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
-+{
-+ switch (reason) {
-+ case DLL_PROCESS_ATTACH:
-+ InitializeCriticalSection(&GC_allocate_ml);
-+ GC_init(); /* Force initialization before thread attach. */
-+ /* fall through */
-+ case DLL_THREAD_ATTACH:
-+ threadAttach();
-+ break;
-+
-+ case DLL_THREAD_DETACH:
-+ threadDetach(GetCurrentThreadId());
- break;
-+
- case DLL_PROCESS_DETACH:
- {
- int i;
-@@ -636,8 +856,8 @@
- }
- return TRUE;
- }
--
--# endif /* GC_DLL */
-+#endif /* GC_DLL */
-+#endif /* !CYGWIN32 */
-
- # endif /* !MSWINCE */
-