Skip to content

Commit 9332b56

Browse files
committed
Cleanup deregisteredFDs
1 parent 445d1d3 commit 9332b56

2 files changed

Lines changed: 13 additions & 15 deletions

File tree

Sources/NIOPosix/SelectorGeneric.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,14 @@ internal class Selector<R: Registration> {
215215
#elseif os(Windows)
216216
@usableFromInline
217217
typealias EventType = WinSDK.pollfd
218+
/// Array of poll file descriptors monitored by WSAPoll. The first entry is always the wakeup socket.
218219
@usableFromInline
219220
var pollFDs = [pollfd]()
221+
/// Tracks indexes of file descriptors pending removal from `pollFDs`. We defer removal until after
222+
/// processing all events in `whenReady0` to avoid invalidating indexes during iteration. Stored as
223+
/// indexes rather than a parallel boolean array for O(1) lookup during cleanup.
220224
@usableFromInline
221-
var deregisteredFDs = [Bool]()
225+
var deregisteredFDs = Set<Int>()
222226
/// The read end of the wakeup socket pair. This is monitored in WSAPoll to allow waking up the event loop.
223227
@usableFromInline
224228
var wakeupReadSocket: NIOBSDSocket.Handle = NIOBSDSocket.invalidHandle

Sources/NIOPosix/SelectorWSAPoll.swift

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ extension Selector: _SelectorBackendProtocol {
8080
// Add the read end to pollFDs so WSAPoll will wake up when data is written to the write end
8181
let wakeupPollFD = pollfd(fd: UInt64(readSocket), events: Int16(WinSDK.POLLRDNORM), revents: 0)
8282
self.pollFDs.append(wakeupPollFD)
83-
self.deregisteredFDs.append(false)
8483

8584
self.lifecycleState = .open
8685
}
@@ -254,18 +253,14 @@ extension Selector: _SelectorBackendProtocol {
254253
try body((SelectorEvent(io: selectorEvent, registration: registration)))
255254
}
256255

257-
// now clean up any deregistered fds
258-
// In reverse order so we don't have to copy elements out of the array
259-
// If we do in in normal order, we'll have to shift all elements after the removed one
260-
for i in self.deregisteredFDs.indices.reversed() {
261-
if self.deregisteredFDs[i] {
262-
// remove this one
263-
let fd = self.pollFDs[i].fd
264-
self.pollFDs.remove(at: i)
265-
self.deregisteredFDs.remove(at: i)
266-
self.registrations.removeValue(forKey: Int(fd))
267-
}
256+
// Clean up any deregistered fds. Process in descending order so that removing
257+
// elements doesn't invalidate the indexes of elements we still need to remove.
258+
for i in self.deregisteredFDs.sorted(by: >) {
259+
let fd = self.pollFDs[i].fd
260+
self.pollFDs.remove(at: i)
261+
self.registrations.removeValue(forKey: Int(fd))
268262
}
263+
self.deregisteredFDs.removeAll(keepingCapacity: true)
269264
} else if result == 0 {
270265
// nothing has happened
271266
} else if result == WinSDK.SOCKET_ERROR {
@@ -283,7 +278,6 @@ extension Selector: _SelectorBackendProtocol {
283278
// that will allow O(1) access here.
284279
let poll = pollfd(fd: UInt64(fileDescriptor), events: interested.wsaPollEvent, revents: 0)
285280
self.pollFDs.append(poll)
286-
self.deregisteredFDs.append(false)
287281
}
288282

289283
func reregister0(
@@ -305,7 +299,7 @@ extension Selector: _SelectorBackendProtocol {
305299
registrationID: SelectorRegistrationID
306300
) throws {
307301
if let index = self.pollFDs.firstIndex(where: { $0.fd == UInt64(fileDescriptor) }) {
308-
self.deregisteredFDs[index] = true
302+
self.deregisteredFDs.insert(index)
309303
}
310304
}
311305

0 commit comments

Comments
 (0)