📄 win32_threads.c
字号:
GC_push_all_stack(sp, thread->stack_base); else { WARN("Thread stack pointer 0x%lx out of range, pushing everything\n", (unsigned long)sp); GC_push_all_stack(stack_min, thread->stack_base); } } } if (!found_me) ABORT("Collecting from unknown thread.");}void GC_get_next_stack(char *start, char **lo, char **hi){ int i;# define ADDR_LIMIT (char *)(-1L) char * current_min = ADDR_LIMIT; LONG my_max = GC_get_max_thread_index(); for (i = 0; i <= my_max; i++) { char * s = (char *)thread_table[i].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;}#if !defined(CYGWIN32)#if !defined(MSWINCE) && defined(GC_DLL)/* We register threads from DllMain */GC_API HANDLE WINAPI GC_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ){ return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);}#else /* defined(MSWINCE) || !defined(GC_DLL)) *//* We have no DllMain to take care of new threads. Thus we *//* must properly intercept thread creation. */typedef struct { LPTHREAD_START_ROUTINE start; LPVOID param;} thread_args;static DWORD WINAPI thread_start(LPVOID arg);GC_API HANDLE WINAPI GC_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ){ HANDLE thread_h = NULL; thread_args *args; if (!GC_is_initialized) GC_init(); /* make sure GC is initialized (i.e. main thread is attached) */ args = GC_malloc_uncollectable(sizeof(thread_args)); /* Handed off to and deallocated by child thread. */ if (0 == args) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } /* set up thread arguments */ args -> start = lpStartAddress; args -> param = lpParameter; thread_h = CreateThread(lpThreadAttributes, dwStackSize, thread_start, args, dwCreationFlags, lpThreadId); return thread_h;}static DWORD WINAPI thread_start(LPVOID arg){ DWORD ret = 0; thread_args *args = (thread_args *)arg; GC_new_thread(); /* Clear the thread entry even if we exit with an exception. */ /* This is probably pointless, since an uncaught exception is */ /* supposed to result in the process being killed. */#ifndef __GNUC__ __try {#endif /* __GNUC__ */ ret = args->start (args->param);#ifndef __GNUC__ } __finally {#endif /* __GNUC__ */ GC_free(args); GC_delete_thread(GetCurrentThreadId());#ifndef __GNUC__ }#endif /* __GNUC__ */ return ret;}#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */#endif /* !CYGWIN32 */#ifdef MSWINCEtypedef struct { HINSTANCE hInstance; HINSTANCE hPrevInstance; LPWSTR lpCmdLine; int nShowCmd;} main_thread_args;DWORD WINAPI main_thread_start(LPVOID arg);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd){ DWORD exit_code = 1; main_thread_args args = { hInstance, hPrevInstance, lpCmdLine, nShowCmd }; HANDLE thread_h; DWORD thread_id; /* initialize everything */ GC_init(); /* start the main thread */ thread_h = GC_CreateThread( NULL, 0, main_thread_start, &args, 0, &thread_id); if (thread_h != NULL) { WaitForSingleObject (thread_h, INFINITE); GetExitCodeThread (thread_h, &exit_code); CloseHandle (thread_h); } GC_deinit(); DeleteCriticalSection(&GC_allocate_ml); return (int) exit_code;}DWORD WINAPI main_thread_start(LPVOID arg){ main_thread_args * args = (main_thread_args *) arg; return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance, args->lpCmdLine, args->nShowCmd);}# else /* !MSWINCE *//* Called by GC_init() - we hold the allocation lock. */void GC_thr_init() { if (GC_thr_initialized) return; GC_main_thread = GetCurrentThreadId(); GC_thr_initialized = TRUE; /* Add the initial thread, so we can stop it. */ GC_new_thread();}#ifdef CYGWIN32struct 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 me;# if DEBUG_CYGWIN_THREADS GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);# endif /* 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. */ while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10); result = pthread_join(pthread_id, retval); GC_delete_gc_thread(me);# if DEBUG_CYGWIN_THREADS GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);# 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 (!GC_is_initialized) GC_init(); /* make sure GC is initialized (i.e. main thread is attached) */ /* 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_printf2("About to create a thread from 0x%x(0x%x)\n", (int)pthread_self(), GetCurrentThreadId);# endif result = pthread_create(new_thread, attr, GC_start_routine, si); if (result) { /* failure */ GC_free(si); } return(result);}void * GC_start_routine(void * arg){ struct start_info * si = arg; void * result; void *(*start)(void *); void *start_arg; pthread_t pthread_id; GC_thread me; GC_bool detached; int i;# if DEBUG_CYGWIN_THREADS GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(), GetCurrentThreadId());# endif /* 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_new_thread(); UNLOCK(); start = si -> start_routine; start_arg = si -> arg; if (si-> detached) me -> flags |= DETACHED; me -> pthread_id = pthread_id = pthread_self(); 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(0);# if DEBUG_CYGWIN_THREADS GC_printf2("thread 0x%x(0x%x) returned from start routine.\n", (int)pthread_self(),GetCurrentThreadId());# endif return(result);}void GC_thread_exit_proc(void *arg){ GC_thread me = (GC_thread)arg; int i;# if DEBUG_CYGWIN_THREADS GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n", (int)pthread_self(),GetCurrentThreadId());# endif LOCK(); if (me -> flags & DETACHED) { GC_delete_thread(GetCurrentThreadId()); } else { /* deallocate it as part of join */ me -> flags |= FINISHED; } UNLOCK();}/* nothing required here... */int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { return pthread_sigmask(how, set, oset);}int GC_pthread_detach(pthread_t thread){ int result; GC_thread thread_gc_id; LOCK(); thread_gc_id = GC_lookup_thread(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 /* !CYGWIN32 *//* * We avoid acquiring locks here, since this doesn't seem to be preemptable. * Pontus Rydin suggests wrapping the thread start routine instead. */#ifdef GC_DLLBOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved){ switch (reason) { case DLL_PROCESS_ATTACH: GC_init(); /* Force initialization before thread attach. */ /* fall through */ case DLL_THREAD_ATTACH: GC_ASSERT(GC_thr_initialized); if (GC_main_thread != GetCurrentThreadId()) { GC_new_thread(); } /* o.w. we already did it during GC_thr_init(), called by GC_init() */ break; case DLL_THREAD_DETACH: GC_delete_thread(GetCurrentThreadId()); break; case DLL_PROCESS_DETACH: { int i; LOCK(); for (i = 0; i <= GC_get_max_thread_index(); ++i) { if (thread_table[i].in_use) GC_delete_gc_thread(thread_table + i); } UNLOCK(); GC_deinit(); DeleteCriticalSection(&GC_allocate_ml); } break; } return TRUE;}#endif /* GC_DLL */#endif /* !CYGWIN32 */# endif /* !MSWINCE */#endif /* GC_WIN32_THREADS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -