/* survives in the child. */ void GC_remove_all_threads_but_me(void) { pthread_t self = pthread_self(); int hv; GC_thread p, next, me; for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) { me = 0; for (p = GC_threads[hv]; 0 != p; p = next) { next = p -> next; if (THREAD_EQUAL(p -> id, self)) { me = p; p -> next = 0; } else { # ifdef THREAD_LOCAL_ALLOC if (!(p -> flags & FINISHED)) { GC_destroy_thread_local(&(p->tlfs)); } # endif /* THREAD_LOCAL_ALLOC */ if (p != &first_thread) GC_INTERNAL_FREE(p); } } GC_threads[hv] = me; } }
/* 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); } }
static GC_bool ensure_toggleref_capacity(int capacity_inc) { GC_ASSERT(capacity_inc >= 0); if (NULL == GC_toggleref_arr) { GC_toggleref_array_capacity = 32; /* initial capacity */ GC_toggleref_arr = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE( GC_toggleref_array_capacity * sizeof(GCToggleRef), NORMAL); if (NULL == GC_toggleref_arr) return FALSE; } if ((unsigned)GC_toggleref_array_size + (unsigned)capacity_inc >= (unsigned)GC_toggleref_array_capacity) { GCToggleRef *new_array; while ((unsigned)GC_toggleref_array_capacity < (unsigned)GC_toggleref_array_size + (unsigned)capacity_inc) { GC_toggleref_array_capacity *= 2; if (GC_toggleref_array_capacity < 0) /* overflow */ return FALSE; } new_array = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE( GC_toggleref_array_capacity * sizeof(GCToggleRef), NORMAL); if (NULL == new_array) return FALSE; BCOPY(GC_toggleref_arr, new_array, GC_toggleref_array_size * sizeof(GCToggleRef)); GC_INTERNAL_FREE(GC_toggleref_arr); GC_toggleref_arr = new_array; } return TRUE; }
/* (The code intentionally traps if it wasn't.) */ void GC_delete_thread(pthread_t id) { int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ; register GC_thread p = GC_threads[hv]; register GC_thread prev = 0; GC_ASSERT(I_HOLD_LOCK()); while (!THREAD_EQUAL(p -> id, id)) { prev = p; p = p -> next; } if (prev == 0) { GC_threads[hv] = p -> next; } else { prev -> next = p -> next; } # ifdef GC_DARWIN_THREADS mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread); # endif GC_INTERNAL_FREE(p); }
/* thread being deleted. */ void GC_delete_gc_thread(GC_vthread gc_id) { CloseHandle(gc_id->handle); if (GC_win32_dll_threads) { /* This is intended to be lock-free. */ /* It is either called synchronously from the thread being deleted, */ /* or by the joining thread. */ /* In this branch asynchronosu changes to *gc_id are possible. */ gc_id -> stack_base = 0; gc_id -> id = 0; # ifdef CYGWIN32 gc_id -> pthread_id = 0; # endif /* CYGWIN32 */ # ifdef GC_WIN32_PTHREADS gc_id -> pthread_id.p = NULL; # endif /* GC_WIN32_PTHREADS */ AO_store_release(&(gc_id->in_use), FALSE); } else { /* Cast away volatile qualifier, since we have lock. */ GC_thread gc_nvid = (GC_thread)gc_id; DWORD id = gc_nvid -> id; 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 != gc_nvid) { prev = p; p = p -> next; } if (prev == 0) { GC_threads[hv] = p -> next; } else { prev -> next = p -> next; } GC_INTERNAL_FREE(p); } }