summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/os_windows.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/os_windows.c')
-rw-r--r--src/pkg/runtime/os_windows.c101
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);
}