@@ -162,43 +162,50 @@ def _write_to_self(self):
162
162
exc_info = True )
163
163
164
164
def _start_serving (self , protocol_factory , sock ,
165
- sslcontext = None , server = None ):
165
+ sslcontext = None , server = None , backlog = 100 ):
166
166
self .add_reader (sock .fileno (), self ._accept_connection ,
167
- protocol_factory , sock , sslcontext , server )
167
+ protocol_factory , sock , sslcontext , server , backlog )
168
168
169
169
def _accept_connection (self , protocol_factory , sock ,
170
- sslcontext = None , server = None ):
171
- try :
172
- conn , addr = sock .accept ()
173
- if self ._debug :
174
- logger .debug ("%r got a new connection from %r: %r" ,
175
- server , addr , conn )
176
- conn .setblocking (False )
177
- except (BlockingIOError , InterruptedError , ConnectionAbortedError ):
178
- pass # False alarm.
179
- except OSError as exc :
180
- # There's nowhere to send the error, so just log it.
181
- if exc .errno in (errno .EMFILE , errno .ENFILE ,
182
- errno .ENOBUFS , errno .ENOMEM ):
183
- # Some platforms (e.g. Linux keep reporting the FD as
184
- # ready, so we remove the read handler temporarily.
185
- # We'll try again in a while.
186
- self .call_exception_handler ({
187
- 'message' : 'socket.accept() out of system resource' ,
188
- 'exception' : exc ,
189
- 'socket' : sock ,
190
- })
191
- self .remove_reader (sock .fileno ())
192
- self .call_later (constants .ACCEPT_RETRY_DELAY ,
193
- self ._start_serving ,
194
- protocol_factory , sock , sslcontext , server )
170
+ sslcontext = None , server = None , backlog = 100 ):
171
+ # This method is only called once for each event loop tick where the
172
+ # listening socket has triggered an EVENT_READ. There may be multiple
173
+ # connections waiting for an .accept() so it is called in a loop.
174
+ # See https://bugs.python.org/issue27906 for more details.
175
+ for _ in range (backlog ):
176
+ try :
177
+ conn , addr = sock .accept ()
178
+ if self ._debug :
179
+ logger .debug ("%r got a new connection from %r: %r" ,
180
+ server , addr , conn )
181
+ conn .setblocking (False )
182
+ except (BlockingIOError , InterruptedError , ConnectionAbortedError ):
183
+ # Early exit because the socket accept buffer is empty.
184
+ return None
185
+ except OSError as exc :
186
+ # There's nowhere to send the error, so just log it.
187
+ if exc .errno in (errno .EMFILE , errno .ENFILE ,
188
+ errno .ENOBUFS , errno .ENOMEM ):
189
+ # Some platforms (e.g. Linux keep reporting the FD as
190
+ # ready, so we remove the read handler temporarily.
191
+ # We'll try again in a while.
192
+ self .call_exception_handler ({
193
+ 'message' : 'socket.accept() out of system resource' ,
194
+ 'exception' : exc ,
195
+ 'socket' : sock ,
196
+ })
197
+ self .remove_reader (sock .fileno ())
198
+ self .call_later (constants .ACCEPT_RETRY_DELAY ,
199
+ self ._start_serving ,
200
+ protocol_factory , sock , sslcontext , server ,
201
+ backlog )
202
+ else :
203
+ raise # The event loop will catch, log and ignore it.
195
204
else :
196
- raise # The event loop will catch, log and ignore it.
197
- else :
198
- extra = {'peername' : addr }
199
- accept = self ._accept_connection2 (protocol_factory , conn , extra ,
200
- sslcontext , server )
201
- self .create_task (accept )
205
+ extra = {'peername' : addr }
206
+ accept = self ._accept_connection2 (protocol_factory , conn , extra ,
207
+ sslcontext , server )
208
+ self .create_task (accept )
202
209
203
210
@coroutine
204
211
def _accept_connection2 (self , protocol_factory , conn , extra ,
0 commit comments