void GC_start_world(void) { DWORD thread_id = GetCurrentThreadId(); int i; LONG my_max = GC_get_max_thread_index(); GC_ASSERT(I_HOLD_LOCK()); if (GC_win32_dll_threads) { for (i = 0; i <= my_max; i++) { GC_thread t = (GC_thread)(dll_thread_table + i); if (t -> stack_base != 0 && t -> suspended && t -> id != thread_id) { if (ResumeThread(t -> handle) == (DWORD)-1) ABORT("ResumeThread failed"); t -> suspended = FALSE; } } } else { GC_thread t; int i; for (i = 0; i < THREAD_TABLE_SZ; i++) { for (t = GC_threads[i]; t != 0; t = t -> next) { if (t -> stack_base != 0 && t -> suspended && t -> id != thread_id) { if (ResumeThread(t -> handle) == (DWORD)-1) ABORT("ResumeThread failed"); t -> suspended = FALSE; } } } } GC_please_stop = FALSE; }
void GC_push_thread_structures(void) { GC_ASSERT(I_HOLD_LOCK()); if (GC_win32_dll_threads) { /* Unlike the other threads implementations, the thread table here */ /* contains no pointers to the collectable heap. Thus we have */ /* no private structures we need to preserve. */ # ifdef GC_PTHREADS { int i; /* pthreads may keep a pointer in the thread exit value */ LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max; i++) if (dll_thread_table[i].in_use) GC_push_all((ptr_t)&(dll_thread_table[i].status), (ptr_t)(&(dll_thread_table[i].status)+1)); } # endif } else { GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads)); } # if defined(THREAD_LOCAL_ALLOC) GC_push_all((ptr_t)(&GC_thread_key), (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key)); /* Just in case we ever use our own TLS implementation. */ # endif }
static GC_thread GC_lookup_thread(DWORD id) { int i; LONG max = GC_get_max_thread_index(); for (i = 0; i <= max; i++) if (thread_table[i].in_use && thread_table[i].id == id) return &thread_table[i]; return NULL; }
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; }
/* have not yet terminated or are still joinable. */ static GC_thread GC_lookup_thread(pthread_t 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].pthread_id != id || !thread_table[i].in_use); /* Must still be in_use, since nobody else can store our thread_id. */ i++); if (i > my_max) return 0; return thread_table + i; }
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); } }
void GC_stop_world(void) { DWORD thread_id = GetCurrentThreadId(); int i; if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()"); GC_ASSERT(I_HOLD_LOCK()); GC_please_stop = TRUE; # ifndef CYGWIN32 EnterCriticalSection(&GC_write_cs); # endif if (GC_win32_dll_threads) { /* Any threads being created during this loop will end up setting */ /* GC_attached_thread when they start. This will force marking to */ /* restart. */ /* This is not ideal, but hopefully correct. */ GC_attached_thread = FALSE; for (i = 0; i <= GC_get_max_thread_index(); i++) { GC_vthread t = dll_thread_table + i; if (t -> stack_base != 0 && t -> id != thread_id) { GC_suspend((GC_thread)t); } } } else { GC_thread t; int i; for (i = 0; i < THREAD_TABLE_SZ; i++) { for (t = GC_threads[i]; t != 0; t = t -> next) { if (t -> stack_base != 0 && !KNOWN_FINISHED(t) && t -> id != thread_id) { GC_suspend(t); } } } } # ifndef CYGWIN32 LeaveCriticalSection(&GC_write_cs); # endif }
void GC_push_all_stacks(void) { DWORD me = GetCurrentThreadId(); GC_bool found_me = FALSE; size_t nthreads = 0; if (GC_win32_dll_threads) { int i; LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max; i++) { GC_thread t = (GC_thread)(dll_thread_table + i); if (t -> in_use) { ++nthreads; GC_push_stack_for(t); if (t -> id == me) found_me = TRUE; } } } else { GC_thread t; int i; for (i = 0; i < THREAD_TABLE_SZ; i++) { for (t = GC_threads[i]; t != 0; t = t -> next) { ++nthreads; if (!KNOWN_FINISHED(t)) GC_push_stack_for(t); if (t -> id == me) found_me = TRUE; } } } if (GC_print_stats == VERBOSE) { GC_log_printf("Pushed %d thread stacks ", nthreads); if (GC_win32_dll_threads) { GC_log_printf("based on DllMain thread tracking\n"); } else { GC_log_printf("\n"); } } if (!found_me && !GC_in_thread_creation) ABORT("Collecting from unknown thread."); }
/* Assumes we do NOT hold the allocation lock. */ static GC_thread GC_lookup_pthread(pthread_t id) { if (GC_win32_dll_threads) { int i; LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max && (!AO_load_acquire(&(dll_thread_table[i].in_use)) || THREAD_EQUAL(dll_thread_table[i].pthread_id, id)); /* Must still be in_use, since nobody else can store our thread_id. */ i++); if (i > my_max) return 0; return (GC_thread)(dll_thread_table + i); } else { /* We first try the cache. If that fails, we use a very slow */ /* approach. */ int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ; int hv; GC_thread p; LOCK(); for (p = GC_threads[hv_guess]; 0 != p; p = p -> next) { if (THREAD_EQUAL(p -> pthread_id, id)) goto foundit; } for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) { for (p = GC_threads[hv]; 0 != p; p = p -> next) { if (THREAD_EQUAL(p -> pthread_id, id)) goto foundit; } } p = 0; foundit: UNLOCK(); return p; } }
void GC_get_next_stack(char *start, char **lo, char **hi) { int i; # define ADDR_LIMIT (char *)(-1L) char * current_min = ADDR_LIMIT; if (GC_win32_dll_threads) { LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max; i++) { ptr_t s = (ptr_t)(dll_thread_table[i].stack_base); if (0 != s && s > start && s < current_min) { current_min = s; } } } else { for (i = 0; i < THREAD_TABLE_SZ; i++) { GC_thread t; for (t = GC_threads[i]; t != 0; t = t -> next) { ptr_t s = (ptr_t)(t -> stack_base); if (0 != s && s > start && s < current_min) { current_min = s; } } } } *hi = current_min; if (current_min == ADDR_LIMIT) { *lo = ADDR_LIMIT; return; } *lo = GC_get_stack_min(current_min); if (*lo < start) *lo = start; }
/* Also used (for assertion checking only) from thread_local_alloc.c. */ GC_thread GC_lookup_thread_inner(DWORD thread_id) { if (GC_win32_dll_threads) { int i; LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max && (!AO_load_acquire(&(dll_thread_table[i].in_use)) || dll_thread_table[i].id != thread_id); /* Must still be in_use, since nobody else can store our thread_id. */ i++) {} if (i > my_max) { return 0; } else { return (GC_thread)(dll_thread_table + i); } } else { word hv = ((word)thread_id) % THREAD_TABLE_SZ; register GC_thread p = GC_threads[hv]; GC_ASSERT(I_HOLD_LOCK()); while (p != 0 && p -> id != thread_id) p = p -> next; return(p); } }
if (thread_table[i].in_use && thread_table[i].id == id) return &thread_table[i]; return NULL; } #endif /* CYGWIN32 */ void GC_push_thread_structures GC_PROTO((void)) { /* Unlike the other threads implementations, the thread table here */ /* contains no pointers to the collectable heap. Thus we have */ /* no private structures we need to preserve. */ # ifdef CYGWIN32 { int i; /* pthreads may keep a pointer in the thread exit value */ LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max; i++) if (thread_table[i].in_use) GC_push_all((ptr_t)&(thread_table[i].status), (ptr_t)(&(thread_table[i].status)+1)); } # endif } /* Wrappers for functions that are likely to block for an appreciable */ /* length of time. Must be called in pairs, if at all. */ /* Nothing much beyond the system call itself should be executed */ /* between these. */ void GC_start_blocking(void) {