@@ -49,6 +49,7 @@ const (
49
49
//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
50
50
//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
51
51
//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
52
+ //go:cgo_import_dynamic runtime._WaitForMultipleObjects WaitForMultipleObjects%4 "kernel32.dll"
52
53
//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
53
54
//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
54
55
96
97
_VirtualFree ,
97
98
_VirtualQuery ,
98
99
_WaitForSingleObject ,
100
+ _WaitForMultipleObjects ,
99
101
_WriteConsoleW ,
100
102
_WriteFile ,
101
103
_ stdFunction
@@ -139,7 +141,8 @@ func tstart_stdcall(newm *m)
139
141
func ctrlhandler ()
140
142
141
143
type mOS struct {
142
- waitsema uintptr // semaphore for parking on locks
144
+ waitsema uintptr // semaphore for parking on locks
145
+ resumesema uintptr // semaphore to indicate suspend/resume
143
146
}
144
147
145
148
//go:linkname os_sigpipe os.sigpipe
@@ -258,6 +261,40 @@ func loadOptionalSyscalls() {
258
261
}
259
262
}
260
263
264
+ func monitorSuspendResume () {
265
+ const _DEVICE_NOTIFY_CALLBACK = 2
266
+ type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
267
+ callback uintptr
268
+ context uintptr
269
+ }
270
+
271
+ powrprof := windowsLoadSystemLib ([]byte ("powrprof.dll\000 " ))
272
+ if powrprof == 0 {
273
+ return // Running on Windows 7, where we don't need it anyway.
274
+ }
275
+ powerRegisterSuspendResumeNotification := windowsFindfunc (powrprof , []byte ("PowerRegisterSuspendResumeNotification\000 " ))
276
+ if powerRegisterSuspendResumeNotification == nil {
277
+ return // Running on Windows 7, where we don't need it anyway.
278
+ }
279
+ var fn interface {} = func (context uintptr , changeType uint32 , setting uintptr ) uintptr {
280
+ for mp := (* m )(atomic .Loadp (unsafe .Pointer (& allm ))); mp != nil ; mp = mp .alllink {
281
+ if mp .resumesema != 0 {
282
+ stdcall1 (_SetEvent , mp .resumesema )
283
+ }
284
+ }
285
+ return 0
286
+ }
287
+ params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
288
+ callback : compileCallback (* efaceOf (& fn ), true ),
289
+ }
290
+ handle := uintptr (0 )
291
+ if stdcall3 (powerRegisterSuspendResumeNotification , _DEVICE_NOTIFY_CALLBACK ,
292
+ uintptr (unsafe .Pointer (& params )),
293
+ uintptr (unsafe .Pointer (& handle ))) != 0 {
294
+ throw ("PowerRegisterSuspendResumeNotification failure" )
295
+ }
296
+ }
297
+
261
298
//go:nosplit
262
299
func getLoadLibrary () uintptr {
263
300
return uintptr (unsafe .Pointer (_LoadLibraryW ))
@@ -488,6 +525,10 @@ func goenvs() {
488
525
}
489
526
490
527
stdcall1 (_FreeEnvironmentStringsW , uintptr (strings ))
528
+
529
+ // We call this all the way here, late in init, so that malloc works
530
+ // for the callback function this generates.
531
+ monitorSuspendResume ()
491
532
}
492
533
493
534
// exiting is set to non-zero when the process is exiting.
@@ -606,19 +647,32 @@ func semasleep(ns int64) int32 {
606
647
_WAIT_FAILED = 0xFFFFFFFF
607
648
)
608
649
609
- // store ms in ns to save stack space
650
+ var result uintptr
610
651
if ns < 0 {
611
- ns = _INFINITE
652
+ result = stdcall2 ( _WaitForSingleObject , getg (). m . waitsema , uintptr ( _INFINITE ))
612
653
} else {
613
- ns = int64 (timediv (ns , 1000000 , nil ))
614
- if ns == 0 {
615
- ns = 1
654
+ start := nanotime ()
655
+ elapsed := int64 (0 )
656
+ for {
657
+ ms := int64 (timediv (ns - elapsed , 1000000 , nil ))
658
+ if ms == 0 {
659
+ ms = 1
660
+ }
661
+ result = stdcall4 (_WaitForMultipleObjects , 2 ,
662
+ uintptr (unsafe .Pointer (& [2 ]uintptr {getg ().m .waitsema , getg ().m .resumesema })),
663
+ 0 , uintptr (ms ))
664
+ if result != _WAIT_OBJECT_0 + 1 {
665
+ // Not a suspend/resume event
666
+ break
667
+ }
668
+ elapsed = nanotime () - start
669
+ if elapsed >= ns {
670
+ return - 1
671
+ }
616
672
}
617
673
}
618
-
619
- result := stdcall2 (_WaitForSingleObject , getg ().m .waitsema , uintptr (ns ))
620
674
switch result {
621
- case _WAIT_OBJECT_0 : //signaled
675
+ case _WAIT_OBJECT_0 : // Signaled
622
676
return 0
623
677
624
678
case _WAIT_TIMEOUT :
@@ -667,6 +721,15 @@ func semacreate(mp *m) {
667
721
throw ("runtime.semacreate" )
668
722
})
669
723
}
724
+ mp .resumesema = stdcall4 (_CreateEventA , 0 , 0 , 0 , 0 )
725
+ if mp .resumesema == 0 {
726
+ systemstack (func () {
727
+ print ("runtime: createevent failed; errno=" , getlasterror (), "\n " )
728
+ throw ("runtime.semacreate" )
729
+ })
730
+ stdcall1 (_CloseHandle , mp .waitsema )
731
+ mp .waitsema = 0
732
+ }
670
733
}
671
734
672
735
// May run with m.p==nil, so write barriers are not allowed. This
0 commit comments