@@ -13,37 +13,46 @@ import AndroidNDK
1313import CoreFoundation
1414import Dispatch
1515import SystemPackage
16+ import Socket
1617
1718@available ( macOS 13 . 0 , iOS 13 . 0 , * )
1819public extension Looper {
1920
2021 // Swift structured concurrency executor that enqueues jobs on an Android Looper.
2122 final class Executor : SerialExecutor , @unchecked Sendable {
2223
23- let eventFd : FileDescriptor
24+ #if os(Android)
25+ let eventFd : SocketDescriptor . Event
26+ #endif
2427 let looper : Looper
2528 let queue = LockedState ( initialState: [ UnownedJob] ( ) )
2629
2730 /// Initialize with Android Looper
2831 internal init ( looper: consuming Looper ) throws ( AndroidLooperError) {
32+ #if os(Android)
33+ let eventFd : SocketDescriptor . Event
2934 // open fd
30- let fd = eventfd ( 0 , EFD_CLOEXEC | EFD_NONBLOCK) // TODO: Move to System / Socket package
31- if fd < 0 {
32- throw . bionic( Errno ( rawValue: errno) )
35+ do {
36+ eventFd = try SocketDescriptor . Event ( 0 , flags: [ . closeOnExec, . nonBlocking] )
37+ }
38+ catch {
39+ throw . bionic( error)
3340 }
3441 // initialize
35- let eventFd = FileDescriptor ( rawValue: fd)
3642 self . eventFd = eventFd
43+ #endif
3744 self . looper = looper
3845 // Add fd to Looper
3946 try configureLooper ( )
4047 }
4148
4249 deinit {
50+ #if os(Android)
4351 if eventFd. rawValue != - 1 {
44- _ = try ? looper. remove ( fileDescriptor: eventFd)
52+ _ = try ? looper. remove ( fileDescriptor: . init ( rawValue : eventFd. rawValue ) )
4553 try ? eventFd. close ( )
4654 }
55+ #endif
4756 }
4857
4958 /// Enqueue a single job
@@ -66,36 +75,30 @@ internal extension Looper.Executor {
6675 func configureLooper( ) throws ( AndroidLooperError) {
6776 do {
6877 // add to looper
69- try looper. handle. add ( fileDescriptor: eventFd, callback: drainAExecutor, data: Unmanaged . passUnretained ( self ) . toOpaque ( ) ) . get ( )
78+ try looper. handle. add ( fileDescriptor: . init ( rawValue : eventFd. rawValue ) , callback: drainAExecutor, data: Unmanaged . passUnretained ( self ) . toOpaque ( ) ) . get ( )
7079 }
7180 catch {
81+ #if os(Android)
7282 try ? eventFd. close ( )
83+ #endif
7384 throw error
7485 }
7586 }
7687
7788 /// Read number of remaining events from eventFd
7889 var eventsRemaining : UInt64 {
7990 get throws {
80- var value = UInt64 ( 0 )
81- try withUnsafeMutableBytes ( of: & value) {
82- guard try eventFd. read ( into: $0) == MemoryLayout< UInt64> . size else {
83- throw Errno . invalidArgument
84- }
85- }
86-
87- return value
91+ #if os(Android)
92+ try eventFd. read ( ) . rawValue
93+ #endif
8894 }
8995 }
9096
9197 /// Increment number of remaining events on eventFd
9298 func signal( ) throws {
93- var value = UInt64 ( 1 )
94- try withUnsafeBytes ( of: & value) { ( pointer) throws -> ( ) in
95- guard try eventFd. write ( pointer) == MemoryLayout< UInt64> . size else {
96- throw Errno . outOfRange
97- }
98- }
99+ #if os(Android)
100+ try eventFd. write ( 1 )
101+ #endif
99102 }
100103
101104 /// Drain job queue
0 commit comments