Skip to content

Commit

Permalink
Fix usage of PowerUnregisterSuspendResumeNotification
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Aug 8, 2024
1 parent 7beca62 commit 478987d
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 3 deletions.
12 changes: 12 additions & 0 deletions common/winpowrprof/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,28 @@ import (
"runtime"
"testing"

F "github.com/sagernet/sing/common/format"

"github.com/stretchr/testify/require"
)

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)
require.NoError(t, listener.Start())
require.NoError(t, listener.Close())
}

func TestBatchPowerEvents(t *testing.T) {
if runtime.GOOS != "windows" {
t.SkipNow()
}
for i := 0; i < 100; i++ {
t.Run(F.ToString(i), TestPowerEvents)
}
}
19 changes: 16 additions & 3 deletions common/winpowrprof/event_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"unsafe"

"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"

"golang.org/x/sys/windows"
)
Expand Down Expand Up @@ -42,6 +43,7 @@ var suspendResumeNotificationCallback = common.OnceValue(func() uintptr {
})

type powerEventListener struct {
pinner myPinner
callback EventCallback
handle uintptr
}
Expand All @@ -61,6 +63,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
Expand All @@ -77,15 +80,25 @@ func (l *powerEventListener) Start() error {
uintptr(unsafe.Pointer(&l.handle)),
)
if errno != 0 {
l.pinner.Unpin()
return errno
}
if l.handle == 0 {
l.pinner.Unpin()
return E.New("PowerRegisterSuspendResumeNotification returned success but handle is zero")
}
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
}
7 changes: 7 additions & 0 deletions common/winpowrprof/pinner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build go1.21

package winpowrprof

import "runtime"

type myPinner = runtime.Pinner
11 changes: 11 additions & 0 deletions common/winpowrprof/pinner_compat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build !go1.21

package winpowrprof

type myPinner struct{}

func (p *myPinner) Pin(pointer any) {
}

func (p *myPinner) Unpin() {
}

0 comments on commit 478987d

Please sign in to comment.