Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion FlyingSocks/Sources/Socket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ package extension Socket {
}
}

fileprivate func errnoSignalsDisconnected() -> Bool {
func errnoSignalsDisconnected() -> Bool {
#if canImport(WinSDK)
return errno == WSAENOTSOCK || errno == WSAENOTCONN || errno == WSAECONNRESET
#else
Expand Down
24 changes: 14 additions & 10 deletions FlyingSocks/Sources/SocketPool+ePoll.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,30 +97,34 @@ public struct ePoll: EventQueue {
}

public mutating func removeEvents(_ events: Socket.Events, for socket: Socket.FileDescriptor) throws {
var socketEvents = existing[socket] ?? []
for evt in events {
socketEvents.remove(evt)
}
try setEvents(socketEvents, for: socket)
// For edge-triggered epoll, don't remove events when continuations resume.
// Removing and re-adding events re-arms the edge trigger, causing busy loops.
// Keep events registered until socket is closed (kernel auto-removes closed fds).
// If events need to change, addEvents() will call setEvents() with EPOLL_CTL_MOD.
}

mutating func setEvents(_ events: Socket.Events, for socket: Socket.FileDescriptor) throws {
let existingEvents = existing[socket]
guard existingEvents != events else { return } // don't re-arm if events are unchanged

var event = CSystemLinux.epoll_event()
event.events = events.epollEvents.rawValue
event.data.fd = socket.rawValue

if existing[socket] != nil {
if existingEvents != nil {
if events.isEmpty {
guard epoll_ctl(file.rawValue, EPOLL_CTL_DEL, socket.rawValue, &event) != -1 else {
if epoll_ctl(file.rawValue, EPOLL_CTL_DEL, socket.rawValue, &event) == -1 {
if errnoSignalsDisconnected() { existing[socket] = nil }
throw SocketError.makeFailed("epoll_ctl EPOLL_CTL_DEL")
}
} else {
guard epoll_ctl(file.rawValue, EPOLL_CTL_MOD, socket.rawValue, &event) != -1 else {
if epoll_ctl(file.rawValue, EPOLL_CTL_MOD, socket.rawValue, &event) == -1 {
if errnoSignalsDisconnected() { existing[socket] = nil }
throw SocketError.makeFailed("epoll_ctl EPOLL_CTL_MOD")
}
}
} else if !events.isEmpty {
guard epoll_ctl(file.rawValue, EPOLL_CTL_ADD, socket.rawValue, &event) != -1 else {
if epoll_ctl(file.rawValue, EPOLL_CTL_ADD, socket.rawValue, &event) == -1 {
throw SocketError.makeFailed("epoll_ctl EPOLL_CTL_ADD")
}
}
Expand Down Expand Up @@ -242,7 +246,7 @@ private struct EPOLLEvents: OptionSet, Hashable {
private extension Socket.Events {

var epollEvents: EPOLLEvents {
reduce(EPOLLEvents()) { [$0, $1.epollEvent] }
reduce(EPOLLEvents()) { [$0, $1.epollEvent] }.union(.edgeTriggered)
}

static func make(from pollevents: EPOLLEvents) -> Socket.Events {
Expand Down
Loading