Commit ab4578ad authored by Alex Brainman's avatar Alex Brainman

[dev.cc] runtime: convert remaining windows C code to Go

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/177090043
parent f4a52545
......@@ -152,5 +152,5 @@ func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) {
}
op.errno = errno
op.qty = qty
netpollready(gpp, op.pd, mode)
netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode)
}
// 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.
package runtime
import (
"unsafe"
)
//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll"
//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll"
//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll"
//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll"
//go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll"
//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll"
//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll"
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll"
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll"
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll"
//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll"
//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll"
//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll"
//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll"
//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll"
//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll"
//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll"
//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll"
//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll"
//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll"
var (
_AddVectoredExceptionHandler,
_CloseHandle,
_CreateEventA,
_CreateThread,
_CreateWaitableTimerA,
_CryptAcquireContextW,
_CryptGenRandom,
_CryptReleaseContext,
_DuplicateHandle,
_ExitProcess,
_FreeEnvironmentStringsW,
_GetEnvironmentStringsW,
_GetProcAddress,
_GetStdHandle,
_GetSystemInfo,
_GetThreadContext,
_LoadLibraryW,
_LoadLibraryA,
_NtWaitForSingleObject,
_ResumeThread,
_SetConsoleCtrlHandler,
_SetEvent,
_SetProcessPriorityBoost,
_SetThreadPriority,
_SetUnhandledExceptionFilter,
_SetWaitableTimer,
_Sleep,
_SuspendThread,
_WaitForSingleObject,
_WriteFile,
_timeBeginPeriod stdFunction
)
var _GetQueuedCompletionStatusEx stdFunction
// in sys_windows_386.s and sys_windows_amd64.s
func externalthreadhandler()
func exceptiontramp()
func firstcontinuetramp()
func lastcontinuetramp()
//go:nosplit
func getLoadLibrary() uintptr {
return uintptr(unsafe.Pointer(_LoadLibraryW))
}
//go:nosplit
func getGetProcAddress() uintptr {
return uintptr(unsafe.Pointer(_GetProcAddress))
}
func getproccount() int32 {
var info systeminfo
stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
return int32(info.dwnumberofprocessors)
}
const (
currentProcess = ^uintptr(0) // -1 = current process
currentThread = ^uintptr(1) // -2 = current thread
)
var (
kernel32Name = []byte("kernel32.dll\x00")
addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00")
getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00")
)
func osinit() {
setBadSignalMsg()
kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0])))
externalthreadhandlerp = funcPC(externalthreadhandler)
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
addVectoredContinueHandler := uintptr(0)
if kernel32 != 0 {
addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0])))
}
if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 {
// use SetUnhandledExceptionFilter for windows-386 or
// if VectoredContinueHandler is unavailable.
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
} else {
stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp))
stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp))
}
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
stdcall1(_timeBeginPeriod, 1)
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.
stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
if kernel32 != 0 {
_GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0])))))
}
}
var random_data [_HashRandomBytes]byte
//go:nosplit
func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
const (
prov_rsa_full = 1
crypt_verifycontext = 0xF0000000
)
var handle uintptr
*rnd = nil
*rnd_len = 0
if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
if stdcall3(_CryptGenRandom, handle, _HashRandomBytes, uintptr(unsafe.Pointer(&random_data[0]))) != 0 {
*rnd = unsafe.Pointer(&random_data[0])
*rnd_len = _HashRandomBytes
}
stdcall2(_CryptReleaseContext, handle, 0)
}
}
func goenvs() {
var p *uint16
env := (*uint16)(unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)))
n := 0
for p = env; *p != 0; n++ {
p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)))
}
envs = makeStringSlice(int(n))
p = env
for i := 0; i < n; i++ {
envs[i] = gostringw(p)
p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)))
}
stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env)))
}
//go:nosplit
func exit(code int32) {
stdcall1(_ExitProcess, uintptr(code))
}
//go:nosplit
func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
const (
_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
_STD_ERROR_HANDLE = ^uintptr(11) // -12
)
var handle uintptr
switch fd {
case 1:
handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
case 2:
handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
default:
// assume fd is real windows handle.
handle = fd
}
var written uint32
stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
return int32(written)
}
//go:nosplit
func semasleep(ns int64) int32 {
// store ms in ns to save stack space
if ns < 0 {
ns = _INFINITE
} else {
ns = int64(timediv(ns, 1000000, nil))
if ns == 0 {
ns = 1
}
}
if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
return -1 // timeout
}
return 0
}
//go:nosplit
func semawakeup(mp *m) {
stdcall1(_SetEvent, mp.waitsema)
}
//go:nosplit
func semacreate() uintptr {
return stdcall4(_CreateEventA, 0, 0, 0, 0)
}
func newosproc(mp *m, stk unsafe.Pointer) {
const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
thandle := stdcall6(_CreateThread, 0, 0x20000,
funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
if thandle == 0 {
println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")")
gothrow("runtime.newosproc")
}
}
// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
}
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
var thandle uintptr
stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
atomicstoreuintptr(&getg().m.thread, thandle)
}
// Called from dropm to undo the effect of an minit.
func unminit() {
tp := &getg().m.thread
stdcall1(_CloseHandle, *tp)
*tp = 0
}
// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
type _KSYSTEM_TIME struct {
LowPart uint32
High1Time int32
High2Time int32
}
const (
_INTERRUPT_TIME = 0x7ffe0008
_SYSTEM_TIME = 0x7ffe0014
)
//go:nosplit
func systime(addr uintptr) int64 {
timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
var t _KSYSTEM_TIME
for i := 1; i < 10000; i++ {
// these fields must be read in that order (see URL above)
t.High1Time = timeaddr.High1Time
t.LowPart = timeaddr.LowPart
t.High2Time = timeaddr.High2Time
if t.High1Time == t.High2Time {
return int64(t.High1Time)<<32 | int64(t.LowPart)
}
if (i % 100) == 0 {
osyield()
}
}
systemstack(func() {
gothrow("interrupt/system time is changing too fast")
})
return 0
}
//go:nosplit
func unixnano() int64 {
return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
}
//go:nosplit
func nanotime() int64 {
return systime(_INTERRUPT_TIME) * 100
}
// Calling stdcall on os stack.
//go:nosplit
func stdcall(fn stdFunction) uintptr {
gp := getg()
mp := gp.m
mp.libcall.fn = uintptr(unsafe.Pointer(fn))
if mp.profilehz != 0 {
// leave pc/sp for cpu profiler
mp.libcallg = gp
mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
// sp must be the last, because once async cpu profiler finds
// all three values to be non-zero, it will use them
mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
}
asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall))
mp.libcallsp = 0
return mp.libcall.r1
}
//go:nosplit
func stdcall0(fn stdFunction) uintptr {
mp := getg().m
mp.libcall.n = 0
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
return stdcall(fn)
}
//go:nosplit
func stdcall1(fn stdFunction, a0 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 1
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
//go:nosplit
func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 2
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
//go:nosplit
func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 3
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
//go:nosplit
func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 4
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
//go:nosplit
func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 5
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
//go:nosplit
func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 6
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
//go:nosplit
func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
mp := getg().m
mp.libcall.n = 7
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
return stdcall(fn)
}
// in sys_windows_386.s and sys_windows_amd64.s
func usleep1(usec uint32)
//go:nosplit
func osyield() {
usleep1(1)
}
//go:nosplit
func usleep(us uint32) {
// Have 1us units; want 100ns units.
usleep1(10 * us)
}
func issigpanic(code uint32) uint32 {
switch code {
default:
return 0
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:
case _EXCEPTION_BREAKPOINT:
}
return 1
}
func initsig() {
/*
// TODO(brainman): I don't think we need that bit of code
// following line keeps these functions alive at link stage
// if there's a better way please write it here
void *e = runtime·exceptiontramp;
void *f = runtime·firstcontinuetramp;
void *l = runtime·lastcontinuetramp;
USED(e);
USED(f);
USED(l);
*/
}
func ctrlhandler1(_type uint32) uint32 {
var s uint32
switch _type {
case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
s = _SIGINT
default:
return 0
}
if sigsend(s) {
return 1
}
exit(2) // SIGINT, SIGTERM, etc
return 0
}
// in sys_windows_386.s and sys_windows_amd64.s
func profileloop()
var profiletimer uintptr
func profilem(mp *m) {
var r *context
rbuf := make([]byte, unsafe.Sizeof(*r)+15)
tls := &mp.tls[0]
if mp == &m0 {
tls = &tls0[0]
}
gp := *((**g)(unsafe.Pointer(tls)))
// align Context to 16 bytes
r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
r.contextflags = _CONTEXT_CONTROL
stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
dosigprof(r, gp, mp)
}
func profileloop1() {
stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
for {
stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
first := (*m)(atomicloadp(unsafe.Pointer(&allm)))
for mp := first; mp != nil; mp = mp.alllink {
thread := atomicloaduintptr(&mp.thread)
// Do not profile threads blocked on Notes,
// this includes idle worker threads,
// idle timer thread, idle heap scavenger, etc.
if thread == 0 || mp.profilehz == 0 || mp.blocked {
continue
}
stdcall1(_SuspendThread, thread)
if mp.profilehz != 0 && !mp.blocked {
profilem(mp)
}
stdcall1(_ResumeThread, thread)
}
}
}
var cpuprofilerlock mutex
func resetcpuprofiler(hz int32) {
lock(&cpuprofilerlock)
if profiletimer == 0 {
timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
atomicstoreuintptr(&profiletimer, timer)
thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
stdcall1(_CloseHandle, thread)
}
unlock(&cpuprofilerlock)
ms := int32(0)
due := ^int64(^uint64(1 << 63))
if hz > 0 {
ms = 1000 / hz
if ms == 0 {
ms = 1
}
due = int64(ms) * -10000
}
stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
}
func memlimit() uintptr {
return 0
}
var (
badsignalmsg [100]byte
badsignallen int32
)
func setBadSignalMsg() {
const msg = "runtime: signal received on thread not created by Go.\n"
for i, c := range msg {
badsignalmsg[i] = byte(c)
badsignallen++
}
}
func crash() {
// 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.
}
......@@ -2,63 +2,60 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
void
runtime·dumpregs(Context *r)
{
runtime·printf("eax %x\n", r->Eax);
runtime·printf("ebx %x\n", r->Ebx);
runtime·printf("ecx %x\n", r->Ecx);
runtime·printf("edx %x\n", r->Edx);
runtime·printf("edi %x\n", r->Edi);
runtime·printf("esi %x\n", r->Esi);
runtime·printf("ebp %x\n", r->Ebp);
runtime·printf("esp %x\n", r->Esp);
runtime·printf("eip %x\n", r->Eip);
runtime·printf("eflags %x\n", r->EFlags);
runtime·printf("cs %x\n", r->SegCs);
runtime·printf("fs %x\n", r->SegFs);
runtime·printf("gs %x\n", r->SegGs);
package runtime
import (
"unsafe"
)
var text struct{}
func dumpregs(r *context) {
print("eax ", hex(r.eax), "\n")
print("ebx ", hex(r.ebx), "\n")
print("ecx ", hex(r.ecx), "\n")
print("edx ", hex(r.edx), "\n")
print("edi ", hex(r.edi), "\n")
print("esi ", hex(r.esi), "\n")
print("ebp ", hex(r.ebp), "\n")
print("esp ", hex(r.esp), "\n")
print("eip ", hex(r.eip), "\n")
print("eflags ", hex(r.eflags), "\n")
print("cs ", hex(r.segcs), "\n")
print("fs ", hex(r.segfs), "\n")
print("gs ", hex(r.seggs), "\n")
}
bool
runtime·isgoexception(ExceptionRecord *info, Context *r)
{
extern byte runtime·text[], runtime·etext[];
func isgoexception(info *exceptionrecord, r *context) bool {
// Only handle exception if executing instructions in Go binary
// (not Windows library code).
if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip)
return false;
// (not Windows library code).
if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip {
return false
}
if(!runtime·issigpanic(info->ExceptionCode))
return false;
if issigpanic(info.exceptioncode) == 0 {
return false
}
return true;
return true
}
// Called by sigtramp from Windows VEH handler.
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
uint32
runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
{
uintptr *sp;
if(!runtime·isgoexception(info, r))
return EXCEPTION_CONTINUE_SEARCH;
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
if !isgoexception(info, r) {
return _EXCEPTION_CONTINUE_SEARCH
}
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = info->ExceptionCode;
gp->sigcode0 = info->ExceptionInformation[0];
gp->sigcode1 = info->ExceptionInformation[1];
gp->sigpc = r->Eip;
gp.sig = info.exceptioncode
gp.sigcode0 = uintptr(info.exceptioninformation[0])
gp.sigcode1 = uintptr(info.exceptioninformation[1])
gp.sigpc = uintptr(r.eip)
// Only push runtime·sigpanic if r->eip != 0.
// If r->eip == 0, probably panicked because of a
......@@ -66,63 +63,56 @@ runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
// make the trace look like a call to runtime·sigpanic instead.
// (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->Eip != 0) {
sp = (uintptr*)r->Esp;
*--sp = r->Eip;
r->Esp = (uintptr)sp;
if r.eip != 0 {
sp := unsafe.Pointer(uintptr(r.esp))
sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
*((*uintptr)(sp)) = uintptr(r.eip)
r.esp = uint32(uintptr(sp))
}
r->Eip = (uintptr)runtime·sigpanic;
return EXCEPTION_CONTINUE_EXECUTION;
r.eip = uint32(funcPC(sigpanic))
return _EXCEPTION_CONTINUE_EXECUTION
}
// lastcontinuehandler is reached, because runtime cannot handle
// current exception. lastcontinuehandler will print crash info and exit.
uint32
runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
{
bool crash;
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
(uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip);
runtime·printf("PC=%x\n", r->Eip);
if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
runtime·printf("signal arrived during cgo execution\n");
gp = g->m->lockedg;
func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
_g_ := getg()
if panicking != 0 { // traceback already printed
exit(2)
}
panicking = 1
print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.eip), "\n")
print("PC=", hex(r.eip), "\n")
if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
print("signal arrived during cgo execution\n")
gp = _g_.m.lockedg
}
print("\n")
var docrash bool
if gotraceback(&docrash) > 0 {
tracebacktrap(uintptr(r.eip), uintptr(r.esp), 0, gp)
tracebackothers(gp)
dumpregs(r)
}
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
if docrash {
crash()
}
if(crash)
runtime·crash();
runtime·exit(2);
return 0; // not reached
exit(2)
return 0 // not reached
}
void
runtime·sigenable(uint32 sig)
{
USED(sig);
func sigenable(sig uint32) {
}
void
runtime·sigdisable(uint32 sig)
{
USED(sig);
func sigdisable(sig uint32) {
}
void
runtime·dosigprof(Context *r, G *gp, M *mp)
{
runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
func dosigprof(r *context, gp *g, mp *m) {
sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp)
}
......@@ -2,71 +2,68 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
void
runtime·dumpregs(Context *r)
{
runtime·printf("rax %X\n", r->Rax);
runtime·printf("rbx %X\n", r->Rbx);
runtime·printf("rcx %X\n", r->Rcx);
runtime·printf("rdx %X\n", r->Rdx);
runtime·printf("rdi %X\n", r->Rdi);
runtime·printf("rsi %X\n", r->Rsi);
runtime·printf("rbp %X\n", r->Rbp);
runtime·printf("rsp %X\n", r->Rsp);
runtime·printf("r8 %X\n", r->R8 );
runtime·printf("r9 %X\n", r->R9 );
runtime·printf("r10 %X\n", r->R10);
runtime·printf("r11 %X\n", r->R11);
runtime·printf("r12 %X\n", r->R12);
runtime·printf("r13 %X\n", r->R13);
runtime·printf("r14 %X\n", r->R14);
runtime·printf("r15 %X\n", r->R15);
runtime·printf("rip %X\n", r->Rip);
runtime·printf("rflags %X\n", r->EFlags);
runtime·printf("cs %X\n", (uint64)r->SegCs);
runtime·printf("fs %X\n", (uint64)r->SegFs);
runtime·printf("gs %X\n", (uint64)r->SegGs);
package runtime
import (
"unsafe"
)
var text struct{}
func dumpregs(r *context) {
print("rax ", hex(r.rax), "\n")
print("rbx ", hex(r.rbx), "\n")
print("rcx ", hex(r.rcx), "\n")
print("rdi ", hex(r.rdi), "\n")
print("rsi ", hex(r.rsi), "\n")
print("rbp ", hex(r.rbp), "\n")
print("rsp ", hex(r.rsp), "\n")
print("r8 ", hex(r.r8), "\n")
print("r9 ", hex(r.r9), "\n")
print("r10 ", hex(r.r10), "\n")
print("r11 ", hex(r.r11), "\n")
print("r12 ", hex(r.r12), "\n")
print("r13 ", hex(r.r13), "\n")
print("r14 ", hex(r.r14), "\n")
print("r15 ", hex(r.r15), "\n")
print("rip ", hex(r.rip), "\n")
print("rflags ", hex(r.eflags), "\n")
print("cs ", hex(r.segcs), "\n")
print("fs ", hex(r.segfs), "\n")
print("gs ", hex(r.seggs), "\n")
}
bool
runtime·isgoexception(ExceptionRecord *info, Context *r)
{
extern byte runtime·text[], runtime·etext[];
func isgoexception(info *exceptionrecord, r *context) bool {
// Only handle exception if executing instructions in Go binary
// (not Windows library code).
if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip)
return false;
// (not Windows library code).
if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip {
return false
}
if(!runtime·issigpanic(info->ExceptionCode))
return false;
if issigpanic(info.exceptioncode) == 0 {
return false
}
return true;
return true
}
// Called by sigtramp from Windows VEH handler.
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
uint32
runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
{
uintptr *sp;
if(!runtime·isgoexception(info, r))
return EXCEPTION_CONTINUE_SEARCH;
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
if !isgoexception(info, r) {
return _EXCEPTION_CONTINUE_SEARCH
}
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = info->ExceptionCode;
gp->sigcode0 = info->ExceptionInformation[0];
gp->sigcode1 = info->ExceptionInformation[1];
gp->sigpc = r->Rip;
gp.sig = info.exceptioncode
gp.sigcode0 = uintptr(info.exceptioninformation[0])
gp.sigcode1 = uintptr(info.exceptioninformation[1])
gp.sigpc = uintptr(r.rip)
// Only push runtime·sigpanic if r->rip != 0.
// If r->rip == 0, probably panicked because of a
......@@ -74,77 +71,67 @@ runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
// make the trace look like a call to runtime·sigpanic instead.
// (Otherwise the trace will end at runtime·sigpanic and we
// won't get to see who faulted.)
if(r->Rip != 0) {
sp = (uintptr*)r->Rsp;
*--sp = r->Rip;
r->Rsp = (uintptr)sp;
if r.rip != 0 {
sp := unsafe.Pointer(uintptr(r.rsp))
sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
*((*uintptr)(sp)) = uintptr(r.rip)
r.rsp = uint64(uintptr(sp))
}
r->Rip = (uintptr)runtime·sigpanic;
return EXCEPTION_CONTINUE_EXECUTION;
r.rip = uint64(funcPC(sigpanic))
return _EXCEPTION_CONTINUE_EXECUTION
}
// It seems Windows searches ContinueHandler's list even
// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
// firstcontinuehandler will stop that search,
// if exceptionhandler did the same earlier.
uint32
runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
{
USED(gp);
if(!runtime·isgoexception(info, r))
return EXCEPTION_CONTINUE_SEARCH;
return EXCEPTION_CONTINUE_EXECUTION;
func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
if !isgoexception(info, r) {
return _EXCEPTION_CONTINUE_SEARCH
}
return _EXCEPTION_CONTINUE_EXECUTION
}
// lastcontinuehandler is reached, because runtime cannot handle
// current exception. lastcontinuehandler will print crash info and exit.
uint32
runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
{
bool crash;
func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
_g_ := getg()
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
if panicking != 0 { // traceback already printed
exit(2)
}
panicking = 1
runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.rip), "\n")
print("PC=", hex(r.rip), "\n")
if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
print("signal arrived during cgo execution\n")
gp = _g_.m.lockedg
}
print("\n")
runtime·printf("PC=%X\n", r->Rip);
if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
runtime·printf("signal arrived during cgo execution\n");
gp = g->m->lockedg;
var docrash bool
if gotraceback(&docrash) > 0 {
tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp)
tracebackothers(gp)
dumpregs(r)
}
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
if docrash {
crash()
}
if(crash)
runtime·crash();
runtime·exit(2);
return 0; // not reached
exit(2)
return 0 // not reached
}
void
runtime·sigenable(uint32 sig)
{
USED(sig);
func sigenable(sig uint32) {
}
void
runtime·sigdisable(uint32 sig)
{
USED(sig);
func sigdisable(sig uint32) {
}
void
runtime·dosigprof(Context *r, G *gp, M *mp)
{
runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
func dosigprof(r *context, gp *g, mp *m) {
sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp)
}
// 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.
package runtime
import "unsafe"
// Call a Windows function with stdcall conventions,
// and switch to os stack during the call.
func asmstdcall(fn unsafe.Pointer)
func getlasterror() uint32
func setlasterror(err uint32)
// Function to be called by windows CreateThread
// to start new os thread.
func tstart_stdcall(newm *m) uint32
func ctrlhandler(_type uint32) uint32
// TODO(brainman): should not need those
const (
_NSIG = 65
)
// 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"
#include "textflag.h"
#include "arch_GOARCH.h"
#include "malloc.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"
#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·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·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "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·WaitForSingleObject WaitForSingleObject "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
extern void *runtime·AddVectoredExceptionHandler;
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·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·SetUnhandledExceptionFilter;
extern void *runtime·SetWaitableTimer;
extern void *runtime·Sleep;
extern void *runtime·SuspendThread;
extern void *runtime·WaitForSingleObject;
extern void *runtime·WriteFile;
extern void *runtime·timeBeginPeriod;
#pragma dataflag NOPTR
void *runtime·GetQueuedCompletionStatusEx;
extern uintptr runtime·externalthreadhandlerp;
void runtime·externalthreadhandler(void);
void runtime·exceptiontramp(void);
void runtime·firstcontinuetramp(void);
void runtime·lastcontinuetramp(void);
#pragma textflag NOSPLIT
uintptr
runtime·getLoadLibrary(void)
{
return (uintptr)runtime·LoadLibrary;
}
#pragma textflag NOSPLIT
uintptr
runtime·getGetProcAddress(void)
{
return (uintptr)runtime·GetProcAddress;
}
static int32
getproccount(void)
{
SystemInfo info;
runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info);
return info.dwNumberOfProcessors;
}
void
runtime·osinit(void)
{
void *kernel32;
void *addVectoredContinueHandler;
kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp);
addVectoredContinueHandler = nil;
if(kernel32 != nil)
addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler");
if(addVectoredContinueHandler == nil || sizeof(void*) == 4) {
// use SetUnhandledExceptionFilter for windows-386 or
// if VectoredContinueHandler is unavailable.
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp);
} else {
runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp);
runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp);
}
runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
runtime·stdcall1(runtime·timeBeginPeriod, 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·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
if(kernel32 != nil) {
runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
}
}
#pragma textflag NOSPLIT
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
uintptr handle;
*rnd = nil;
*rnd_len = 0;
if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil,
1 /* PROV_RSA_FULL */,
0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
static byte random_data[HashRandomBytes];
if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) {
*rnd = random_data;
*rnd_len = HashRandomBytes;
}
runtime·stdcall2(runtime·CryptReleaseContext, handle, 0);
}
}
void
runtime·goenvs(void)
{
extern Slice runtime·envs;
uint16 *env;
String *s;
int32 i, n;
uint16 *p;
env = runtime·stdcall0(runtime·GetEnvironmentStringsW);
n = 0;
for(p=env; *p; n++)
p += runtime·findnullw(p)+1;
runtime·envs = runtime·makeStringSlice(n);
s = (String*)runtime·envs.array;
p = env;
for(i=0; i<n; i++) {
s[i] = runtime·gostringw(p);
p += runtime·findnullw(p)+1;
}
runtime·stdcall1(runtime·FreeEnvironmentStringsW, (uintptr)env);
}
#pragma textflag NOSPLIT
void
runtime·exit(int32 code)
{
runtime·stdcall1(runtime·ExitProcess, code);
}
#pragma textflag NOSPLIT
int32
runtime·write(uintptr fd, void *buf, int32 n)
{
void *handle;
uint32 written;
written = 0;
switch(fd) {
case 1:
handle = runtime·stdcall1(runtime·GetStdHandle, -11);
break;
case 2:
handle = runtime·stdcall1(runtime·GetStdHandle, -12);
break;
default:
// assume fd is real windows handle.
handle = (void*)fd;
break;
}
runtime·stdcall5(runtime·WriteFile, (uintptr)handle, (uintptr)buf, n, (uintptr)&written, 0);
return written;
}
#define INFINITE ((uintptr)0xFFFFFFFF)
#pragma textflag NOSPLIT
int32
runtime·semasleep(int64 ns)
{
// store ms in ns to save stack space
if(ns < 0)
ns = INFINITE;
else {
ns = runtime·timediv(ns, 1000000, nil);
if(ns == 0)
ns = 1;
}
if(runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)g->m->waitsema, ns) != 0)
return -1; // timeout
return 0;
}
#pragma textflag NOSPLIT
void
runtime·semawakeup(M *mp)
{
runtime·stdcall1(runtime·SetEvent, mp->waitsema);
}
#pragma textflag NOSPLIT
uintptr
runtime·semacreate(void)
{
return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0);
}
#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
void
runtime·newosproc(M *mp, void *stk)
{
void *thandle;
USED(stk);
thandle = runtime·stdcall6(runtime·CreateThread,
(uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp,
STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)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");
}
}
// 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)
{
uintptr thandle;
// -1 = current process, -2 = current thread
runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS);
runtime·atomicstoreuintptr(&g->m->thread, thandle);
}
// Called from dropm to undo the effect of an minit.
void
runtime·unminit(void)
{
runtime·stdcall1(runtime·CloseHandle, g->m->thread);
g->m->thread = 0;
}
// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
typedef struct KSYSTEM_TIME {
uint32 LowPart;
int32 High1Time;
int32 High2Time;
} KSYSTEM_TIME;
#pragma dataflag NOPTR
const KSYSTEM_TIME* INTERRUPT_TIME = (KSYSTEM_TIME*)0x7ffe0008;
#pragma dataflag NOPTR
const KSYSTEM_TIME* SYSTEM_TIME = (KSYSTEM_TIME*)0x7ffe0014;
static void badsystime(void);
#pragma textflag NOSPLIT
int64
runtime·systime(KSYSTEM_TIME *timeaddr)
{
KSYSTEM_TIME t;
int32 i;
void (*fn)(void);
for(i = 1; i < 10000; i++) {
// these fields must be read in that order (see URL above)
t.High1Time = timeaddr->High1Time;
t.LowPart = timeaddr->LowPart;
t.High2Time = timeaddr->High2Time;
if(t.High1Time == t.High2Time)
return (int64)t.High1Time<<32 | t.LowPart;
if((i%100) == 0)
runtime·osyield();
}
fn = badsystime;
runtime·onM(&fn);
return 0;
}
#pragma textflag NOSPLIT
int64
runtime·unixnano(void)
{
return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL;
}
static void
badsystime(void)
{
runtime·throw("interrupt/system time is changing too fast");
}
#pragma textflag NOSPLIT
int64
runtime·nanotime(void)
{
return runtime·systime(INTERRUPT_TIME) * 100LL;
}
// Calling stdcall on os stack.
#pragma textflag NOSPLIT
static void*
stdcall(void *fn)
{
g->m->libcall.fn = (uintptr)fn;
if(g->m->profilehz != 0) {
// leave pc/sp for cpu profiler
g->m->libcallg = g;
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
g->m->libcallsp = (uintptr)runtime·getcallersp(&fn);
}
runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall);
g->m->libcallsp = 0;
return (void*)g->m->libcall.r1;
}
#pragma textflag NOSPLIT
void*
runtime·stdcall0(void *fn)
{
g->m->libcall.n = 0;
g->m->libcall.args = (uintptr)&fn; // it's unused but must be non-nil, otherwise crashes
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall1(void *fn, uintptr a0)
{
USED(a0);
g->m->libcall.n = 1;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall2(void *fn, uintptr a0, uintptr a1)
{
USED(a0, a1);
g->m->libcall.n = 2;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2)
{
USED(a0, a1, a2);
g->m->libcall.n = 3;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3)
{
USED(a0, a1, a2, a3);
g->m->libcall.n = 4;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4)
{
USED(a0, a1, a2, a3, a4);
g->m->libcall.n = 5;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5)
{
USED(a0, a1, a2, a3, a4, a5);
g->m->libcall.n = 6;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
#pragma textflag NOSPLIT
void*
runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6)
{
USED(a0, a1, a2, a3, a4, a5, a6);
g->m->libcall.n = 7;
g->m->libcall.args = (uintptr)&a0;
return stdcall(fn);
}
extern void runtime·usleep1(uint32);
#pragma textflag NOSPLIT
void
runtime·osyield(void)
{
runtime·usleep1(1);
}
#pragma textflag NOSPLIT
void
runtime·usleep(uint32 us)
{
// Have 1us units; want 100ns units.
runtime·usleep1(10*us);
}
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:
case EXCEPTION_BREAKPOINT:
return 1;
}
return 0;
}
void
runtime·initsig(void)
{
// following line keeps these functions alive at link stage
// if there's a better way please write it here
void *e = runtime·exceptiontramp;
void *f = runtime·firstcontinuetramp;
void *l = runtime·lastcontinuetramp;
USED(e);
USED(f);
USED(l);
}
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, M *mp);
extern void runtime·profileloop(void);
#pragma dataflag NOPTR
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;
// align Context to 16 bytes
r = (Context*)((uintptr)(&rbuf[15]) & ~15);
r->ContextFlags = CONTEXT_CONTROL;
runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r);
runtime·dosigprof(r, gp, mp);
}
void
runtime·profileloop1(void)
{
M *mp, *allm;
uintptr thread;
runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST);
for(;;) {
runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1);
allm = runtime·atomicloadp(&runtime·allm);
for(mp = allm; mp != nil; mp = mp->alllink) {
thread = runtime·atomicloaduintptr(&mp->thread);
// Do not profile threads blocked on Notes,
// this includes idle worker threads,
// idle timer thread, idle heap scavenger, etc.
if(thread == 0 || mp->profilehz == 0 || mp->blocked)
continue;
runtime·stdcall1(runtime·SuspendThread, (uintptr)thread);
if(mp->profilehz != 0 && !mp->blocked)
profilem(mp);
runtime·stdcall1(runtime·ResumeThread, (uintptr)thread);
}
}
}
void
runtime·resetcpuprofiler(int32 hz)
{
static Mutex lock;
void *timer, *thread;
int32 ms;
int64 due;
runtime·lock(&lock);
if(profiletimer == nil) {
timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil);
runtime·atomicstorep(&profiletimer, timer);
thread = runtime·stdcall6(runtime·CreateThread,
(uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil);
runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST);
runtime·stdcall1(runtime·CloseHandle, (uintptr)thread);
}
runtime·unlock(&lock);
ms = 0;
due = 1LL<<63;
if(hz > 0) {
ms = 1000 / hz;
if(ms == 0)
ms = 1;
due = ms * -10000;
}
runtime·stdcall6(runtime·SetWaitableTimer,
(uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil);
runtime·atomicstore((uint32*)&g->m->profilehz, hz);
}
uintptr
runtime·memlimit(void)
{
return 0;
}
#pragma dataflag NOPTR
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.
}
......@@ -4,24 +4,8 @@
package runtime
import "unsafe"
type stdFunction *byte
func stdcall0(fn stdFunction) uintptr
func stdcall1(fn stdFunction, a0 uintptr) uintptr
func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr
func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr
func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr
func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr
func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr
func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr
func asmstdcall(fn unsafe.Pointer)
func getlasterror() uint32
func setlasterror(err uint32)
func usleep1(usec uint32)
func os_sigpipe() {
gothrow("too many writes on closed pipe")
}
......
// 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.
extern void *runtime·LoadLibrary;
extern void *runtime·GetProcAddress;
extern void *runtime·GetQueuedCompletionStatusEx;
// Call a Windows function with stdcall conventions,
// and switch to os stack during the call.
void runtime·asmstdcall(void *c);
void *runtime·stdcall0(void *fn);
void *runtime·stdcall1(void *fn, uintptr a0);
void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1);
void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2);
void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3);
void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
uint32 runtime·getlasterror(void);
void runtime·setlasterror(uint32 err);
// Function to be called by windows CreateThread
// to start new os thread.
uint32 runtime·tstart_stdcall(M *newm);
uint32 runtime·issigpanic(uint32);
void runtime·sigpanic(void);
uint32 runtime·ctrlhandler(uint32 type);
// Windows dll function to go callback entry.
byte *runtime·compilecallback(Eface fn, bool cleanstack);
void *runtime·callbackasm(void);
void runtime·install_exception_handler(void);
void runtime·remove_exception_handler(void);
// TODO(brainman): should not need those
enum {
NSIG = 65,
};
......@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build !solaris
// +build !windows
package runtime
......
......@@ -41,20 +41,20 @@ func callbackasmAddr(i int) uintptr {
func compileCallback(fn eface, cleanstack bool) (code uintptr) {
if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
panic("compilecallback: not a function")
panic("compileCallback: not a function")
}
ft := (*functype)(unsafe.Pointer(fn._type))
if len(ft.out) != 1 {
panic("compilecallback: function must have one output parameter")
if ft.out.len != 1 {
panic("compileCallback: function must have one output parameter")
}
uintptrSize := unsafe.Sizeof(uintptr(0))
if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize {
panic("compilecallback: output parameter size is wrong")
if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize {
panic("compileCallback: output parameter size is wrong")
}
argsize := uintptr(0)
for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] {
for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] {
if (*t).size > uintptrSize {
panic("compilecallback: input parameter size is wrong")
panic("compileCallback: input parameter size is wrong")
}
argsize += uintptrSize
}
......@@ -87,8 +87,6 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
return callbackasmAddr(n)
}
func getLoadLibrary() uintptr
//go:nosplit
func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
var c libcall
......@@ -103,8 +101,6 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
return
}
func getGetProcAddress() uintptr
//go:nosplit
func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
var c libcall
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment