runtime: use newm for profileloop

This replaces the externalthreadhandler-based implementation of
profileloop with one that uses newm to start a new thread. This is a
step toward eliminating externalthreadhandler.

For #45530.

Change-Id: Id8e5540423fe2d2004024b649afec6998f77b092
Reviewed-on: https://go-review.googlesource.com/c/go/+/309633
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
Austin Clements 2021-04-13 08:32:21 -04:00
parent e512bc2cf0
commit e69f02265c
5 changed files with 9 additions and 32 deletions

View file

@ -1198,9 +1198,6 @@ func ctrlHandler(_type uint32) uintptr {
return 0 return 0
} }
// in sys_windows_386.s and sys_windows_amd64.s
func profileloop()
// called from zcallback_windows_*.s to sys_windows_*.s // called from zcallback_windows_*.s to sys_windows_*.s
func callbackasm1() func callbackasm1()
@ -1233,13 +1230,18 @@ func gFromSP(mp *m, sp uintptr) *g {
return nil return nil
} }
func profileloop1(param uintptr) uint32 { func profileLoop() {
stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
for { for {
stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
first := (*m)(atomic.Loadp(unsafe.Pointer(&allm))) first := (*m)(atomic.Loadp(unsafe.Pointer(&allm)))
for mp := first; mp != nil; mp = mp.alllink { for mp := first; mp != nil; mp = mp.alllink {
if mp == getg().m {
// Don't profile ourselves.
continue
}
lock(&mp.threadLock) lock(&mp.threadLock)
// Do not profile threads blocked on Notes, // Do not profile threads blocked on Notes,
// this includes idle worker threads, // this includes idle worker threads,
@ -1251,8 +1253,8 @@ func profileloop1(param uintptr) uint32 {
// Acquire our own handle to the thread. // Acquire our own handle to the thread.
var thread uintptr var thread uintptr
if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 { if stdcall7(_DuplicateHandle, currentProcess, mp.thread, currentProcess, uintptr(unsafe.Pointer(&thread)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 {
print("runtime.profileloop1: duplicatehandle failed; errno=", getlasterror(), "\n") print("runtime: duplicatehandle failed; errno=", getlasterror(), "\n")
throw("runtime.profileloop1: duplicatehandle failed") throw("duplicatehandle failed")
} }
unlock(&mp.threadLock) unlock(&mp.threadLock)
@ -1280,9 +1282,7 @@ func setProcessCPUProfiler(hz int32) {
if profiletimer == 0 { if profiletimer == 0 {
timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
atomic.Storeuintptr(&profiletimer, timer) atomic.Storeuintptr(&profiletimer, timer)
thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) newm(profileLoop, nil, -1)
stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
stdcall1(_CloseHandle, thread)
} }
} }

View file

@ -156,15 +156,6 @@ TEXT runtime·lastcontinuetramp<ABIInternal>(SB),NOSPLIT,$0-0
MOVL $runtime·lastcontinuehandler(SB), AX MOVL $runtime·lastcontinuehandler(SB), AX
JMP sigtramp<>(SB) JMP sigtramp<>(SB)
// Called by OS using stdcall ABI: uint32 profileloop(void*).
TEXT runtime·profileloop<ABIInternal>(SB),NOSPLIT,$0
PUSHL $runtime·profileloop1(SB)
NOP SP // tell vet SP changed - stop checking offsets
CALL runtime·externalthreadhandler(SB)
MOVL 4(SP), CX
ADDL $12, SP
JMP CX
TEXT runtime·externalthreadhandler<ABIInternal>(SB),NOSPLIT|TOPFRAME,$0 TEXT runtime·externalthreadhandler<ABIInternal>(SB),NOSPLIT|TOPFRAME,$0
PUSHL BP PUSHL BP
MOVL SP, BP MOVL SP, BP

View file

@ -202,12 +202,6 @@ TEXT runtime·lastcontinuetramp<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-0
MOVQ $runtime·lastcontinuehandler(SB), AX MOVQ $runtime·lastcontinuehandler(SB), AX
JMP sigtramp<>(SB) JMP sigtramp<>(SB)
TEXT runtime·profileloop<ABIInternal>(SB),NOSPLIT|NOFRAME,$8
MOVQ $runtime·profileloop1(SB), CX
MOVQ CX, 0(SP)
CALL runtime·externalthreadhandler<ABIInternal>(SB)
RET
TEXT runtime·externalthreadhandler<ABIInternal>(SB),NOSPLIT|NOFRAME|TOPFRAME,$0 TEXT runtime·externalthreadhandler<ABIInternal>(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
PUSHQ BP PUSHQ BP
MOVQ SP, BP MOVQ SP, BP

View file

@ -233,10 +233,6 @@ TEXT runtime·lastcontinuetramp<ABIInternal>(SB),NOSPLIT|NOFRAME,$0
MOVW $runtime·lastcontinuehandler(SB), R1 MOVW $runtime·lastcontinuehandler(SB), R1
B sigtramp<>(SB) B sigtramp<>(SB)
TEXT runtime·profileloop<ABIInternal>(SB),NOSPLIT|NOFRAME,$0
MOVW $runtime·profileloop1(SB), R1
B runtime·externalthreadhandler<ABIInternal>(SB)
// int32 externalthreadhandler(uint32 arg, int (*func)(uint32)) // int32 externalthreadhandler(uint32 arg, int (*func)(uint32))
// stack layout: // stack layout:
// +----------------+ // +----------------+

View file

@ -299,10 +299,6 @@ TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0
MOVD $runtime·lastcontinuehandler<ABIInternal>(SB), R1 MOVD $runtime·lastcontinuehandler<ABIInternal>(SB), R1
B sigtramp<>(SB) B sigtramp<>(SB)
TEXT runtime·profileloop<ABIInternal>(SB),NOSPLIT|NOFRAME,$0
MOVD $runtime·profileloop1(SB), R1
B runtime·externalthreadhandler<ABIInternal>(SB)
// externalthreadhander called with R0 = uint32 arg, R1 = Go function f. // externalthreadhander called with R0 = uint32 arg, R1 = Go function f.
// Need to call f(arg), which returns a uint32, and return it in R0. // Need to call f(arg), which returns a uint32, and return it in R0.
TEXT runtime·externalthreadhandler<ABIInternal>(SB),NOSPLIT|TOPFRAME,$96-0 TEXT runtime·externalthreadhandler<ABIInternal>(SB),NOSPLIT|TOPFRAME,$96-0