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.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c
new file mode 100644
index 000000000..b28affe31
--- /dev/null
+++ b/src/pkg/runtime/os_windows.c
@@ -0,0 +1,470 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
+#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
+#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
+#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
+#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
+#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll"
+#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll"
+#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
+#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
+#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
+#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll"
+#pragma dynimport runtime·GetSystemTimeAsFileTime GetSystemTimeAsFileTime "kernel32.dll"
+#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
+#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.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·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;
+
+extern void *runtime·CloseHandle;
+extern void *runtime·CreateEvent;
+extern void *runtime·CreateThread;
+extern void *runtime·CreateWaitableTimer;
+extern void *runtime·CryptAcquireContextW;
+extern void *runtime·CryptGenRandom;
+extern void *runtime·CryptReleaseContext;
+extern void *runtime·DuplicateHandle;
+extern void *runtime·ExitProcess;
+extern void *runtime·FreeEnvironmentStringsW;
+extern void *runtime·GetEnvironmentStringsW;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetStdHandle;
+extern void *runtime·GetSystemInfo;
+extern void *runtime·GetSystemTimeAsFileTime;
+extern void *runtime·GetThreadContext;
+extern void *runtime·LoadLibrary;
+extern void *runtime·ResumeThread;
+extern void *runtime·SetConsoleCtrlHandler;
+extern void *runtime·SetEvent;
+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;
+
+static int32
+getproccount(void)
+{
+ SystemInfo info;
+
+ runtime·stdcall(runtime·GetSystemInfo, 1, &info);
+ return info.dwNumberOfProcessors;
+}
+
+void
+runtime·osinit(void)
+{
+ // -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·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
+ runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
+ runtime·ncpu = getproccount();
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ uintptr handle;
+ *rnd = nil;
+ *rnd_len = 0;
+ if(runtime·stdcall(runtime·CryptAcquireContextW, 5, &handle, nil, nil,
+ (uintptr)1 /* PROV_RSA_FULL */,
+ (uintptr)0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
+ static byte random_data[HashRandomBytes];
+ if(runtime·stdcall(runtime·CryptGenRandom, 3, handle, (uintptr)HashRandomBytes, random_data)) {
+ *rnd = random_data;
+ *rnd_len = HashRandomBytes;
+ }
+ runtime·stdcall(runtime·CryptReleaseContext, 2, handle, (uintptr)0);
+ }
+}
+
+void
+runtime·goenvs(void)
+{
+ extern Slice syscall·envs;
+
+ uint16 *env;
+ String *s;
+ int32 i, n;
+ uint16 *p;
+
+ env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
+
+ n = 0;
+ for(p=env; *p; n++)
+ p += runtime·findnullw(p)+1;
+
+ s = runtime·malloc(n*sizeof s[0]);
+
+ p = env;
+ for(i=0; i<n; i++) {
+ s[i] = runtime·gostringw(p);
+ p += runtime·findnullw(p)+1;
+ }
+ syscall·envs.array = (byte*)s;
+ syscall·envs.len = n;
+ syscall·envs.cap = n;
+
+ runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
+}
+
+void
+runtime·exit(int32 code)
+{
+ runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
+}
+
+int32
+runtime·write(int32 fd, void *buf, int32 n)
+{
+ void *handle;
+ uint32 written;
+
+ written = 0;
+ switch(fd) {
+ case 1:
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
+ break;
+ case 2:
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
+ break;
+ default:
+ return -1;
+ }
+ runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
+ return written;
+}
+
+#define INFINITE ((uintptr)0xFFFFFFFF)
+
+int32
+runtime·semasleep(int64 ns)
+{
+ uintptr ms;
+
+ if(ns < 0)
+ ms = INFINITE;
+ else if(ns/1000000 > 0x7fffffffLL)
+ ms = 0x7fffffff;
+ else {
+ ms = ns/1000000;
+ if(ms == 0)
+ ms = 1;
+ }
+ if(runtime·stdcall(runtime·WaitForSingleObject, 2, m->waitsema, ms) != 0)
+ return -1; // timeout
+ return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ runtime·stdcall(runtime·SetEvent, 1, mp->waitsema);
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
+}
+
+#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+ void *thandle;
+
+ USED(stk);
+
+ thandle = runtime·stdcall(runtime·CreateThread, 6,
+ nil, (uintptr)0x20000, runtime·tstart_stdcall, mp,
+ STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
+ if(thandle == nil) {
+ 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).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+ USED(mp);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+ runtime·install_exception_handler();
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+ runtime·remove_exception_handler();
+}
+
+int64
+runtime·nanotime(void)
+{
+ int64 filetime;
+
+ runtime·stdcall(runtime·GetSystemTimeAsFileTime, 1, &filetime);
+
+ // Filetime is 100s of nanoseconds since January 1, 1601.
+ // Convert to nanoseconds since January 1, 1970.
+ return (filetime - 116444736000000000LL) * 100LL;
+}
+
+void
+time·now(int64 sec, int32 usec)
+{
+ int64 ns;
+
+ ns = runtime·nanotime();
+ sec = ns / 1000000000LL;
+ usec = ns - sec * 1000000000LL;
+ FLUSH(&sec);
+ FLUSH(&usec);
+}
+
+// Calling stdcall on os stack.
+#pragma textflag 7
+void *
+runtime·stdcall(void *fn, int32 count, ...)
+{
+ WinCall c;
+
+ c.fn = fn;
+ c.n = count;
+ c.args = (uintptr*)&count + 1;
+ runtime·asmcgocall(runtime·asmstdcall, &c);
+ return (void*)c.r1;
+}
+
+uint32
+runtime·issigpanic(uint32 code)
+{
+ switch(code) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case EXCEPTION_INT_OVERFLOW:
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ return 1;
+ }
+ return 0;
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ if(g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ runtime·panicstring("integer divide by zero");
+ case EXCEPTION_INT_OVERFLOW:
+ runtime·panicstring("integer overflow");
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ runtime·panicstring("floating point error");
+ }
+ runtime·throw("fault");
+}
+
+extern void *runtime·sigtramp;
+
+void
+runtime·initsig(void)
+{
+ // following line keeps sigtramp alive at link stage
+ // if there's a better way please write it here
+ void *p = runtime·sigtramp;
+ USED(p);
+}
+
+uint32
+runtime·ctrlhandler1(uint32 type)
+{
+ int32 s;
+
+ switch(type) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ s = SIGINT;
+ break;
+ default:
+ return 0;
+ }
+
+ if(runtime·sigsend(s))
+ return 1;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ return 0;
+}
+
+extern void runtime·dosigprof(Context *r, G *gp);
+extern void runtime·profileloop(void);
+static void *profiletimer;
+
+static void
+profilem(M *mp)
+{
+ extern M runtime·m0;
+ extern uint32 runtime·tls0[];
+ byte rbuf[sizeof(Context)+15];
+ Context *r;
+ void *tls;
+ G *gp;
+
+ tls = mp->tls;
+ if(mp == &runtime·m0)
+ 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);
+ }
+}
+
+void
+runtime·profileloop1(void)
+{
+ M *mp, *allm;
+ void *thread;
+
+ runtime·stdcall(runtime·SetThreadPriority, 2,
+ (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST);
+
+ for(;;) {
+ runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1);
+ allm = runtime·atomicloadp(&runtime·allm);
+ for(mp = allm; mp != nil; mp = mp->alllink) {
+ thread = runtime·atomicloadp(&mp->thread);
+ if(thread == nil)
+ continue;
+ runtime·stdcall(runtime·SuspendThread, 1, thread);
+ if(mp->profilehz != 0)
+ profilem(mp);
+ runtime·stdcall(runtime·ResumeThread, 1, thread);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ static Lock lock;
+ void *timer, *thread;
+ int32 ms;
+ int64 due;
+
+ runtime·lock(&lock);
+ if(profiletimer == nil) {
+ timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil);
+ runtime·atomicstorep(&profiletimer, timer);
+ thread = runtime·stdcall(runtime·CreateThread, 6,
+ nil, nil, runtime·profileloop, nil, nil, nil);
+ runtime·stdcall(runtime·CloseHandle, 1, thread);
+ }
+ runtime·unlock(&lock);
+
+ ms = 0;
+ due = 1LL<<63;
+ if(hz > 0) {
+ ms = 1000 / hz;
+ if(ms == 0)
+ ms = 1;
+ due = ms * -10000;
+ }
+ runtime·stdcall(runtime·SetWaitableTimer, 6,
+ profiletimer, &due, (uintptr)ms, nil, nil, nil);
+ runtime·atomicstore((uint32*)&m->profilehz, hz);
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ return 0;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+int8 runtime·badcallbackmsg[] = "runtime: cgo callback on thread not created by Go.\n";
+int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1;
+
+int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
+int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
+
+void
+runtime·crash(void)
+{
+ // TODO: This routine should do whatever is needed
+ // to make the Windows program abort/crash as it
+ // would if Go was not intercepting signals.
+ // On Unix the routine would remove the custom signal
+ // handler and then raise a signal (like SIGABRT).
+ // Something like that should happen here.
+ // It's okay to leave this empty for now: if crash returns
+ // the ordinary exit-after-panic happens.
+}