blob: 33637f1d7a51f52737eeb6f27a14c9938303fa52 [file] [log] [blame]
// 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.h"
#include "os.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·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·LoadLibraryEx LoadLibraryExA "kernel32.dll"
#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
extern void *runtime·CloseHandle;
extern void *runtime·CreateEvent;
extern void *runtime·CreateThread;
extern void *runtime·ExitProcess;
extern void *runtime·FreeEnvironmentStringsW;
extern void *runtime·GetEnvironmentStringsW;
extern void *runtime·GetProcAddress;
extern void *runtime·GetStdHandle;
extern void *runtime·LoadLibraryEx;
extern void *runtime·QueryPerformanceCounter;
extern void *runtime·QueryPerformanceFrequency;
extern void *runtime·SetConsoleCtrlHandler;
extern void *runtime·SetEvent;
extern void *runtime·WaitForSingleObject;
extern void *runtime·WriteFile;
static int64 timerfreq;
void
runtime·osinit(void)
{
runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
}
void
runtime·goenvs(void)
{
extern Slice os·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;
}
os·Envs.array = (byte*)s;
os·Envs.len = n;
os·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;
}
// Thread-safe allocation of an event.
static void
initevent(void **pevent)
{
void *event;
event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
if(!runtime·casp(pevent, 0, event)) {
// Someone else filled it in. Use theirs.
runtime·stdcall(runtime·CloseHandle, 1, event);
}
}
#define LOCK_HELD ((M*)-1)
static void
eventlock(Lock *l)
{
// Allocate event if needed.
if(m->event == nil)
initevent(&m->event);
for(;;) {
m->nextwaitm = runtime·atomicloadp(&l->waitm);
if(m->nextwaitm == nil) {
if(runtime·casp(&l->waitm, nil, LOCK_HELD))
return;
// Someone else has it.
// l->waitm points to a linked list of M's waiting
// for this lock, chained through m->nextwaitm.
// Queue this M.
} else if(runtime·casp(&l->waitm, m->nextwaitm, m))
break;
}
// Wait.
runtime·stdcall(runtime·WaitForSingleObject, 2, m->event, (uintptr)-1);
}
static void
eventunlock(Lock *l)
{
M *mp;
for(;;) {
mp = runtime·atomicloadp(&l->waitm);
if(mp == LOCK_HELD) {
if(runtime·casp(&l->waitm, LOCK_HELD, nil))
return;
// Other M's are waiting for the lock.
// Dequeue a M.
} else if(runtime·casp(&l->waitm, mp, mp->nextwaitm))
break;
}
// Wake that M.
runtime·stdcall(runtime·SetEvent, 1, mp->event);
}
void
runtime·lock(Lock *l)
{
if(m->locks < 0)
runtime·throw("lock count");
m->locks++;
eventlock(l);
}
void
runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
runtime·throw("lock count");
eventunlock(l);
}
void
runtime·noteclear(Note *n)
{
n->lock.waitm = nil;
eventlock(&n->lock);
}
void
runtime·notewakeup(Note *n)
{
eventunlock(&n->lock);
}
void
runtime·notesleep(Note *n)
{
eventlock(&n->lock);
eventunlock(&n->lock); // Let other sleepers find out too.
}
void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
void *thandle;
USED(stk);
USED(g); // assuming g = m->g0
USED(fn); // assuming fn = mstart
thandle = runtime·stdcall(runtime·CreateThread, 6, (uintptr)0, (uintptr)0, runtime·tstart_stdcall, m, (uintptr)0, (uintptr)0);
if(thandle == 0) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
runtime·throw("runtime.newosproc");
}
}
// Called to initialize a new m (including the bootstrap m).
void
runtime·minit(void)
{
}
void
runtime·gettime(int64 *sec, int32 *usec)
{
int64 count;
runtime·stdcall(runtime·QueryPerformanceCounter, 1, &count);
*sec = count / timerfreq;
count %= timerfreq;
*usec = count*1000000 / timerfreq;
}
// 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)
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");
}
String
runtime·signame(int32 sig)
{
int8 *s;
switch(sig) {
case SIGINT:
s = "SIGINT: interrupt";
break;
default:
return runtime·emptystring;
}
return runtime·gostringnocopy((byte*)s);
}
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;
}
void
os·sigpipe(void)
{
runtime·throw("too many writes on closed pipe");
}