Skip to content

Commit 09f940b

Browse files
committed
internal/cgohandler: Separate from xpc package
Signed-off-by: Norio Nomura <norio.nomura@gmail.com>
1 parent 3a32863 commit 09f940b

File tree

6 files changed

+63
-59
lines changed

6 files changed

+63
-59
lines changed

internal/cgohandler/cgohandler.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package cgohandler
2+
3+
/*
4+
# include <stdint.h>
5+
*/
6+
import "C"
7+
import (
8+
"runtime"
9+
"runtime/cgo"
10+
)
11+
12+
// Handler holds a cgo.Handle for an Object.
13+
// It provides methods to hold and release the handle.
14+
// handle will released when Handler is cleaned up.
15+
type Handler struct {
16+
handle cgo.Handle
17+
}
18+
19+
// releaseOnCleanup registers a cleanup function to delete the cgo.Handle when cleaned up.
20+
func (h *Handler) releaseOnCleanup() {
21+
runtime.AddCleanup(h, func(h cgo.Handle) {
22+
h.Delete()
23+
}, h.handle)
24+
}
25+
26+
// New creates a new [Handler] and holds the given value.
27+
func New(v any) (*Handler, uintptr) {
28+
if v == nil {
29+
return nil, 0
30+
}
31+
h := &Handler{cgo.NewHandle(v)}
32+
h.releaseOnCleanup()
33+
return h, uintptr(h.handle)
34+
}
35+
36+
// Unwrap unwraps the cgo.Handle from the given uintptr and returns the associated value.
37+
// It does NOT delete the handle; it expects the handle to be managed by [Handler] or caller.
38+
func Unwrap[T any](handle uintptr) T {
39+
if handle == 0 {
40+
var zero T
41+
return zero
42+
}
43+
return cgo.Handle(handle).Value().(T)
44+
}

xpc/array.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212
"unsafe"
1313

14+
"github.com/Code-Hex/vz/v3/internal/cgohandler"
1415
"github.com/Code-Hex/vz/v3/internal/objc"
1516
)
1617

@@ -74,7 +75,7 @@ type ArrayApplier func(uint64, Object) bool
7475
//
7576
//export callArrayApplier
7677
func callArrayApplier(cgoApplier uintptr, index C.size_t, cgoValue uintptr) C.bool {
77-
applier := unwrapHandler[ArrayApplier](cgoApplier)
78+
applier := cgohandler.Unwrap[ArrayApplier](cgoApplier)
7879
value := unwrapObject[Object](cgoValue)
7980
result := applier(uint64(index), value)
8081
return C.bool(result)

xpc/cgo_handle.go

Lines changed: 0 additions & 44 deletions
This file was deleted.

xpc/dictionary.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313
"unsafe"
1414

15+
"github.com/Code-Hex/vz/v3/internal/cgohandler"
1516
"github.com/Code-Hex/vz/v3/internal/objc"
1617
)
1718

@@ -103,7 +104,7 @@ type DictionaryApplier func(string, Object) bool
103104
//
104105
//export callDictionaryApplier
105106
func callDictionaryApplier(cgoApplier uintptr, cKey *C.char, cgoValue uintptr) C.bool {
106-
applier := unwrapHandler[DictionaryApplier](cgoApplier)
107+
applier := cgohandler.Unwrap[DictionaryApplier](cgoApplier)
107108
return C.bool(applier(C.GoString(cKey), unwrapObject[Object](cgoValue)))
108109
}
109110

xpc/listener.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ import "C"
99
import (
1010
"unsafe"
1111

12+
"github.com/Code-Hex/vz/v3/internal/cgohandler"
1213
"github.com/Code-Hex/vz/v3/internal/objc"
1314
)
1415

1516
// Listener represents an XPC listener. (macOS 14.0+)
1617
// - https://developer.apple.com/documentation/xpc/xpc_listener_t?language=objc
1718
type Listener struct {
1819
*xpcObject
19-
sessionHandler *cgoHandler
20+
sessionHandler *cgohandler.Handler
2021
}
2122

2223
// SessionHandler is a function that handles incoming sessions.
@@ -47,9 +48,9 @@ func NewListener(service string, handler SessionHandler, options ...ListenerOpti
4748
// For example, vmnet_network_create fails when using a concurrent queue.
4849
q := C.dispatchQueueCreateSerial(cname)
4950
defer C.dispatchRelease(q)
50-
cgoHandler, p := newCgoHandler(handler)
51+
cgoHandler, p := cgohandler.New(handler)
5152
var err_out unsafe.Pointer
52-
ptr := C.xpcListenerCreate(cname, q, C.XPC_LISTENER_CREATE_INACTIVE, p, &err_out)
53+
ptr := C.xpcListenerCreate(cname, q, C.XPC_LISTENER_CREATE_INACTIVE, C.uintptr_t(p), &err_out)
5354
if err_out != nil {
5455
return nil, newRichError(err_out)
5556
}
@@ -67,7 +68,7 @@ func NewListener(service string, handler SessionHandler, options ...ListenerOpti
6768
//
6869
//export callSessionHandler
6970
func callSessionHandler(cgoSessionHandler, cgoSession uintptr) {
70-
handler := unwrapHandler[SessionHandler](cgoSessionHandler)
71+
handler := cgohandler.Unwrap[SessionHandler](cgoSessionHandler)
7172
session := unwrapObject[*Session](cgoSession)
7273
handler(session)
7374
}

xpc/session.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"runtime/cgo"
1212
"unsafe"
1313

14+
"github.com/Code-Hex/vz/v3/internal/cgohandler"
1415
"github.com/Code-Hex/vz/v3/internal/objc"
1516
)
1617

@@ -20,8 +21,8 @@ import (
2021
type Session struct {
2122
// Exported for use in other packages since unimplemented XPC API may require direct access to xpc_session_t.
2223
*xpcObject
23-
cancellationHandler *cgoHandler
24-
incomingMessageHandler *cgoHandler
24+
cancellationHandler *cgohandler.Handler
25+
incomingMessageHandler *cgohandler.Handler
2526
}
2627

2728
var _ Object = &Session{}
@@ -128,16 +129,16 @@ func (s *Session) activate() error {
128129
//
129130
//export callMessageHandler
130131
func callMessageHandler(cgoMessageHandler, cgoMessage uintptr) (reply unsafe.Pointer) {
131-
handler := unwrapHandler[MessageHandler](cgoMessageHandler)
132+
handler := cgohandler.Unwrap[MessageHandler](cgoMessageHandler)
132133
message := unwrapObject[*Dictionary](cgoMessage)
133134
return objc.Ptr(handler(message))
134135
}
135136

136137
// setIncomingMessageHandler sets the [MessageHandler] for the inactive [Session]. (macOS 13.0+)
137138
// - https://developer.apple.com/documentation/xpc/xpc_session_set_incoming_message_handler
138139
func (s *Session) setIncomingMessageHandler(handler MessageHandler) {
139-
cgoHandler, p := newCgoHandler(handler)
140-
C.xpcSessionSetIncomingMessageHandler(objc.Ptr(s), p)
140+
cgoHandler, p := cgohandler.New(handler)
141+
C.xpcSessionSetIncomingMessageHandler(objc.Ptr(s), C.uintptr_t(p))
141142
// Store the handler after setting it to avoid premature garbage collection of the previous handler.
142143
s.incomingMessageHandler = cgoHandler
143144
}
@@ -152,7 +153,7 @@ func (s *Session) Cancel() {
152153
//
153154
//export callCancelHandler
154155
func callCancelHandler(cgoCancelHandler, cgoErr uintptr) {
155-
handler := unwrapHandler[CancellationHandler](cgoCancelHandler)
156+
handler := cgohandler.Unwrap[CancellationHandler](cgoCancelHandler)
156157
err := unwrapObject[*RichError](cgoErr)
157158
handler(err)
158159
}
@@ -161,13 +162,13 @@ func callCancelHandler(cgoCancelHandler, cgoErr uintptr) {
161162
// The handler will call [Session.handleCancellation] after executing the provided handler.
162163
// - https://developer.apple.com/documentation/xpc/xpc_session_set_cancel_handler
163164
func (s *Session) setCancellationHandler(handler CancellationHandler) {
164-
cgoHandler, p := newCgoHandler((CancellationHandler)(func(err *RichError) {
165+
cgoHandler, p := cgohandler.New((CancellationHandler)(func(err *RichError) {
165166
if handler != nil {
166167
handler(err)
167168
}
168169
s.handleCancellation(err)
169170
}))
170-
C.xpcSessionSetCancelHandler(objc.Ptr(s), p)
171+
C.xpcSessionSetCancelHandler(objc.Ptr(s), C.uintptr_t(p))
171172
// Store the handler after setting it to avoid premature garbage collection of the previous handler.
172173
s.cancellationHandler = cgoHandler
173174
}
@@ -182,7 +183,7 @@ type ReplyHandler func(*Dictionary, *RichError)
182183
//
183184
//export callReplyHandler
184185
func callReplyHandler(cgoReplyHandler uintptr, cgoReply, cgoError uintptr) {
185-
handler := unwrapHandler[ReplyHandler](cgoReplyHandler)
186+
handler := cgohandler.Unwrap[ReplyHandler](cgoReplyHandler)
186187
reply := unwrapObject[*Dictionary](uintptr(cgoReply))
187188
err := unwrapObject[*RichError](cgoError)
188189
handler(reply, err)

0 commit comments

Comments
 (0)