//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateWaitableTimerExW CreateWaitableTimerExW%4 "kernel32.dll"
//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
//go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
_CreateIoCompletionPort,
_CreateThread,
_CreateWaitableTimerA,
+ _CreateWaitableTimerExW,
_DuplicateHandle,
_ExitProcess,
_FreeEnvironmentStringsW,
waitsema uintptr // semaphore for parking on locks
resumesema uintptr // semaphore to indicate suspend/resume
+ highResTimer uintptr // high resolution timer handle used in usleep
+
// preemptExtLock synchronizes preemptM with entry/exit from
// external C code.
//
// osRelax is called by the scheduler when transitioning to and from
// all Ps being idle.
//
-// On Windows, it adjusts the system-wide timer resolution. Go needs a
+// Some versions of Windows have high resolution timer. For those
+// versions osRelax is noop.
+// For Windows versions without high resolution timer, osRelax
+// adjusts the system-wide timer resolution. Go needs a
// high resolution timer while running and there's little extra cost
// if we're already using the CPU, but if all Ps are idle there's no
// need to consume extra power to drive the high-res timer.
func osRelax(relax bool) uint32 {
+ if haveHighResTimer {
+ // If the high resolution timer is available, the runtime uses the timer
+ // to sleep for short durations. This means there's no need to adjust
+ // the global clock frequency.
+ return 0
+ }
+
if relax {
return uint32(stdcall1(_timeEndPeriod, 1))
} else {
}
}
+// haveHighResTimer indicates that the CreateWaitableTimerEx
+// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available.
+var haveHighResTimer = false
+
+// createHighResTimer calls CreateWaitableTimerEx with
+// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag to create high
+// resolution timer. createHighResTimer returns new timer
+// handle or 0, if CreateWaitableTimerEx failed.
+func createHighResTimer() uintptr {
+ const (
+ // As per @jstarks, see
+ // https://github.com/golang/go/issues/8687#issuecomment-656259353
+ _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002
+
+ _SYNCHRONIZE = 0x00100000
+ _TIMER_QUERY_STATE = 0x0001
+ _TIMER_MODIFY_STATE = 0x0002
+ )
+ return stdcall4(_CreateWaitableTimerExW, 0, 0,
+ _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
+ _SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
+}
+
+func initHighResTimer() {
+ if GOARCH == "arm" {
+ // TODO: Not yet implemented.
+ return
+ }
+ h := createHighResTimer()
+ if h != 0 {
+ haveHighResTimer = true
+ usleep2Addr = unsafe.Pointer(funcPC(usleep2HighRes))
+ stdcall1(_CloseHandle, h)
+ }
+}
+
func osinit() {
asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
usleep2Addr = unsafe.Pointer(funcPC(usleep2))
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
+ initHighResTimer()
timeBeginPeriodRetValue = osRelax(false)
ncpu = getproccount()
var thandle uintptr
stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
+ // Configure usleep timer, if possible.
+ var timer uintptr
+ if haveHighResTimer {
+ timer = createHighResTimer()
+ if timer == 0 {
+ print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
+ throw("CreateWaitableTimerEx when creating timer failed")
+ }
+ }
+
mp := getg().m
lock(&mp.threadLock)
mp.thread = thandle
+ mp.highResTimer = timer
unlock(&mp.threadLock)
// Query the true stack base from the OS. Currently we're
lock(&mp.threadLock)
stdcall1(_CloseHandle, mp.thread)
mp.thread = 0
+ if mp.highResTimer != 0 {
+ stdcall1(_CloseHandle, mp.highResTimer)
+ mp.highResTimer = 0
+ }
unlock(&mp.threadLock)
}
return stdcall(fn)
}
-// in sys_windows_386.s and sys_windows_amd64.s
+// In sys_windows_386.s and sys_windows_amd64.s.
func onosstack(fn unsafe.Pointer, arg uint32)
+
+// These are not callable functions. They should only be called via onosstack.
func usleep2(usec uint32)
+func usleep2HighRes(usec uint32)
func switchtothread()
var usleep2Addr unsafe.Pointer
MOVL BP, SP
RET
+// Runs on OS stack. duration (in 100ns units) is in BX.
+TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36
+ // Want negative 100ns units.
+ NEGL BX
+ MOVL $-1, hi-4(SP)
+ MOVL BX, lo-8(SP)
+
+ get_tls(CX)
+ MOVL g(CX), CX
+ MOVL g_m(CX), CX
+ MOVL (m_mOS+mOS_highResTimer)(CX), CX
+ MOVL CX, saved_timer-12(SP)
+
+ MOVL $0, fResume-16(SP)
+ MOVL $0, lpArgToCompletionRoutine-20(SP)
+ MOVL $0, pfnCompletionRoutine-24(SP)
+ MOVL $0, lPeriod-28(SP)
+ LEAL lo-8(SP), BX
+ MOVL BX, lpDueTime-32(SP)
+ MOVL CX, hTimer-36(SP)
+ MOVL SP, BP
+ MOVL runtime·_SetWaitableTimer(SB), AX
+ CALL AX
+ MOVL BP, SP
+
+ MOVL $0, ptime-28(SP)
+ MOVL $0, alertable-32(SP)
+ MOVL saved_timer-12(SP), CX
+ MOVL CX, handle-36(SP)
+ MOVL SP, BP
+ MOVL runtime·_NtWaitForSingleObject(SB), AX
+ CALL AX
+ MOVL BP, SP
+
+ RET
+
// Runs on OS stack.
TEXT runtime·switchtothread(SB),NOSPLIT,$0
MOVL SP, BP
MOVQ 40(SP), SP
RET
+// Runs on OS stack. duration (in 100ns units) is in BX.
+TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
+ MOVQ SP, AX
+ ANDQ $~15, SP // alignment as per Windows requirement
+ MOVQ AX, 64(SP)
+
+ get_tls(CX)
+ MOVQ g(CX), CX
+ MOVQ g_m(CX), CX
+ MOVQ (m_mOS+mOS_highResTimer)(CX), CX // hTimer
+ MOVQ CX, 48(SP) // save hTimer for later
+ // Want negative 100ns units.
+ NEGQ BX
+ LEAQ 56(SP), DX // lpDueTime
+ MOVQ BX, (DX)
+ MOVQ $0, R8 // lPeriod
+ MOVQ $0, R9 // pfnCompletionRoutine
+ MOVQ $0, AX
+ MOVQ AX, 32(SP) // lpArgToCompletionRoutine
+ MOVQ AX, 40(SP) // fResume
+ MOVQ runtime·_SetWaitableTimer(SB), AX
+ CALL AX
+
+ MOVQ 48(SP), CX // handle
+ MOVQ $0, DX // alertable
+ MOVQ $0, R8 // ptime
+ MOVQ runtime·_NtWaitForSingleObject(SB), AX
+ CALL AX
+
+ MOVQ 64(SP), SP
+ RET
+
// Runs on OS stack.
TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
MOVQ SP, AX