From 08e8c02fb1ed6530165f7d3d8cf6f22384be0a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 8 Aug 2024 13:14:58 +0800 Subject: [PATCH] Fix usage of `PowerUnregisterSuspendResumeNotification` --- common/winpowrprof/event_test.go | 1 + common/winpowrprof/event_windows.go | 14 +++++++++++--- common/winpowrprof/pinner.go | 7 +++++++ common/winpowrprof/pinner_compat.go | 11 +++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 common/winpowrprof/pinner.go create mode 100644 common/winpowrprof/pinner_compat.go diff --git a/common/winpowrprof/event_test.go b/common/winpowrprof/event_test.go index 1113fe3c..61555960 100644 --- a/common/winpowrprof/event_test.go +++ b/common/winpowrprof/event_test.go @@ -11,6 +11,7 @@ func TestPowerEvents(t *testing.T) { if runtime.GOOS != "windows" { t.SkipNow() } + t.Parallel() listener, err := NewEventListener(func(event int) {}) require.NoError(t, err) require.NotNil(t, listener) diff --git a/common/winpowrprof/event_windows.go b/common/winpowrprof/event_windows.go index 26c776d0..5619a0f7 100644 --- a/common/winpowrprof/event_windows.go +++ b/common/winpowrprof/event_windows.go @@ -42,6 +42,7 @@ var suspendResumeNotificationCallback = common.OnceValue(func() uintptr { }) type powerEventListener struct { + pinner myPinner callback EventCallback handle uintptr } @@ -61,6 +62,7 @@ func NewEventListener(callback EventCallback) (EventListener, error) { } func (l *powerEventListener) Start() error { + l.pinner.Pin(&l.callback) type DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct { callback uintptr context unsafe.Pointer @@ -77,15 +79,21 @@ func (l *powerEventListener) Start() error { uintptr(unsafe.Pointer(&l.handle)), ) if errno != 0 { + l.pinner.Unpin() return errno } return nil } func (l *powerEventListener) Close() error { - _, _, errno := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), uintptr(unsafe.Pointer(&l.handle))) - if errno != 0 { - return errno + if l.handle == 0 { + return nil + } + defer l.pinner.Unpin() + r0, _, _ := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), l.handle) + if r0 != windows.NO_ERROR { + return syscall.Errno(r0) } + l.handle = 0 return nil } diff --git a/common/winpowrprof/pinner.go b/common/winpowrprof/pinner.go new file mode 100644 index 00000000..f3cf1daa --- /dev/null +++ b/common/winpowrprof/pinner.go @@ -0,0 +1,7 @@ +//go:build go1.21 + +package winpowrprof + +import "runtime" + +type myPinner = runtime.Pinner diff --git a/common/winpowrprof/pinner_compat.go b/common/winpowrprof/pinner_compat.go new file mode 100644 index 00000000..c52fd9fc --- /dev/null +++ b/common/winpowrprof/pinner_compat.go @@ -0,0 +1,11 @@ +//go:build !go1.21 + +package winpowrprof + +type myPinner struct{} + +func (p *myPinner) Pin(pointer any) { +} + +func (p *myPinner) Unpin() { +}