mirror of
https://github.com/golang/go
synced 2024-11-23 13:40:04 -07:00
[dev.cc] runtime: convert remaining windows C code to Go
LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/177090043
This commit is contained in:
parent
f4a525452e
commit
ab4578adef
@ -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)
|
||||
}
|
||||
|
564
src/runtime/os1_windows.go
Normal file
564
src/runtime/os1_windows.go
Normal file
@ -0,0 +1,564 @@
|
||||
// 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.
|
||||
}
|
118
src/runtime/os1_windows_386.go
Normal file
118
src/runtime/os1_windows_386.go
Normal file
@ -0,0 +1,118 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
func isgoexception(info *exceptionrecord, r *context) bool {
|
||||
// Only handle exception if executing instructions in Go binary
|
||||
// (not Windows library code).
|
||||
if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip {
|
||||
return false
|
||||
}
|
||||
|
||||
if issigpanic(info.exceptioncode) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
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).
|
||||
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 = 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
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// 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 := 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 = uint32(funcPC(sigpanic))
|
||||
return _EXCEPTION_CONTINUE_EXECUTION
|
||||
}
|
||||
|
||||
// lastcontinuehandler is reached, because runtime cannot handle
|
||||
// current exception. lastcontinuehandler will print crash info and exit.
|
||||
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)
|
||||
}
|
||||
|
||||
if docrash {
|
||||
crash()
|
||||
}
|
||||
|
||||
exit(2)
|
||||
return 0 // not reached
|
||||
}
|
||||
|
||||
func sigenable(sig uint32) {
|
||||
}
|
||||
|
||||
func sigdisable(sig uint32) {
|
||||
}
|
||||
|
||||
func dosigprof(r *context, gp *g, mp *m) {
|
||||
sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp)
|
||||
}
|
137
src/runtime/os1_windows_amd64.go
Normal file
137
src/runtime/os1_windows_amd64.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2011 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"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
func isgoexception(info *exceptionrecord, r *context) bool {
|
||||
// Only handle exception if executing instructions in Go binary
|
||||
// (not Windows library code).
|
||||
if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip {
|
||||
return false
|
||||
}
|
||||
|
||||
if issigpanic(info.exceptioncode) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
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).
|
||||
|
||||
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 = 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
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// 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 := 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 = 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.
|
||||
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.
|
||||
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.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")
|
||||
|
||||
var docrash bool
|
||||
if gotraceback(&docrash) > 0 {
|
||||
tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp)
|
||||
tracebackothers(gp)
|
||||
dumpregs(r)
|
||||
}
|
||||
|
||||
if docrash {
|
||||
crash()
|
||||
}
|
||||
|
||||
exit(2)
|
||||
return 0 // not reached
|
||||
}
|
||||
|
||||
func sigenable(sig uint32) {
|
||||
}
|
||||
|
||||
func sigdisable(sig uint32) {
|
||||
}
|
||||
|
||||
func dosigprof(r *context, gp *g, mp *m) {
|
||||
sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp)
|
||||
}
|
25
src/runtime/os2_windows.go
Normal file
25
src/runtime/os2_windows.go
Normal file
@ -0,0 +1,25 @@
|
||||
// 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
|
||||
)
|
@ -1,636 +0,0 @@
|
||||
// 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")
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
// 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,
|
||||
};
|
@ -1,128 +0,0 @@
|
||||
// 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 "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);
|
||||
}
|
||||
|
||||
bool
|
||||
runtime·isgoexception(ExceptionRecord *info, Context *r)
|
||||
{
|
||||
extern byte runtime·text[], runtime·etext[];
|
||||
|
||||
// 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;
|
||||
|
||||
if(!runtime·issigpanic(info->ExceptionCode))
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
// Only push runtime·sigpanic if r->eip != 0.
|
||||
// If r->eip == 0, probably panicked because of a
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// 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;
|
||||
}
|
||||
r->Eip = (uintptr)runtime·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;
|
||||
}
|
||||
runtime·printf("\n");
|
||||
|
||||
if(runtime·gotraceback(&crash)){
|
||||
runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
|
||||
runtime·tracebackothers(gp);
|
||||
runtime·dumpregs(r);
|
||||
}
|
||||
|
||||
if(crash)
|
||||
runtime·crash();
|
||||
|
||||
runtime·exit(2);
|
||||
return 0; // not reached
|
||||
}
|
||||
|
||||
void
|
||||
runtime·sigenable(uint32 sig)
|
||||
{
|
||||
USED(sig);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·sigdisable(uint32 sig)
|
||||
{
|
||||
USED(sig);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·dosigprof(Context *r, G *gp, M *mp)
|
||||
{
|
||||
runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
// Copyright 2011 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 "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);
|
||||
}
|
||||
|
||||
bool
|
||||
runtime·isgoexception(ExceptionRecord *info, Context *r)
|
||||
{
|
||||
extern byte runtime·text[], runtime·etext[];
|
||||
|
||||
// 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;
|
||||
|
||||
if(!runtime·issigpanic(info->ExceptionCode))
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
// Only push runtime·sigpanic if r->rip != 0.
|
||||
// If r->rip == 0, probably panicked because of a
|
||||
// call to a nil func. Not pushing that onto sp will
|
||||
// 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;
|
||||
}
|
||||
r->Rip = (uintptr)runtime·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;
|
||||
}
|
||||
|
||||
// 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,
|
||||
info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
runtime·printf("\n");
|
||||
|
||||
if(runtime·gotraceback(&crash)){
|
||||
runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
|
||||
runtime·tracebackothers(gp);
|
||||
runtime·dumpregs(r);
|
||||
}
|
||||
|
||||
if(crash)
|
||||
runtime·crash();
|
||||
|
||||
runtime·exit(2);
|
||||
return 0; // not reached
|
||||
}
|
||||
|
||||
void
|
||||
runtime·sigenable(uint32 sig)
|
||||
{
|
||||
USED(sig);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·sigdisable(uint32 sig)
|
||||
{
|
||||
USED(sig);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·dosigprof(Context *r, G *gp, M *mp)
|
||||
{
|
||||
runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user