void GC_suspend_handler(int sig) { int dummy; GC_thread me; sigset_t all_sigs; sigset_t old_sigs; int i; if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler"); me = GC_lookup_thread(pthread_self()); /* The lookup here is safe, since I'm doing this on behalf */ /* of a thread which holds the allocation lock in order */ /* to stop the world. Thus concurrent modification of the */ /* data structure is impossible. */ if (PLEASE_STOP != me -> stop) { /* Misdirected signal. */ pthread_mutex_unlock(&GC_suspend_lock); return; } pthread_mutex_lock(&GC_suspend_lock); me -> stack_hot = (ptr_t)(&dummy); me -> stop = STOPPED; pthread_cond_signal(&GC_suspend_ack_cv); pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock); pthread_mutex_unlock(&GC_suspend_lock); /* GC_printf1("Continuing 0x%x\n", pthread_self()); */ }
GC_API int GC_register_my_thread(struct GC_stack_base *sb) { DWORD t = GetCurrentThreadId(); if (0 == GC_lookup_thread(t)) { /* We lock here, since we want to wait for an ongoing GC. */ LOCK(); GC_register_my_thread_inner(sb, t); UNLOCK(); return GC_SUCCESS; } else { return GC_DUPLICATE; } }
int GC_pthread_detach(pthread_t thread) { GC_thread t; LOCK(); t=GC_lookup_thread(thread); UNLOCK(); if (t) { LOCK(); t->flags |= DETACHED; UNLOCK(); return 0; } else return pthread_detach(thread); }
GC_PTR GC_local_malloc(size_t bytes) { if (EXPECT(!SMALL_ENOUGH(bytes),0)) { return(GC_malloc(bytes)); } else { int index = INDEX_FROM_BYTES(bytes); ptr_t * my_fl; ptr_t my_entry; # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) GC_key_t k = GC_thread_key; # endif void * tsd; # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) if (EXPECT(0 == k, 0)) { /* This can happen if we get called when the world is */ /* being initialized. Whether we can actually complete */ /* the initialization then is unclear. */ GC_init_parallel(); k = GC_thread_key; } # endif tsd = GC_getspecific(GC_thread_key); # ifdef GC_ASSERTIONS LOCK(); GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self())); UNLOCK(); # endif my_fl = ((GC_thread)tsd) -> normal_freelists + index; my_entry = *my_fl; if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { ptr_t next = obj_link(my_entry); GC_PTR result = (GC_PTR)my_entry; *my_fl = next; obj_link(my_entry) = 0; PREFETCH_FOR_WRITE(next); return result; } else if ((word)my_entry - 1 < DIRECT_GRANULES) { *my_fl = my_entry + index + 1; return GC_malloc(bytes); } else { GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl); if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_malloc(bytes); } } }
/* Must be called before a second thread is created. */ void GC_init_parallel(void) { if (parallel_initialized) return; parallel_initialized = TRUE; /* GC_init() calls us back, so set flag first. */ if (!GC_is_initialized) GC_init(); if (GC_win32_dll_threads) { GC_need_to_lock = TRUE; /* Cannot intercept thread creation. Hence we don't know if */ /* other threads exist. However, client is not allowed to */ /* create other threads before collector initialization. */ /* Thus it's OK not to lock before this. */ } /* Initialize thread local free lists if used. */ # if defined(THREAD_LOCAL_ALLOC) LOCK(); GC_init_thread_local(&(GC_lookup_thread(GetCurrentThreadId())->tlfs)); UNLOCK(); # endif }