Skip to content

Commit 2546a17

Browse files
author
Guido van Rossum
committed
Important race condition fix for Tulip.
1 parent 559ae0f commit 2546a17

File tree

1 file changed

+18
-33
lines changed

1 file changed

+18
-33
lines changed

Lib/asyncio/selector_events.py

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ def __init__(self, loop, sock, protocol, extra, server=None):
344344
self._protocol = protocol
345345
self._server = server
346346
self._buffer = collections.deque()
347-
self._conn_lost = 0
347+
self._conn_lost = 0 # Set when call to connection_lost scheduled.
348348
self._closing = False # Set when close() called.
349349
if server is not None:
350350
server.attach(self)
@@ -356,27 +356,27 @@ def close(self):
356356
if self._closing:
357357
return
358358
self._closing = True
359-
self._conn_lost += 1
360359
self._loop.remove_reader(self._sock_fd)
361360
if not self._buffer:
361+
self._conn_lost += 1
362362
self._loop.call_soon(self._call_connection_lost, None)
363363

364364
def _fatal_error(self, exc):
365-
# should be called from exception handler only
366-
logger.exception('Fatal error for %s', self)
365+
# Should be called from exception handler only.
366+
if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
367+
logger.exception('Fatal error for %s', self)
367368
self._force_close(exc)
368369

369370
def _force_close(self, exc):
371+
if self._conn_lost:
372+
return
370373
if self._buffer:
371374
self._buffer.clear()
372375
self._loop.remove_writer(self._sock_fd)
373-
374-
if self._closing:
375-
return
376-
377-
self._closing = True
376+
if not self._closing:
377+
self._closing = True
378+
self._loop.remove_reader(self._sock_fd)
378379
self._conn_lost += 1
379-
self._loop.remove_reader(self._sock_fd)
380380
self._loop.call_soon(self._call_connection_lost, exc)
381381

382382
def _call_connection_lost(self, exc):
@@ -424,8 +424,6 @@ def _read_ready(self):
424424
data = self._sock.recv(self.max_size)
425425
except (BlockingIOError, InterruptedError):
426426
pass
427-
except ConnectionResetError as exc:
428-
self._force_close(exc)
429427
except Exception as exc:
430428
self._fatal_error(exc)
431429
else:
@@ -453,17 +451,15 @@ def write(self, data):
453451
try:
454452
n = self._sock.send(data)
455453
except (BlockingIOError, InterruptedError):
456-
n = 0
457-
except (BrokenPipeError, ConnectionResetError) as exc:
458-
self._force_close(exc)
459-
return
460-
except OSError as exc:
454+
pass
455+
except Exception as exc:
461456
self._fatal_error(exc)
462457
return
463458
else:
464459
data = data[n:]
465460
if not data:
466461
return
462+
467463
# Start async I/O.
468464
self._loop.add_writer(self._sock_fd, self._write_ready)
469465

@@ -478,9 +474,6 @@ def _write_ready(self):
478474
n = self._sock.send(data)
479475
except (BlockingIOError, InterruptedError):
480476
self._buffer.append(data)
481-
except (BrokenPipeError, ConnectionResetError) as exc:
482-
self._loop.remove_writer(self._sock_fd)
483-
self._force_close(exc)
484477
except Exception as exc:
485478
self._loop.remove_writer(self._sock_fd)
486479
self._fatal_error(exc)
@@ -493,7 +486,6 @@ def _write_ready(self):
493486
elif self._eof:
494487
self._sock.shutdown(socket.SHUT_WR)
495488
return
496-
497489
self._buffer.append(data) # Try again later.
498490

499491
def write_eof(self):
@@ -622,8 +614,6 @@ def _on_ready(self):
622614
except (BlockingIOError, InterruptedError,
623615
ssl.SSLWantReadError, ssl.SSLWantWriteError):
624616
pass
625-
except ConnectionResetError as exc:
626-
self._force_close(exc)
627617
except Exception as exc:
628618
self._fatal_error(exc)
629619
else:
@@ -644,10 +634,6 @@ def _on_ready(self):
644634
except (BlockingIOError, InterruptedError,
645635
ssl.SSLWantReadError, ssl.SSLWantWriteError):
646636
n = 0
647-
except (BrokenPipeError, ConnectionResetError) as exc:
648-
self._loop.remove_writer(self._sock_fd)
649-
self._force_close(exc)
650-
return
651637
except Exception as exc:
652638
self._loop.remove_writer(self._sock_fd)
653639
self._fatal_error(exc)
@@ -726,12 +712,12 @@ def sendto(self, data, addr=None):
726712
else:
727713
self._sock.sendto(data, addr)
728714
return
715+
except (BlockingIOError, InterruptedError):
716+
self._loop.add_writer(self._sock_fd, self._sendto_ready)
729717
except ConnectionRefusedError as exc:
730718
if self._address:
731719
self._fatal_error(exc)
732720
return
733-
except (BlockingIOError, InterruptedError):
734-
self._loop.add_writer(self._sock_fd, self._sendto_ready)
735721
except Exception as exc:
736722
self._fatal_error(exc)
737723
return
@@ -746,13 +732,13 @@ def _sendto_ready(self):
746732
self._sock.send(data)
747733
else:
748734
self._sock.sendto(data, addr)
735+
except (BlockingIOError, InterruptedError):
736+
self._buffer.appendleft((data, addr)) # Try again later.
737+
break
749738
except ConnectionRefusedError as exc:
750739
if self._address:
751740
self._fatal_error(exc)
752741
return
753-
except (BlockingIOError, InterruptedError):
754-
self._buffer.appendleft((data, addr)) # Try again later.
755-
break
756742
except Exception as exc:
757743
self._fatal_error(exc)
758744
return
@@ -765,5 +751,4 @@ def _sendto_ready(self):
765751
def _force_close(self, exc):
766752
if self._address and isinstance(exc, ConnectionRefusedError):
767753
self._protocol.connection_refused(exc)
768-
769754
super()._force_close(exc)

0 commit comments

Comments
 (0)