Skip to content
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

ThreadedServer vs ForkingServer - different behaviour on pypy3 V2.3.1 and python3.4.1 --> rpyc BUG ! #149

Closed
bitranox opened this issue Oct 23, 2014 · 1 comment

Comments

@bitranox
Copy link

ThreadedServer vs ForkingServer - different behaviour on pypy3 V2.3.1 and python3.4.1
I use rpyc 3.3 on Linux Mint Mate, either with python3 (Version 3.4.1) or pypy3 (Version 2.3.1)
on python3 - ThreadedServer and ForkingServer working as expected so far.
on pypy3 - ThreadedServer Works, But ForkingServer terminates when a client is closing the connection.

tomerfiliba answered : well, it's clearly a pypy bug. i'd suggest you added prints() around the server's code (rpyc/utils/server.py) to see what's going on there. perhaps it's an issue with signals, or what not. donno.

So I reported back to the pypy team and they stated that the error is in rpyc/utils/server.py :

Here the answer of Philip Jenvey, of the pypy team :

Sorry for the back and forth but this isn't a PyPy issue. The problem lies in rpyc.utils.server.Server.accept method: it doesn't handle the case of the listener socket's accept call potentially failing with EAGAIN.

EAGAINs from socket's accept should only occur with non-blocking sockets. I guess Server.accept assumes its listener socket is blocking (no EAGAINs) but it's actually in what Python calls "timeout mode" (has had an explicit timeout set via settimeout) which basically triggers non-blocking mode internally.

You can see this in e.g. even CPython's socketmodule.c: the sock_settimeout function, when called w/ a timeout value >= 0.0, calls internal_setblocking with block=0 meaning enable non-blocking mode underneath. These assertions prove it:

diff --git a/rpyc/utils/server.py b/rpyc/utils/server.py
index e471bc6..f7c15dd 100644
--- a/rpyc/utils/server.py
+++ b/rpyc/utils/server.py
@@ -125,6 +125,9 @@ class Server(object):
         """accepts an incoming socket connection (blocking)"""
         while self.active:
             try:
+                import fcntl
+                flags = fcntl.fcntl(self.listener.fileno(), fcntl.F_GETFL)
+                assert (flags & os.O_NONBLOCK) == os.O_NONBLOCK
                 sock, addrinfo = self.listener.accept()
             except socket.timeout:
                 pass
Python 2.6.4 (r264:75706, Dec  7 2009, 18:43:55) 
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import fcntl, os, socket
>>> is_nonblock = lambda s: (fcntl.fcntl(s.fileno(), fcntl.F_GETFL) & os.O_NONBLOCK) == os.O_NONBLOCK
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> assert not is_nonblock(s)
>>> s.settimeout(0.5)
>>> assert is_nonblock(s)

This could potentially happen on CPython too, if it doesn't it's probably due to slight different timings due to differing run times and luck.

Something along the lines of the following patch to rpyc fixes your script to run to completion:

diff --git a/rpyc/utils/server.py b/rpyc/utils/server.py
index e471bc6..ef0e1de 100644
--- a/rpyc/utils/server.py
+++ b/rpyc/utils/server.py
@@ -130,7 +130,8 @@ class Server(object):
                 pass
             except socket.error:
                 ex = sys.exc_info()[1]
-                if get_exc_errno(ex) == errno.EINTR:
+                exc_errno = get_exc_errno(ex)
+                if exc_errno in (errno.EINTR, errno.EAGAIN):
                     pass
                 else:
                     raise EOFError()

Good luck with it, I must say I'm a bit frustrated with rpyc now with its author being so quick to assume the problem as PyPy's without even bothering to look into it =]

Philip Jenvey

well I hope this is useful, please let me know if You will apply the patch in future versions of rpyc,
or if I will have to take care myself for the issue.

yours sincerely
Robert Nowotny

@bitranox bitranox changed the title ThreadedServer vs ForkingServer - different behaviour on pypy3 V2.3.1 and python3.4.1 --> pypy BUG ! ThreadedServer vs ForkingServer - different behaviour on pypy3 V2.3.1 and python3.4.1 --> rpyc BUG ! Oct 23, 2014
@bitranox
Copy link
Author

Dear tomerfiliba,
thanks for the patch. Its ['f','w']orking now.
yours sincerely
Robert

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant