Skip to content

Commit

Permalink
runtime: implement high resolution timer on windows arm/arm64
Browse files Browse the repository at this point in the history
This CL moves the usleep2HighRes from assembly to good old Go.
This is safe because since CL 288793 usleep is always called with
a g, else one wold have to call usleep_no_g. This condition was
not enforced when high resolution timers were first implemented
on Windows (CL 248699), so the implementation was done in assembly.

Other than removing a bunch of obscure assembly code, this CL makes
high resolution timers work on windows arm/arm64 by free, as the
system calls are the same in all windows platforms.

Change-Id: I41ecf78026fd7e11e85258a411ae074a77e8c7fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/471142
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
  • Loading branch information
qmuntal authored and gopherbot committed Mar 13, 2023
1 parent b561eba commit b6f29d2
Show file tree
Hide file tree
Showing 5 changed files with 5 additions and 94 deletions.
15 changes: 5 additions & 10 deletions src/runtime/os_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,13 +440,7 @@ func createHighResTimer() uintptr {
_SYNCHRONIZE|_TIMER_QUERY_STATE|_TIMER_MODIFY_STATE)
}

const highResTimerSupported = GOARCH == "386" || GOARCH == "amd64"

func initHighResTimer() {
if !highResTimerSupported {
// TODO: Not yet implemented.
return
}
h := createHighResTimer()
if h != 0 {
haveHighResTimer = true
Expand Down Expand Up @@ -1130,7 +1124,6 @@ func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {

// These must run on the system stack only.
func usleep2(dt int32)
func usleep2HighRes(dt int32)
func switchtothread()

//go:nosplit
Expand All @@ -1152,13 +1145,15 @@ func usleep_no_g(us uint32) {
//go:nosplit
func usleep(us uint32) {
systemstack(func() {
dt := -10 * int32(us) // relative sleep (negative), 100ns units
dt := -10 * int64(us) // relative sleep (negative), 100ns units
// If the high-res timer is available and its handle has been allocated for this m, use it.
// Otherwise fall back to the low-res one, which doesn't need a handle.
if haveHighResTimer && getg().m.highResTimer != 0 {
usleep2HighRes(dt)
h := getg().m.highResTimer
stdcall6(_SetWaitableTimer, h, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0)
stdcall3(_NtWaitForSingleObject, h, 0, 0)
} else {
usleep2(dt)
usleep2(int32(dt))
}
})
}
Expand Down
37 changes: 0 additions & 37 deletions src/runtime/sys_windows_386.s
Original file line number Diff line number Diff line change
Expand Up @@ -241,43 +241,6 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20-4
MOVL BP, SP
RET

// Runs on OS stack.
// duration (in -100ns units) is in dt+0(FP).
// g is valid.
TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36-4
MOVL dt+0(FP), 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
Expand Down
33 changes: 0 additions & 33 deletions src/runtime/sys_windows_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -251,39 +251,6 @@ TEXT runtime·usleep2(SB),NOSPLIT,$48-4
MOVQ 40(SP), SP
RET

// Runs on OS stack. duration (in -100ns units) is in dt+0(FP).
// g is valid.
TEXT runtime·usleep2HighRes(SB),NOSPLIT,$72-4
MOVLQSX dt+0(FP), BX
get_tls(CX)

MOVQ SP, AX
ANDQ $~15, SP // alignment as per Windows requirement
MOVQ AX, 64(SP)

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
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,$0
MOVQ SP, AX
Expand Down
7 changes: 0 additions & 7 deletions src/runtime/sys_windows_arm.s
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,6 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0-4
MOVW R4, R13 // Restore SP
MOVM.IA.W (R13), [R4, R15] // pop {R4, pc}

// Runs on OS stack.
// duration (in -100ns units) is in dt+0(FP).
// g is valid.
// TODO: needs to be implemented properly.
TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0-4
B runtime·abort(SB)

// Runs on OS stack.
TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
MOVM.DB.W [R4, R14], (R13) // push {R4, lr}
Expand Down
7 changes: 0 additions & 7 deletions src/runtime/sys_windows_arm64.s
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,6 @@ TEXT runtime·usleep2(SB),NOSPLIT,$32-4
ADD $16, RSP
RET

// Runs on OS stack.
// duration (in -100ns units) is in dt+0(FP).
// g is valid.
// TODO: needs to be implemented properly.
TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0-4
B runtime·abort(SB)

// Runs on OS stack.
TEXT runtime·switchtothread(SB),NOSPLIT,$16-0
MOVD runtime·_SwitchToThread(SB), R0
Expand Down

0 comments on commit b6f29d2

Please sign in to comment.