greenio: check both EAGAIN and EWOULDBLOCK; Thanks to Ramakrishnan G
https://github.com/eventlet/eventlet/issues/61
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -93,3 +93,4 @@ Thanks To
|
||||
* David Goetz, wsgi: Allow minimum_chunk_size to be overriden on a per request basis
|
||||
* Dmitry Orlov, websocket: accept Upgrade: websocket (lowercase)
|
||||
* Zhang Hua, profile: accumulate results between runs (Bitbucket #162)
|
||||
* Ramakrishnan G, greenio: consider EAGAIN error code like EWOULDBLOCK (Github #61)
|
||||
|
||||
@@ -3,7 +3,7 @@ import errno
|
||||
socket = __import__("socket")
|
||||
|
||||
from eventlet import greenio
|
||||
from eventlet.support import get_errno
|
||||
from eventlet.support import EAGAIN_ALIASES, get_errno
|
||||
from eventlet import greenthread
|
||||
from eventlet import hubs
|
||||
from eventlet.patcher import slurp_properties
|
||||
@@ -11,12 +11,13 @@ from eventlet.patcher import slurp_properties
|
||||
__all__ = os_orig.__all__
|
||||
__patched__ = ['fdopen', 'read', 'write', 'wait', 'waitpid']
|
||||
|
||||
slurp_properties(os_orig, globals(),
|
||||
slurp_properties(os_orig, globals(),
|
||||
ignore=__patched__, srckeys=dir(os_orig))
|
||||
|
||||
|
||||
def fdopen(fd, *args, **kw):
|
||||
"""fdopen(fd [, mode='r' [, bufsize]]) -> file_object
|
||||
|
||||
|
||||
Return an open file object connected to a file descriptor."""
|
||||
if not isinstance(fd, int):
|
||||
raise TypeError('fd should be int, not %r' % fd)
|
||||
@@ -25,16 +26,17 @@ def fdopen(fd, *args, **kw):
|
||||
except IOError as e:
|
||||
raise OSError(*e.args)
|
||||
|
||||
|
||||
__original_read__ = os_orig.read
|
||||
def read(fd, n):
|
||||
"""read(fd, buffersize) -> string
|
||||
|
||||
|
||||
Read a file descriptor."""
|
||||
while True:
|
||||
try:
|
||||
return __original_read__(fd, n)
|
||||
except (OSError, IOError) as e:
|
||||
if get_errno(e) != errno.EAGAIN:
|
||||
if get_errno(e) not in EAGAIN_ALIASES:
|
||||
raise
|
||||
except socket.error as e:
|
||||
if get_errno(e) == errno.EPIPE:
|
||||
@@ -42,34 +44,37 @@ def read(fd, n):
|
||||
raise
|
||||
hubs.trampoline(fd, read=True)
|
||||
|
||||
|
||||
__original_write__ = os_orig.write
|
||||
def write(fd, st):
|
||||
"""write(fd, string) -> byteswritten
|
||||
|
||||
|
||||
Write a string to a file descriptor.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
return __original_write__(fd, st)
|
||||
except (OSError, IOError) as e:
|
||||
if get_errno(e) != errno.EAGAIN:
|
||||
if get_errno(e) not in EAGAIN_ALIASES:
|
||||
raise
|
||||
except socket.error as e:
|
||||
if get_errno(e) != errno.EPIPE:
|
||||
raise
|
||||
hubs.trampoline(fd, write=True)
|
||||
|
||||
|
||||
|
||||
def wait():
|
||||
"""wait() -> (pid, status)
|
||||
|
||||
|
||||
Wait for completion of a child process."""
|
||||
return waitpid(0,0)
|
||||
|
||||
|
||||
__original_waitpid__ = os_orig.waitpid
|
||||
def waitpid(pid, options):
|
||||
"""waitpid(...)
|
||||
waitpid(pid, options) -> (pid, status)
|
||||
|
||||
|
||||
Wait for completion of a given child process."""
|
||||
if options & os_orig.WNOHANG != 0:
|
||||
return __original_waitpid__(pid, options)
|
||||
|
||||
@@ -7,7 +7,7 @@ import sys
|
||||
import errno
|
||||
time = __import__('time')
|
||||
|
||||
from eventlet.support import get_errno
|
||||
from eventlet.support import EAGAIN_ALIASES, get_errno
|
||||
from eventlet.hubs import trampoline
|
||||
from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS
|
||||
orig_socket = __import__('socket')
|
||||
@@ -21,6 +21,7 @@ else:
|
||||
|
||||
__patched__ = ['SSLSocket', 'wrap_socket', 'sslwrap_simple']
|
||||
|
||||
|
||||
class GreenSSLSocket(__ssl.SSLSocket):
|
||||
""" This is a green version of the SSLSocket class from the ssl module added
|
||||
in 2.6. For documentation on it, please see the Python standard
|
||||
@@ -140,7 +141,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
|
||||
except orig_socket.error as e:
|
||||
if self.act_non_blocking:
|
||||
raise
|
||||
if get_errno(e) == errno.EWOULDBLOCK:
|
||||
if get_errno(e) in EAGAIN_ALIASES:
|
||||
trampoline(self, write=True,
|
||||
timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
|
||||
if get_errno(e) in SOCKET_CLOSED:
|
||||
@@ -163,7 +164,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
|
||||
except orig_socket.error as e:
|
||||
if self.act_non_blocking:
|
||||
raise
|
||||
if get_errno(e) == errno.EWOULDBLOCK:
|
||||
if get_errno(e) in EAGAIN_ALIASES:
|
||||
trampoline(self, read=True,
|
||||
timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
|
||||
if get_errno(e) in SOCKET_CLOSED:
|
||||
@@ -263,7 +264,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
|
||||
set_nonblocking(newsock)
|
||||
break
|
||||
except orig_socket.error as e:
|
||||
if get_errno(e) != errno.EWOULDBLOCK:
|
||||
if get_errno(e) not in EAGAIN_ALIASES:
|
||||
raise
|
||||
trampoline(self, read=True, timeout=self.gettimeout(),
|
||||
timeout_exc=timeout_exc('timed out'))
|
||||
@@ -282,8 +283,10 @@ class GreenSSLSocket(__ssl.SSLSocket):
|
||||
def dup(self):
|
||||
raise NotImplementedError("Can't dup an ssl object")
|
||||
|
||||
|
||||
SSLSocket = GreenSSLSocket
|
||||
|
||||
|
||||
def wrap_socket(sock, *a, **kw):
|
||||
return GreenSSLSocket(sock, *a, **kw)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from eventlet.support import get_errno, six
|
||||
from eventlet.support import EAGAIN_ALIASES, get_errno, six
|
||||
from eventlet.hubs import trampoline
|
||||
BUFFER_SIZE = 4096
|
||||
|
||||
@@ -13,7 +13,7 @@ import warnings
|
||||
|
||||
__all__ = ['GreenSocket', 'GreenPipe', 'shutdown_safe']
|
||||
|
||||
CONNECT_ERR = set((errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK))
|
||||
CONNECT_ERR = set((errno.EINPROGRESS, errno.EALREADY) + EAGAIN_ALIASES)
|
||||
CONNECT_SUCCESS = set((0, errno.EISCONN))
|
||||
if sys.platform[:3] == "win":
|
||||
CONNECT_ERR.add(errno.WSAEINVAL) # Bug 67
|
||||
@@ -53,19 +53,19 @@ def socket_accept(descriptor):
|
||||
try:
|
||||
return descriptor.accept()
|
||||
except socket.error as e:
|
||||
if get_errno(e) == errno.EWOULDBLOCK:
|
||||
if get_errno(e) in EAGAIN_ALIASES:
|
||||
return None
|
||||
raise
|
||||
|
||||
|
||||
if sys.platform[:3] == "win":
|
||||
# winsock sometimes throws ENOTCONN
|
||||
SOCKET_BLOCKING = set((errno.EWOULDBLOCK,))
|
||||
SOCKET_BLOCKING = set(EAGAIN_ALIASES)
|
||||
SOCKET_CLOSED = set((errno.ECONNRESET, errno.ENOTCONN, errno.ESHUTDOWN))
|
||||
else:
|
||||
# oddly, on linux/darwin, an unconnected socket is expected to block,
|
||||
# so we treat ENOTCONN the same as EWOULDBLOCK
|
||||
SOCKET_BLOCKING = set((errno.EWOULDBLOCK, errno.ENOTCONN))
|
||||
SOCKET_BLOCKING = set((errno.ENOTCONN,) + EAGAIN_ALIASES)
|
||||
SOCKET_CLOSED = set((errno.ECONNRESET, errno.ESHUTDOWN, errno.EPIPE))
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ class _SocketDuckForFd(object):
|
||||
data = os.read(self._fileno, buflen)
|
||||
return data
|
||||
except OSError as e:
|
||||
if get_errno(e) != errno.EAGAIN:
|
||||
if get_errno(e) not in EAGAIN_ALIASES:
|
||||
raise IOError(*e.args)
|
||||
trampoline(self, read=True)
|
||||
|
||||
@@ -379,7 +379,7 @@ class _SocketDuckForFd(object):
|
||||
try:
|
||||
total_sent = os_write(fileno, data)
|
||||
except OSError as e:
|
||||
if get_errno(e) != errno.EAGAIN:
|
||||
if get_errno(e) not in EAGAIN_ALIASES:
|
||||
raise IOError(*e.args)
|
||||
total_sent = 0
|
||||
while total_sent < len_data:
|
||||
@@ -387,7 +387,7 @@ class _SocketDuckForFd(object):
|
||||
try:
|
||||
total_sent += os_write(fileno, data[total_sent:])
|
||||
except OSError as e:
|
||||
if get_errno(e) != errno. EAGAIN:
|
||||
if get_errno(e) not in EAGAIN_ALIASES:
|
||||
raise IOError(*e.args)
|
||||
|
||||
def __del__(self):
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import errno
|
||||
import sys
|
||||
|
||||
from eventlet.support import greenlets
|
||||
|
||||
|
||||
EAGAIN_ALIASES = (errno.EAGAIN, errno.EWOULDBLOCK)
|
||||
|
||||
|
||||
def get_errno(exc):
|
||||
""" Get the error code out of socket.error objects.
|
||||
socket.error in <2.5 does not have errno attribute
|
||||
@@ -14,7 +18,8 @@ def get_errno(exc):
|
||||
"""
|
||||
|
||||
try:
|
||||
if exc.errno is not None: return exc.errno
|
||||
if exc.errno is not None:
|
||||
return exc.errno
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user