Skip to content

Commit 5845fbb

Browse files
committed
Fix usage of PowerUnregisterSuspendResumeNotification
1 parent 7beca62 commit 5845fbb

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

common/winpowrprof/event_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,28 @@ import (
44
"runtime"
55
"testing"
66

7+
F "github.com/sagernet/sing/common/format"
8+
79
"github.com/stretchr/testify/require"
810
)
911

1012
func TestPowerEvents(t *testing.T) {
1113
if runtime.GOOS != "windows" {
1214
t.SkipNow()
1315
}
16+
t.Parallel()
1417
listener, err := NewEventListener(func(event int) {})
1518
require.NoError(t, err)
1619
require.NotNil(t, listener)
1720
require.NoError(t, listener.Start())
1821
require.NoError(t, listener.Close())
1922
}
23+
24+
func TestBatchPowerEvents(t *testing.T) {
25+
if runtime.GOOS != "windows" {
26+
t.SkipNow()
27+
}
28+
for i := 0; i < 100; i++ {
29+
t.Run(F.ToString(i), TestPowerEvents)
30+
}
31+
}

common/winpowrprof/event_windows.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"unsafe"
88

99
"github.com/sagernet/sing/common"
10+
E "github.com/sagernet/sing/common/exceptions"
1011

1112
"golang.org/x/sys/windows"
1213
)
@@ -42,6 +43,7 @@ var suspendResumeNotificationCallback = common.OnceValue(func() uintptr {
4243
})
4344

4445
type powerEventListener struct {
46+
pinner myPinner
4547
callback EventCallback
4648
handle uintptr
4749
}
@@ -61,6 +63,7 @@ func NewEventListener(callback EventCallback) (EventListener, error) {
6163
}
6264

6365
func (l *powerEventListener) Start() error {
66+
l.pinner.Pin(&l.callback)
6467
type DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
6568
callback uintptr
6669
context unsafe.Pointer
@@ -77,15 +80,25 @@ func (l *powerEventListener) Start() error {
7780
uintptr(unsafe.Pointer(&l.handle)),
7881
)
7982
if errno != 0 {
83+
l.pinner.Unpin()
8084
return errno
8185
}
86+
if l.handle == 0 {
87+
l.pinner.Unpin()
88+
return E.New("PowerRegisterSuspendResumeNotification returned success but handle is zero")
89+
}
8290
return nil
8391
}
8492

8593
func (l *powerEventListener) Close() error {
86-
_, _, errno := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), uintptr(unsafe.Pointer(&l.handle)))
87-
if errno != 0 {
88-
return errno
94+
if l.handle == 0 {
95+
return nil
96+
}
97+
defer l.pinner.Unpin()
98+
r0, _, _ := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), l.handle)
99+
if r0 != windows.NO_ERROR {
100+
return syscall.Errno(r0)
89101
}
102+
l.handle = 0
90103
return nil
91104
}

common/winpowrprof/pinner.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build go1.21
2+
3+
package winpowrprof
4+
5+
import "runtime"
6+
7+
type myPinner = runtime.Pinner

common/winpowrprof/pinner_compat.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build !go1.21
2+
3+
package winpowrprof
4+
5+
type myPinner struct{}
6+
7+
func (p *myPinner) Pin(pointer any) {
8+
}
9+
10+
func (p *myPinner) Unpin() {
11+
}

0 commit comments

Comments
 (0)