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