@@ -50,7 +50,16 @@ In particular, it is in charge of:
5050public class IncomingSocketManager {
5151
5252 /// A mapping from socket file descriptor to IncomingSocketHandler
53- var socketHandlers = [ Int32: IncomingSocketHandler] ( )
53+ private var socketHandlers = [ Int32: IncomingSocketHandler] ( )
54+ private var shQueue = DispatchQueue ( label: " socketHandlers.queue " , attributes: . concurrent)
55+
56+ internal var socketHandlerCount : Int {
57+ var result : Int = 0
58+ shQueue. sync {
59+ result = socketHandlers. count
60+ }
61+ return result
62+ }
5463
5564 /// Interval at which to check for idle sockets to close
5665 let keepAliveIdleCheckingInterval : TimeInterval = 5.0
@@ -151,7 +160,9 @@ public class IncomingSocketManager {
151160 try socket. setBlocking ( mode: false )
152161
153162 let handler = IncomingSocketHandler ( socket: socket, using: processor)
154- socketHandlers [ socket. socketfd] = handler
163+ shQueue. sync ( flags: . barrier) {
164+ socketHandlers [ socket. socketfd] = handler
165+ }
155166
156167 #if !GCD_ASYNCH && os(Linux)
157168 var event = epoll_event ( )
@@ -205,21 +216,22 @@ public class IncomingSocketManager {
205216
206217 Log . error ( " Error occurred on a file descriptor of an epool wait " )
207218 } else {
208- if let handler = socketHandlers [ event. data. fd] {
209-
210- if ( event. events & EPOLLOUT . rawValue) != 0 {
211- handler. handleWrite ( )
212- }
213- if ( event. events & EPOLLIN . rawValue) != 0 {
214- let processed = handler. handleRead ( )
215- if !processed {
216- deferredHandlingNeeded = true
217- deferredHandlers [ event. data. fd] = handler
219+ shQueue. sync {
220+ if let handler = socketHandlers [ event. data. fd] {
221+ if ( event. events & EPOLLOUT . rawValue) != 0 {
222+ handler. handleWrite ( )
223+ }
224+ if ( event. events & EPOLLIN . rawValue) != 0 {
225+ let processed = handler. handleRead ( )
226+ if !processed {
227+ deferredHandlingNeeded = true
228+ deferredHandlers [ event. data. fd] = handler
229+ }
218230 }
219231 }
220- }
221- else {
222- Log . error ( " No handler for file descriptor \( event . data . fd ) " )
232+ else {
233+ Log . error ( " No handler for file descriptor \( event . data . fd ) " )
234+ }
223235 }
224236 }
225237 }
@@ -258,38 +270,32 @@ public class IncomingSocketManager {
258270 /// 2. Removing the reference to the IncomingHTTPSocketHandler
259271 /// 3. Have the IncomingHTTPSocketHandler close the socket
260272 ///
261- /// **Note:** In order to safely update the socketHandlers Dictionary the removal
262- /// of idle sockets is done in the thread that is accepting new incoming sockets
263- /// after a socket was accepted. Had this been done in a timer, there would be a
264- /// to have a lock around the access to the socketHandlers Dictionary. The other
265- /// idea here is that if sockets aren't coming in, it doesn't matter too much if
266- /// we leave a round some idle sockets.
267- ///
268273 /// - Parameter allSockets: flag indicating if the manager is shutting down, and we should cleanup all sockets, not just idle ones
269274 private func removeIdleSockets( removeAll: Bool = false ) {
270275 let now = Date ( )
271276 guard removeAll || now. timeIntervalSince ( keepAliveIdleLastTimeChecked) > keepAliveIdleCheckingInterval else { return }
272-
273- let maxInterval = now. timeIntervalSinceReferenceDate
274- for (fileDescriptor, handler) in socketHandlers {
275- if !removeAll && handler. processor != nil && ( handler. processor? . inProgress ?? false || maxInterval < handler. processor? . keepAliveUntil ?? maxInterval) {
276- continue
277- }
278- socketHandlers. removeValue ( forKey: fileDescriptor)
277+ shQueue . sync ( flags : . barrier ) {
278+ let maxInterval = now. timeIntervalSinceReferenceDate
279+ for (fileDescriptor, handler) in socketHandlers {
280+ if !removeAll && handler. processor != nil && ( handler. processor? . inProgress ?? false || maxInterval < handler. processor? . keepAliveUntil ?? maxInterval) {
281+ continue
282+ }
283+ socketHandlers. removeValue ( forKey: fileDescriptor)
279284
280- #if !GCD_ASYNCH && os(Linux)
281- let result = epoll_ctl ( epollDescriptor ( fd: fileDescriptor) , EPOLL_CTL_DEL, fileDescriptor, nil )
282- if result == - 1 {
283- if errno != EBADF && // Ignore EBADF error (bad file descriptor), probably got closed.
284- errno != ENOENT { // Ignore ENOENT error (No such file or directory), probably got closed.
285- Log . error ( " epoll_ctl failure. Error code= \( errno) . Reason= \( lastError ( ) ) " )
285+ #if !GCD_ASYNCH && os(Linux)
286+ let result = epoll_ctl ( epollDescriptor ( fd: fileDescriptor) , EPOLL_CTL_DEL, fileDescriptor, nil )
287+ if result == - 1 {
288+ if errno != EBADF && // Ignore EBADF error (bad file descriptor), probably got closed.
289+ errno != ENOENT { // Ignore ENOENT error (No such file or directory), probably got closed.
290+ Log . error ( " epoll_ctl failure. Error code= \( errno) . Reason= \( lastError ( ) ) " )
291+ }
286292 }
287- }
288- #endif
289-
290- handler. prepareToClose ( )
293+ #endif
294+
295+ handler. prepareToClose ( )
296+ }
297+ keepAliveIdleLastTimeChecked = Date ( )
291298 }
292- keepAliveIdleLastTimeChecked = Date ( )
293299 }
294300
295301 /// Private method to return the last error based on the value of errno.
0 commit comments