/* Suspend the given thread, if it's still active. */ void GC_suspend(GC_thread t) { # ifdef MSWINCE /* SuspendThread will fail if thread is running kernel code */ while (SuspendThread(t -> handle) == (DWORD)-1) Sleep(10); # else /* Apparently the Windows 95 GetOpenFileName call creates */ /* a thread that does not properly get cleaned up, and */ /* SuspendThread on its descriptor may provoke a crash. */ /* This reduces the probability of that event, though it still */ /* appears there's a race here. */ DWORD exitCode; if (GetExitCodeThread(t -> handle, &exitCode) && exitCode != STILL_ACTIVE) { t -> stack_base = 0; /* prevent stack from being pushed */ # ifndef GC_PTHREADS /* this breaks pthread_join on Cygwin, which is guaranteed to */ /* only see user pthreads */ GC_ASSERT(GC_win32_dll_threads); GC_delete_gc_thread(t); # endif return; } if (SuspendThread(t -> handle) == (DWORD)-1) ABORT("SuspendThread failed"); # endif t -> suspended = TRUE; }
/* thread being deleted. */ void GC_delete_thread(DWORD id) { if (GC_win32_dll_threads) { GC_thread t = GC_lookup_thread_inner(id); if (0 == t) { WARN("Removing nonexistent thread %ld\n", (GC_word)id); } else { GC_delete_gc_thread(t); } } else { word hv = ((word)id) % THREAD_TABLE_SZ; register GC_thread p = GC_threads[hv]; register GC_thread prev = 0; GC_ASSERT(I_HOLD_LOCK()); while (p -> id != id) { prev = p; p = p -> next; } CloseHandle(p->handle); if (prev == 0) { GC_threads[hv] = p -> next; } else { prev -> next = p -> next; } GC_INTERNAL_FREE(p); } }
GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) { struct GC_stack_base sb; DWORD thread_id; int sb_result; static int entry_count = 0; if (parallel_initialized && !GC_win32_dll_threads) return TRUE; switch (reason) { case DLL_THREAD_ATTACH: GC_ASSERT(entry_count == 0 || parallel_initialized); ++entry_count; /* and fall through: */ case DLL_PROCESS_ATTACH: /* This may run with the collector uninitialized. */ thread_id = GetCurrentThreadId(); if (parallel_initialized && GC_main_thread != thread_id) { /* Don't lock here. */ sb_result = GC_get_stack_base(&sb); GC_ASSERT(sb_result == GC_SUCCESS); # ifdef THREAD_LOCAL_ALLOC ABORT("Cannot initialize thread local cache from DllMain"); # endif GC_register_my_thread_inner(&sb, thread_id); } /* o.w. we already did it during GC_thr_init(), called by GC_init() */ break; case DLL_THREAD_DETACH: /* We are hopefully running in the context of the exiting thread. */ GC_ASSERT(parallel_initialized); if (!GC_win32_dll_threads) return TRUE; GC_delete_thread(GetCurrentThreadId()); break; case DLL_PROCESS_DETACH: { int i; if (!GC_win32_dll_threads) return TRUE; for (i = 0; i <= GC_get_max_thread_index(); ++i) { if (AO_load(&(dll_thread_table[i].in_use))) GC_delete_gc_thread(dll_thread_table + i); } GC_deinit(); DeleteCriticalSection(&GC_allocate_ml); } break; } return TRUE; }
static void GC_delete_thread(DWORD thread_id) { int i; LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max && (!thread_table[i].in_use || thread_table[i].id != thread_id); /* Must still be in_use, since nobody else can store our thread_id. */ i++) {} if (i > my_max) { WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id); } else { GC_delete_gc_thread(thread_table+i); } }
int GC_pthread_join(pthread_t pthread_id, void **retval) { int result; int i; GC_thread joinee; # if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); # endif # if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n", (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p); # endif if (!parallel_initialized) GC_init_parallel(); /* Thread being joined might not have registered itself yet. */ /* After the join,thread id may have been recycled. */ /* FIXME: It would be better if this worked more like */ /* pthread_support.c. */ #ifndef GC_WIN32_PTHREADS while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10); #endif result = pthread_join(pthread_id, retval); #ifdef GC_WIN32_PTHREADS /* win32_pthreads id are unique */ joinee = GC_lookup_pthread(pthread_id); #endif if (!GC_win32_dll_threads) { LOCK(); GC_delete_gc_thread(joinee); UNLOCK(); } /* otherwise dllmain handles it. */ # if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); # endif # if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n", (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p); # endif return result; }
int GC_pthread_detach(pthread_t thread) { int result; GC_thread thread_gc_id; if (!parallel_initialized) GC_init_parallel(); LOCK(); thread_gc_id = GC_lookup_pthread(thread); UNLOCK(); result = pthread_detach(thread); if (result == 0) { LOCK(); thread_gc_id -> flags |= DETACHED; /* Here the pthread thread id may have been recycled. */ if (thread_gc_id -> flags & FINISHED) { GC_delete_gc_thread(thread_gc_id); } UNLOCK(); } return result; }