diff options
Diffstat (limited to 'src/pkg/runtime/os_windows.c')
-rw-r--r-- | src/pkg/runtime/os_windows.c | 101 |
1 files changed, 61 insertions, 40 deletions
diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c index c3e296aa6..0dd44ed1b 100644 --- a/src/pkg/runtime/os_windows.c +++ b/src/pkg/runtime/os_windows.c @@ -8,6 +8,7 @@ #include "os_GOOS.h" #include "../../cmd/ld/textflag.h" +#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" #pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" #pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" @@ -26,20 +27,20 @@ #pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" #pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" #pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll" +#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" #pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" #pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" +#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" #pragma dynimport runtime·Sleep Sleep "kernel32.dll" #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" -#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" #pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" #pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" -#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" - -extern void *runtime·NtWaitForSingleObject; +#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" +extern void *runtime·AddVectoredExceptionHandler; extern void *runtime·CloseHandle; extern void *runtime·CreateEvent; extern void *runtime·CreateThread; @@ -58,19 +59,25 @@ extern void *runtime·GetSystemTimeAsFileTime; extern void *runtime·GetThreadContext; extern void *runtime·LoadLibrary; extern void *runtime·LoadLibraryA; +extern void *runtime·NtWaitForSingleObject; extern void *runtime·ResumeThread; extern void *runtime·SetConsoleCtrlHandler; extern void *runtime·SetEvent; +extern void *runtime·SetProcessPriorityBoost; extern void *runtime·SetThreadPriority; extern void *runtime·SetWaitableTimer; extern void *runtime·Sleep; extern void *runtime·SuspendThread; -extern void *runtime·timeBeginPeriod; extern void *runtime·WaitForSingleObject; extern void *runtime·WriteFile; +extern void *runtime·timeBeginPeriod; void *runtime·GetQueuedCompletionStatusEx; +extern uintptr runtime·externalthreadhandlerp; +void runtime·externalthreadhandler(void); +void runtime·sigtramp(void); + static int32 getproccount(void) { @@ -84,25 +91,22 @@ void runtime·osinit(void) { void *kernel32; - void *SetProcessPriorityBoost; - // -1 = current process, -2 = current thread - runtime·stdcall(runtime·DuplicateHandle, 7, - (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread, - (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); + runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; + + runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp); runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1); runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1); runtime·ncpu = getproccount(); + + // Windows dynamic priority boosting assumes that a process has different types + // of dedicated threads -- GUI, IO, computational, etc. Go processes use + // equivalent threads that all do a mix of GUI, IO, computations, etc. + // In such context dynamic priority boosting does nothing but harm, so we turn it off. + runtime·stdcall(runtime·SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1); kernel32 = runtime·stdcall(runtime·LoadLibraryA, 1, "kernel32.dll"); if(kernel32 != nil) { - // Windows dynamic priority boosting assumes that a process has different types - // of dedicated threads -- GUI, IO, computational, etc. Go processes use - // equivalent threads that all do a mix of GUI, IO, computations, etc. - // In such context dynamic priority boosting does nothing but harm, so we turn it off. - SetProcessPriorityBoost = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "SetProcessPriorityBoost"); - if(SetProcessPriorityBoost != nil) // supported since Windows XP - runtime·stdcall(SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1); runtime·GetQueuedCompletionStatusEx = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "GetQueuedCompletionStatusEx"); } } @@ -162,7 +166,7 @@ runtime·exit(int32 code) } int32 -runtime·write(int32 fd, void *buf, int32 n) +runtime·write(uintptr fd, void *buf, int32 n) { void *handle; uint32 written; @@ -176,7 +180,9 @@ runtime·write(int32 fd, void *buf, int32 n) handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12); break; default: - return -1; + // assume fd is real windows handle. + handle = (void*)fd; + break; } runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0); return written; @@ -229,7 +235,6 @@ runtime·newosproc(M *mp, void *stk) runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); runtime·throw("runtime.newosproc"); } - runtime·atomicstorep(&mp->thread, thandle); } // Called to initialize a new m (including the bootstrap m). @@ -245,14 +250,19 @@ runtime·mpreinit(M *mp) void runtime·minit(void) { - runtime·install_exception_handler(); + void *thandle; + + // -1 = current process, -2 = current thread + runtime·stdcall(runtime·DuplicateHandle, 7, + (uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle, + (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); + runtime·atomicstorep(&m->thread, thandle); } // Called from dropm to undo the effect of an minit. void runtime·unminit(void) { - runtime·remove_exception_handler(); } #pragma textflag NOSPLIT @@ -285,11 +295,20 @@ time·now(int64 sec, int32 usec) void * runtime·stdcall(void *fn, int32 count, ...) { - m->wincall.fn = fn; - m->wincall.n = count; - m->wincall.args = (uintptr*)&count + 1; - runtime·asmcgocall(runtime·asmstdcall, &m->wincall); - return (void*)m->wincall.r1; + m->libcall.fn = fn; + m->libcall.n = count; + m->libcall.args = (uintptr*)&count + 1; + if(m->profilehz != 0) { + // leave pc/sp for cpu profiler + m->libcallg = g; + m->libcallpc = (uintptr)runtime·getcallerpc(&fn); + // sp must be the last, because once async cpu profiler finds + // all three values to be non-zero, it will use them + m->libcallsp = (uintptr)runtime·getcallersp(&fn); + } + runtime·asmcgocall(runtime·asmstdcall, &m->libcall); + m->libcallsp = 0; + return (void*)m->libcall.r1; } extern void runtime·usleep1(uint32); @@ -329,9 +348,12 @@ runtime·issigpanic(uint32 code) void runtime·sigpanic(void) { + if(!runtime·canpanic(g)) + runtime·throw("unexpected signal during runtime execution"); + switch(g->sig) { case EXCEPTION_ACCESS_VIOLATION: - if(g->sigcode1 < 0x1000) { + if(g->sigcode1 < 0x1000 || g->paniconfault) { if(g->sigpc == 0) runtime·panicstring("call of nil func value"); runtime·panicstring("invalid memory address or nil pointer dereference"); @@ -352,8 +374,6 @@ runtime·sigpanic(void) runtime·throw("fault"); } -extern void *runtime·sigtramp; - void runtime·initsig(void) { @@ -383,7 +403,7 @@ runtime·ctrlhandler1(uint32 type) return 0; } -extern void runtime·dosigprof(Context *r, G *gp); +extern void runtime·dosigprof(Context *r, G *gp, M *mp); extern void runtime·profileloop(void); static void *profiletimer; @@ -402,13 +422,11 @@ profilem(M *mp) tls = runtime·tls0; gp = *(G**)tls; - if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) { - // align Context to 16 bytes - r = (Context*)((uintptr)(&rbuf[15]) & ~15); - r->ContextFlags = CONTEXT_CONTROL; - runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r); - runtime·dosigprof(r, gp); - } + // align Context to 16 bytes + r = (Context*)((uintptr)(&rbuf[15]) & ~15); + r->ContextFlags = CONTEXT_CONTROL; + runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r); + runtime·dosigprof(r, gp, mp); } void @@ -425,10 +443,13 @@ runtime·profileloop1(void) allm = runtime·atomicloadp(&runtime·allm); for(mp = allm; mp != nil; mp = mp->alllink) { thread = runtime·atomicloadp(&mp->thread); - if(thread == nil) + // Do not profile threads blocked on Notes, + // this includes idle worker threads, + // idle timer thread, idle heap scavenger, etc. + if(thread == nil || mp->profilehz == 0 || mp->blocked) continue; runtime·stdcall(runtime·SuspendThread, 1, thread); - if(mp->profilehz != 0) + if(mp->profilehz != 0 && !mp->blocked) profilem(mp); runtime·stdcall(runtime·ResumeThread, 1, thread); } |