aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/runtime/os_windows.go81
-rw-r--r--src/runtime/syscall_windows.go12
2 files changed, 80 insertions, 13 deletions
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index d3e84fe3dc..a3292c427b 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -49,6 +49,7 @@ const (
//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._WaitForMultipleObjects WaitForMultipleObjects%4 "kernel32.dll"
//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
@@ -96,6 +97,7 @@ var (
_VirtualFree,
_VirtualQuery,
_WaitForSingleObject,
+ _WaitForMultipleObjects,
_WriteConsoleW,
_WriteFile,
_ stdFunction
@@ -138,7 +140,8 @@ func tstart_stdcall(newm *m) uint32
func ctrlhandler(_type uint32) uint32
type mOS struct {
- waitsema uintptr // semaphore for parking on locks
+ waitsema uintptr // semaphore for parking on locks
+ resumesema uintptr // semaphore to indicate suspend/resume
}
//go:linkname os_sigpipe os.sigpipe
@@ -257,6 +260,40 @@ func loadOptionalSyscalls() {
}
}
+func monitorSuspendResume() {
+ const _DEVICE_NOTIFY_CALLBACK = 2
+ type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
+ callback uintptr
+ context uintptr
+ }
+
+ powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
+ if powrprof == 0 {
+ return // Running on Windows 7, where we don't need it anyway.
+ }
+ powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
+ if powerRegisterSuspendResumeNotification == nil {
+ return // Running on Windows 7, where we don't need it anyway.
+ }
+ var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
+ for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+ if mp.resumesema != 0 {
+ stdcall1(_SetEvent, mp.resumesema)
+ }
+ }
+ return 0
+ }
+ params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
+ callback: compileCallback(*efaceOf(&fn), true),
+ }
+ handle := uintptr(0)
+ if stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK,
+ uintptr(unsafe.Pointer(&params)),
+ uintptr(unsafe.Pointer(&handle))) != 0 {
+ throw("PowerRegisterSuspendResumeNotification failure")
+ }
+}
+
//go:nosplit
func getLoadLibrary() uintptr {
return uintptr(unsafe.Pointer(_LoadLibraryW))
@@ -487,6 +524,10 @@ func goenvs() {
}
stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
+
+ // We call this all the way here, late in init, so that malloc works
+ // for the callback function this generates.
+ monitorSuspendResume()
}
// exiting is set to non-zero when the process is exiting.
@@ -605,19 +646,32 @@ func semasleep(ns int64) int32 {
_WAIT_FAILED = 0xFFFFFFFF
)
- // store ms in ns to save stack space
+ var result uintptr
if ns < 0 {
- ns = _INFINITE
+ result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
} else {
- ns = int64(timediv(ns, 1000000, nil))
- if ns == 0 {
- ns = 1
+ start := nanotime()
+ elapsed := int64(0)
+ for {
+ ms := int64(timediv(ns-elapsed, 1000000, nil))
+ if ms == 0 {
+ ms = 1
+ }
+ result = stdcall4(_WaitForMultipleObjects, 2,
+ uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
+ 0, uintptr(ms))
+ if result != _WAIT_OBJECT_0+1 {
+ // Not a suspend/resume event
+ break
+ }
+ elapsed = nanotime() - start
+ if elapsed >= ns {
+ return -1
+ }
}
}
-
- result := stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns))
switch result {
- case _WAIT_OBJECT_0: //signaled
+ case _WAIT_OBJECT_0: // Signaled
return 0
case _WAIT_TIMEOUT:
@@ -666,6 +720,15 @@ func semacreate(mp *m) {
throw("runtime.semacreate")
})
}
+ mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
+ if mp.resumesema == 0 {
+ systemstack(func() {
+ print("runtime: createevent failed; errno=", getlasterror(), "\n")
+ throw("runtime.semacreate")
+ })
+ stdcall1(_CloseHandle, mp.waitsema)
+ mp.waitsema = 0
+ }
}
// May run with m.p==nil, so write barriers are not allowed. This
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 36ad7511af..920468286b 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -74,16 +74,18 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
argsize += uintptrSize
}
- lock(&cbs.lock)
- defer unlock(&cbs.lock)
+ lock(&cbs.lock) // We don't unlock this in a defer because this is used from the system stack.
n := cbs.n
for i := 0; i < n; i++ {
if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack {
- return callbackasmAddr(i)
+ r := callbackasmAddr(i)
+ unlock(&cbs.lock)
+ return r
}
}
if n >= cb_max {
+ unlock(&cbs.lock)
throw("too many callback functions")
}
@@ -99,7 +101,9 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
cbs.ctxt[n] = c
cbs.n++
- return callbackasmAddr(n)
+ r := callbackasmAddr(n)
+ unlock(&cbs.lock)
+ return r
}
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800