📄 win32_threads.c
字号:
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;}# ifdef MSWINCE /* The VirtualQuery calls below won't work properly on WinCE, but */ /* since each stack is restricted to an aligned 64K region of */ /* virtual memory we can just take the next lowest multiple of 64K. */# define GC_get_stack_min(s) \ ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))# else static ptr_t GC_get_stack_min(ptr_t s) { ptr_t bottom; MEMORY_BASIC_INFORMATION info; VirtualQuery(s, &info, sizeof(info)); do { bottom = info.BaseAddress; VirtualQuery(bottom - 1, &info, sizeof(info)); } while ((info.Protect & PAGE_READWRITE) && !(info.Protect & PAGE_GUARD)); return(bottom); }# endifvoid GC_push_stack_for(GC_thread thread){ int dummy; ptr_t sp, stack_min; DWORD me = GetCurrentThreadId(); if (thread -> stack_base) { if (thread -> id == me) { sp = (ptr_t) &dummy; } else { CONTEXT context; context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; if (!GetThreadContext(thread -> handle, &context)) ABORT("GetThreadContext failed"); /* Push all registers that might point into the heap. Frame */ /* pointer registers are included in case client code was */ /* compiled with the 'omit frame pointer' optimisation. */# define PUSH1(reg) GC_push_one((word)context.reg)# define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)# define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)# if defined(I386) PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp); sp = (ptr_t)context.Esp;# elif defined(X86_64) PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi); PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15); sp = (ptr_t)context.Rsp;# elif defined(ARM32) PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12); sp = (ptr_t)context.Sp;# elif defined(SHx) PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11); PUSH2(R12,R13), PUSH1(R14); sp = (ptr_t)context.R15;# elif defined(MIPS) PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0); PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0); PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8); PUSH4(IntT9,IntK0,IntK1,IntS8); sp = (ptr_t)context.IntSp;# elif defined(PPC) PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9); PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18); PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26); PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31); sp = (ptr_t)context.Gpr1;# elif defined(ALPHA) PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6); PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp); PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9); PUSH4(IntT10,IntT11,IntT12,IntAt); sp = (ptr_t)context.IntSp;# else# error "architecture is not supported"# endif } /* ! current thread */ stack_min = GC_get_stack_min(thread->stack_base); if (sp >= stack_min && sp < thread->stack_base) {# if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \ || DEBUG_CYGWIN_THREADS GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n", sp, thread -> stack_base, thread -> id, me);# endif GC_push_all_stack(sp, thread->stack_base); } else { WARN("Thread stack pointer 0x%lx out of range, pushing everything\n", (unsigned long)(size_t)sp); GC_push_all_stack(stack_min, thread->stack_base); } } /* thread looks live */}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.");}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;}#ifndef GC_PTHREADS/* 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);void * GC_win32_start_inner(struct GC_stack_base *sb, LPVOID arg){ void * ret; thread_args *args = (thread_args *)arg;# if DEBUG_WIN32_THREADS GC_printf("thread 0x%x starting...\n", GetCurrentThreadId());# endif GC_register_my_thread(sb); /* This waits for an in-progress GC. */ /* 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 = (void *)(size_t)args->start (args->param);#ifndef __GNUC__ } __finally {#endif /* __GNUC__ */ GC_unregister_my_thread(); GC_free(args);#ifndef __GNUC__ }#endif /* __GNUC__ */# if DEBUG_WIN32_THREADS GC_printf("thread 0x%x returned from start routine.\n", GetCurrentThreadId());# endif return ret;}DWORD WINAPI GC_win32_start(LPVOID arg){ return (DWORD)(size_t)GC_call_with_stack_base(GC_win32_start_inner, 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 (!parallel_initialized) GC_init_parallel(); /* make sure GC is initialized (i.e. main thread is attached, tls initialized) */# if DEBUG_WIN32_THREADS GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());# endif if (GC_win32_dll_threads) { return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId); } else { 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; GC_need_to_lock = TRUE; thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start, args, dwCreationFlags, lpThreadId); if( thread_h == 0 ) GC_free( args ); return thread_h; }}void WINAPI GC_ExitThread(DWORD dwExitCode){ GC_unregister_my_thread(); ExitThread(dwExitCode);}uintptr_t GC_beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr){ uintptr_t thread_h = -1L; thread_args *args; if (!parallel_initialized) GC_init_parallel(); /* make sure GC is initialized (i.e. main thread is attached, tls initialized) */# if DEBUG_WIN32_THREADS GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());# endif if (GC_win32_dll_threads) { return _beginthreadex(security, stack_size, start_address, arglist, initflag, thrdaddr); } else { args = GC_malloc_uncollectable(sizeof(thread_args)); /* Handed off to and deallocated by child thread. */ if (0 == args) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return (uintptr_t)(-1); } /* set up thread arguments */ args -> start = (LPTHREAD_START_ROUTINE)start_address; args -> param = arglist; GC_need_to_lock = TRUE; thread_h = _beginthreadex(security, stack_size, (unsigned (__stdcall *) (void *))GC_win32_start, args, initflag, thrdaddr); if( thread_h == 0 ) GC_free( args ); return thread_h; }}void GC_endthreadex(unsigned retval){ GC_unregister_my_thread(); _endthreadex(retval);}#endif /* !GC_PTHREADS */#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(void) { struct GC_stack_base sb; int sb_result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -