]> granicus.if.org Git - python/commit
asyncio, Tulip issue 205: Fix a race condition in BaseSelectorEventLoop.sock_connect()
authorVictor Stinner <victor.stinner@gmail.com>
Sun, 31 Aug 2014 13:07:57 +0000 (15:07 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Sun, 31 Aug 2014 13:07:57 +0000 (15:07 +0200)
commitd5aeccf9767c1619faa29e8ed61c93bde7bc5e3f
tree1a9ba0e09eef02ec84c868d0933c08359778d39d
parent41f3c3f226f167be40ce22ea21f76b30269f139d
asyncio, Tulip issue 205: Fix a race condition in BaseSelectorEventLoop.sock_connect()

There is a race condition in create_connection() used with wait_for() to have a
timeout. sock_connect() registers the file descriptor of the socket to be
notified of write event (if connect() raises BlockingIOError). When
create_connection() is cancelled with a TimeoutError, sock_connect() coroutine
gets the exception, but it doesn't unregister the file descriptor for write
event. create_connection() gets the TimeoutError and closes the socket.

If you call again create_connection(), the new socket will likely gets the same
file descriptor, which is still registered in the selector. When sock_connect()
calls add_writer(), it tries to modify the entry instead of creating a new one.

This issue was originally reported in the Trollius project, but the bug comes
from Tulip in fact (Trollius is based on Tulip):
https://bitbucket.org/enovance/trollius/issue/15/after-timeouterror-on-wait_for

This change fixes the race condition. It also makes sock_connect() more
reliable (and portable) is sock.connect() raises an InterruptedError.
Lib/asyncio/selector_events.py
Lib/test/test_asyncio/test_selector_events.py