New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PEP 475: handle EINTR in the socket module (connect) #67806
Comments
The PEP-475 has been accepted and is partialy implemented. The socket module is not fully patched to handle EINTR. For example, socket.socket.connect() doesn't handle EINTR yet. Attached patch fixes socket.connect() to handle EINTR. It should fix issue bpo-11266 and bpo-20611 in Python 3.5 (Python 2.7 and 3.4 will need to be patched to handle explicitly InterruptedError/OSError(EINTR) in Python). By the way, some socket functions handle EINTR but don't recompute the timeout yet. _PyTime_monotonic() should be used. |
If EINTR is received during connect, the socket is unusable, that's why i |
Can you elaborate? socket.connect() should be modified according to the PEP-475: What do you mean by "unusable"? Is it possible to retry connect()? Is it safe to call getsockopt(fd, SOL_SOCKET, SO_ERROR) until it returns EISCONN? For high-level functions for socket.create_connection(), how should we handle InterruptedError? See also this change in asyncio to handle InterruptedError in asyncio: |
About EINTR and connect(), I've found the following insightful page: Official POSIX wording is this: """If connect() is interrupted by a signal that is caught while blocked waiting to establish a connection, connect() shall fail and set errno to [EINTR], but the connection request shall not be aborted, and the connection shall be established asynchronously.""" |
connect_eintr.py: script calling socket.connect() in a loop and sending SIGARLM signal every millisecond. |
Oops, connect_eintr.py noticed me (thanks to my recent change of the issue bpo-23571 !) that connect_eintr.patch is wrong: socket.connect() returned None with an exception sent, send connect() was interrupted by SIGINT (CTRL+c). Fixed patch. |
This article contains a program connect_test.c to test how connect() behaves on EINTR. Since it's in the public domain, I attached a copy. The program contains the comment: "All systems function as expected when TEST_TWO is set." If TEST_TWO is defined, poll() is used to wait until the socket is writable, and then getsockopt(SO_ERROR) is used to check if the error is now zero, when connect() fails with EINTR. |
connect_eintr-3.patch: Different patch, don't retry connect() if it returns EINTR, but poll using poll/select. The patch changes also the asyncio module. |
I tested polling+getsockopt(SO_ERROR) with connect_test.c on Linux, it works: haypo@smithers$ gcc -D TEST_TWO=1 connect_test.c -o connect_test |
Could you regenerate your latest patch? Also, what's with the assert? |
New changeset f841d3bc30ee by Victor Stinner in branch 'default': |
test_selectors.patch: Enhance test_selector to test the two kinds of signal handlers: one raises an exception, the other one doesn't. I wait until kqueue & devpoll retry on EINTR to push test_selectors.patch. |
New changeset e8246baad0f6 by Victor Stinner in branch 'default': New changeset fa5542660b17 by Victor Stinner in branch 'default': New changeset c027d6468667 by Victor Stinner in branch 'default': |
New changeset 47b2d1ff9743 by Victor Stinner in branch 'default': |
New changeset daf3d2a717e5 by Victor Stinner in branch 'default': New changeset c59d81b802f8 by Victor Stinner in branch 'default': |
Le mardi 31 mars 2015, Roundup Robot <report@bugs.python.org> a écrit :
Oh I forgot to add an #ifdef for socklen_t. I didn't get a warning, so I also forgot to drop the comment before SetLastError(), it's no more |
New changeset d9374864d4a9 by Victor Stinner in branch 'default': New changeset 4fad2b9fc4e6 by Victor Stinner in branch 'default': |
connect_eintr-4.patch: Updated patch after all my changes to refactor socket.connect() (which is now almost a rewrite from scratch!). |
New changeset 7ed567ad8b4c by Victor Stinner in branch 'default': |
New changeset 8ec4acfdb851 by Victor Stinner in branch 'default': |
test_connnect_eintr.py: program to interrupt socket.connect() with signals. It looks like socket.connect() cannot be interrupted by signals: connect() only fails with WSAEINTR when WSACancelBlockingCall() is called, but WSACancelBlockingCall() "has been removed in compliance with the Windows Sockets 2 specification, revision 2.2.0": https://msdn.microsoft.com/en-us/library/windows/desktop/ms741547%28v=vs.85%29.aspx "Blocking hooks are generally used to keep a single-threaded GUI application responsive during calls to blocking functions. Instead of using blocking hooks, an applications should use a separate thread (separate from the main GUI thread) for network activity." |
New changeset aad52bfc816f by Victor Stinner in branch 'default': New changeset f22188acc77d by Victor Stinner in branch 'default': |
Hum, connect() does not always block with test_connect_eintr.py, and this program sometimes fail with ConnectionResetError on connect() on FreeBSD. New program which works on Linux and FreeBSD. It now ensures that connect() will block. |
test_connect_eintr3.py: even better:
Example of output on FreeBSD: Register SIGINT ___[][][#][#][#][#]____[#][**]____[#][#][#][#][*#][#][#][*#][#][#][#][#][#][#][#][#][#]_____[#][#][#][#][#][#][#][#][*#][#]___[#] Test completed in 5.1 sec |
Example of test_connect_eintr3.py output on Linux (3.18): Register SIGINT [][][][][][][][**********][][]___[][] Test completed in 5.4 sec Example of test_connect_eintr3.py output on Mac OS X Yosemite (10.10): Register SIGINT []_____[][**][**********][][***] Test completed in 5.3 sec |
Example of test_connect_eintr3.py output on OpenIndiana: Register SIGINT [][][******][][*****][*****]____[] Test completed in 5.2 sec Oh, and obviously, test_connect_eintr3.py fails with InterruptedError without the patch. Example on Linux: Register SIGINT []____[]_____[]_____[]____[******Traceback (most recent call last):
File "test_connect_eintr.py", line 97, in <module>
func()
File "test_connect_eintr.py", line 51, in func
client.connect(server_addr)
InterruptedError: [Errno 4] Interrupted system call |
New changeset 75fcc7a3738a by Victor Stinner in branch 'default': |
http://buildbot.python.org/all/builders/AMD64%20Snow%20Leop%203.x/builds/2904/steps/test/logs/stdio ====================================================================== Traceback (most recent call last):
File "/Users/buildbot/buildarea/3.x.murray-snowleopard/build/Lib/test/test_ssl.py", line 1441, in test_connect_ex_error
self.assertIn(rc, (errno.ECONNREFUSED, errno.EWOULDBLOCK))
AssertionError: 36 not found in (61, 35) where 36 is errno.EINPROGRESS |
New changeset 44adbb5eeb4b by Victor Stinner in branch 'default': |
New changeset 09a4d5cc6afd by Victor Stinner in branch 'default': |
New changeset bff88c866886 by Victor Stinner in branch 'default': |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: