@@ -138,54 +138,77 @@ internal func _blockingGetSubmissionEntry(ring: inout SQRing, submissionQueueEnt
138138 io_uring_sqe
139139> {
140140 while true {
141- if let entry = _getSubmissionEntry ( ring: & ring, submissionQueueEntries: submissionQueueEntries) {
141+ if let entry = _getSubmissionEntry (
142+ ring: & ring,
143+ submissionQueueEntries: submissionQueueEntries
144+ ) {
142145 return entry
143146 }
144147 // TODO: actually block here instead of spinning
145148 }
146149
147150}
148151
149- internal func _submitRequests( ring: inout SQRing , ringDescriptor: Int32 ) {
150- let flushedEvents = _flushQueue ( ring: & ring)
151-
152- // Ring always needs enter right now;
152+ //TODO: omitting signal mask for now
153+ //Tell the kernel that we've submitted requests and/or are waiting for completions
154+ internal func _enter(
155+ ringDescriptor: Int32 ,
156+ numEvents: UInt32 ,
157+ minCompletions: UInt32 ,
158+ flags: UInt32
159+ ) throws -> Int32 {
160+ // Ring always needs enter right now;
153161 // TODO: support SQPOLL here
154162 while true {
155- let ret = io_uring_enter ( ringDescriptor, flushedEvents , 0 , 0 , nil )
163+ let ret = io_uring_enter ( ringDescriptor, numEvents , minCompletions , flags , nil )
156164 // error handling:
157165 // EAGAIN / EINTR (try again),
158166 // EBADF / EBADFD / EOPNOTSUPP / ENXIO
159167 // (failure in ring lifetime management, fatal),
160168 // EINVAL (bad constant flag?, fatal),
161169 // EFAULT (bad address for argument from library, fatal)
162170 if ret == - EAGAIN || ret == - EINTR {
171+ //TODO: should we wait a bit on AGAIN?
163172 continue
164173 } else if ret < 0 {
165174 fatalError (
166175 " fatal error in submitting requests: " + Errno( rawValue: - ret) . debugDescription
167176 )
168177 } else {
169- break
178+ return ret
170179 }
171180 }
172181}
173182
183+ internal func _submitRequests( ring: inout SQRing , ringDescriptor: Int32 ) throws {
184+ let flushedEvents = _flushQueue ( ring: & ring)
185+ _ = try _enter ( ringDescriptor: ringDescriptor, numEvents: flushedEvents, minCompletions: 0 , flags: 0 )
186+ }
187+
188+ internal func _getUnconsumedSubmissionCount( ring: inout SQRing ) -> UInt32 {
189+ return ring. userTail - ring. kernelHead. pointee. load ( ordering: . acquiring)
190+ }
191+
192+ internal func _getUnconsumedCompletionCount( ring: inout CQRing ) -> UInt32 {
193+ return ring. kernelTail. pointee. load ( ordering: . acquiring) - ring. kernelHead. pointee. load ( ordering: . acquiring)
194+ }
195+
196+ //TODO: pretty sure this is supposed to do more than it does
174197internal func _flushQueue( ring: inout SQRing ) -> UInt32 {
175198 ring. kernelTail. pointee. store (
176- ring. userTail, ordering: . relaxed
199+ ring. userTail, ordering: . releasing
177200 )
178- return ring . userTail - ring . kernelHead . pointee . load ( ordering : . relaxed )
201+ return _getUnconsumedSubmissionCount ( ring : & ring )
179202}
180203
181204@usableFromInline @inline ( __always)
182205internal func _getSubmissionEntry( ring: inout SQRing , submissionQueueEntries: UnsafeMutableBufferPointer < io_uring_sqe > ) -> UnsafeMutablePointer <
183206 io_uring_sqe
184207> ? {
185- let next = ring. userTail + 1
208+ let next = ring. userTail & + 1 //this is expected to wrap
186209
187210 // FEAT: smp load when SQPOLL in use (not in MVP)
188- let kernelHead = ring. kernelHead. pointee. load ( ordering: . relaxed )
211+ let kernelHead = ring. kernelHead. pointee. load ( ordering: . acquiring )
189212
190213 // FEAT: 128-bit event support (not in MVP)
191214 if next - kernelHead <= ring. array. count {
@@ -383,18 +406,45 @@ public struct IORing: @unchecked Sendable, ~Copyable {
383406
384407 func _tryConsumeCompletion( ring: inout CQRing ) -> IOCompletion ? {
385408 let tail = ring. kernelTail. pointee. load ( ordering: . acquiring)
386- let head = ring. kernelHead. pointee. load ( ordering: . relaxed )
409+ let head = ring. kernelHead. pointee. load ( ordering: . acquiring )
387410
388411 if tail != head {
389412 // 32 byte copy - oh well
390413 let res = ring. cqes [ Int ( head & ring. ringMask) ]
391- ring. kernelHead. pointee. store ( head + 1 , ordering: . relaxed )
414+ ring. kernelHead. pointee. store ( head & + 1 , ordering: . releasing )
392415 return IOCompletion ( rawValue: res)
393416 }
394417
395418 return nil
396419 }
397420
421+ internal func handleRegistrationResult( _ result: Int32 ) throws {
422+ //TODO: error handling
423+ }
424+
425+ public mutating func registerEventFD( ring: inout IORing , _ descriptor: FileDescriptor ) throws {
426+ var rawfd = descriptor. rawValue
427+ let result = withUnsafePointer ( to: & rawfd) { fdptr in
428+ return io_uring_register (
429+ ring. ringDescriptor,
430+ IORING_REGISTER_EVENTFD,
431+ UnsafeMutableRawPointer ( mutating: fdptr) ,
432+ 1
433+ )
434+ }
435+ try handleRegistrationResult ( result)
436+ }
437+
438+ public mutating func unregisterEventFD( ring: inout IORing ) throws {
439+ let result = io_uring_register (
440+ ring. ringDescriptor,
441+ IORING_UNREGISTER_EVENTFD,
442+ nil ,
443+ 0
444+ )
445+ try handleRegistrationResult ( result)
446+ }
447+
398448 public mutating func registerFiles( count: UInt32 ) {
399449 guard self . registeredFiles == nil else { fatalError ( ) }
400450 let fileBuf = UnsafeMutableBufferPointer< UInt32> . allocate( capacity: Int ( count) )
@@ -445,9 +495,9 @@ public struct IORing: @unchecked Sendable, ~Copyable {
445495 fatalError ( " failed to unregister buffers: TODO " )
446496 }
447497
448- public func submitRequests( ) {
449- submissionMutex. withLock { ring in
450- _submitRequests ( ring: & ring, ringDescriptor: ringDescriptor)
498+ public func submitRequests( ) throws {
499+ try submissionMutex. withLock { ring in
500+ try _submitRequests ( ring: & ring, ringDescriptor: ringDescriptor)
451501 }
452502 }
453503
0 commit comments