📄 win32_threads.c
字号:
GC_ASSERT(I_HOLD_LOCK()); if (GC_thr_initialized) return; GC_main_thread = GetCurrentThreadId(); GC_thr_initialized = TRUE; /* Add the initial thread, so we can stop it. */ sb_result = GC_get_stack_base(&sb); GC_ASSERT(sb_result == GC_SUCCESS); GC_register_my_thread(&sb);}#ifdef GC_PTHREADSstruct start_info { void *(*start_routine)(void *); void *arg; GC_bool detached;};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;}/* Cygwin-pthreads calls CreateThread internally, but it's not * easily interceptible by us.. * so intercept pthread_create instead */intGC_pthread_create(pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { int result; struct start_info * si; if (!parallel_initialized) GC_init_parallel(); /* make sure GC is initialized (i.e. main thread is attached) */ if (GC_win32_dll_threads) { return pthread_create(new_thread, attr, start_routine, arg); } /* 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 (attr != 0 && pthread_attr_getdetachstate(attr, &si->detached) == PTHREAD_CREATE_DETACHED) { si->detached = TRUE; }# if DEBUG_CYGWIN_THREADS GC_printf("About to create a thread from 0x%x(0x%x)\n", (int)pthread_self(), GetCurrentThreadId);# endif# if DEBUG_WIN32_PTHREADS GC_printf("About to create a thread from 0x%x(0x%x)\n", (int)(pthread_self()).p, GetCurrentThreadId());# endif GC_need_to_lock = TRUE; result = pthread_create(new_thread, attr, GC_pthread_start, si); if (result) { /* failure */ GC_free(si); } return(result);}void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg){ struct start_info * si = arg; void * result; void *(*start)(void *); void *start_arg; DWORD thread_id = GetCurrentThreadId(); pthread_t pthread_id = pthread_self(); GC_thread me; GC_bool detached; int i;# if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id, thread_id);# endif# if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p, thread_id);# endif GC_ASSERT(!GC_win32_dll_threads); /* 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. */ me = GC_register_my_thread_inner(sb, thread_id); SET_PTHREAD_MAP_CACHE(pthread_id, thread_id); UNLOCK(); start = si -> start_routine; start_arg = si -> arg; if (si-> detached) me -> flags |= DETACHED; me -> pthread_id = pthread_id; GC_free(si); /* was allocated uncollectable */ pthread_cleanup_push(GC_thread_exit_proc, (void *)me); result = (*start)(start_arg); me -> status = result; pthread_cleanup_pop(1);# if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) returned from start routine.\n", (int)pthread_self(),GetCurrentThreadId());# endif# if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) returned from start routine.\n", (int)(pthread_self()).p, GetCurrentThreadId());# endif return(result);}void * GC_pthread_start(void * arg){ return GC_call_with_stack_base(GC_pthread_start_inner, arg);}void GC_thread_exit_proc(void *arg){ GC_thread me = (GC_thread)arg; int i; GC_ASSERT(!GC_win32_dll_threads);# if DEBUG_CYGWIN_THREADS GC_printf("thread 0x%x(0x%x) called pthread_exit().\n", (int)pthread_self(),GetCurrentThreadId());# endif# if DEBUG_WIN32_PTHREADS GC_printf("thread 0x%x(0x%x) called pthread_exit().\n", (int)(pthread_self()).p,GetCurrentThreadId());# endif LOCK();# if defined(THREAD_LOCAL_ALLOC) GC_destroy_thread_local(&(me->tlfs));# endif if (me -> flags & DETACHED) { GC_delete_thread(GetCurrentThreadId()); } else { /* deallocate it as part of join */ me -> flags |= FINISHED; } UNLOCK();}#ifndef GC_WIN32_PTHREADS/* win32 pthread does not support sigmask *//* nothing required here... */int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { if (!parallel_initialized) GC_init_parallel(); return pthread_sigmask(how, set, oset);}#endifint 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;}#else /* !GC_PTHREADS *//* * We avoid acquiring locks here, since this doesn't seem to be preemptable. * This may run with an uninitialized collector, in which case we don't do much. * This implies that no threads other than the main one should be created * with an uninitialized collector. (The alternative of initializing * the collector here seems dangerous, since DllMain is limited in what it * can do.) */#ifdef GC_DLLGC_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;}#endif /* GC_DLL */#endif /* !GC_PTHREADS */# endif /* !MSWINCE *//* Perform all initializations, including those that *//* may require allocation. *//* Called without allocation lock. *//* 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}#if defined(USE_PTHREAD_LOCKS) /* Support for pthread locking code. */ /* Pthread_mutex_try_lock may not win here, */ /* due to builtinsupport for spinning first? */volatile GC_bool GC_collecting = 0; /* A hint that we're in the collector and */ /* holding the allocation lock for an */ /* extended period. */void GC_lock(void){ pthread_mutex_lock(&GC_allocate_ml);}#endif /* USE_PTHREAD ... */# if defined(THREAD_LOCAL_ALLOC)/* Add thread-local allocation support. Microsoft uses __declspec(thread) *//* We must explicitly mark ptrfree and gcj free lists, since the free *//* list links wouldn't otherwise be found. We also set them in the *//* normal free lists, since that involves touching less memory than if *//* we scanned them normally. */void GC_mark_thread_local_free_lists(void){ int i; GC_thread p; for (i = 0; i < THREAD_TABLE_SZ; ++i) { for (p = GC_threads[i]; 0 != p; p = p -> next) { GC_mark_thread_local_fls_for(&(p->tlfs)); } }}#if defined(GC_ASSERTIONS) /* Check that all thread-local free-lists are completely marked. */ /* also check that thread-specific-data structures are marked. */ void GC_check_tls(void) { int i; GC_thread p; for (i = 0; i < THREAD_TABLE_SZ; ++i) { for (p = GC_threads[i]; 0 != p; p = p -> next) { GC_check_tls_for(&(p->tlfs)); } }# if defined(USE_CUSTOM_SPECIFIC) if (GC_thread_key != 0) GC_check_tsd_marks(GC_thread_key);# endif }#endif /* GC_ASSERTIONS */#endif /* THREAD_LOCAL_ALLOC ... */#endif /* GC_WIN32_THREADS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -