diff options
author | Thomas Steinacher <tom@eggdrop.ch> | 2016-05-24 16:20:17 -0700 |
---|---|---|
committer | Thomas Steinacher <tom@eggdrop.ch> | 2016-05-24 16:21:18 -0700 |
commit | 2b59b25bb08ea09e98aede1b1f23a270fc085a9f (patch) | |
tree | 75234f28f545e84a383dea2e36f68d8189b7daab /redis/_compat.py | |
parent | 5ef18fd517a50ec04a0a8db353fdba2872c47d61 (diff) | |
download | redis-py-2b59b25bb08ea09e98aede1b1f23a270fc085a9f.tar.gz |
For Python < 3.5, automatically retry EINTR
Diffstat (limited to 'redis/_compat.py')
-rw-r--r-- | redis/_compat.py | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/redis/_compat.py b/redis/_compat.py index 97e4919..d0a6cf3 100644 --- a/redis/_compat.py +++ b/redis/_compat.py @@ -1,6 +1,63 @@ """Internal module for Python 2 backwards compatibility.""" import sys +# For Python older than 3.5, retry EINTR. +if sys.version_info[0] < 3 or sys.version_info[0] == 3 and sys.version_info[1] < 5: + # Adapted from https://bugs.python.org/review/23863/patch/14532/54418 + import socket + import time + import errno + + # Wrapper for handling interruptable system calls. + def _retryable_call(s, func, *args, **kwargs): + # Some modules (SSL) use the _fileobject wrapper directly and + # implement a smaller portion of the socket interface, thus we + # need to let them continue to do so. + timeout, deadline = None, 0.0 + attempted = False + try: + timeout = s.gettimeout() + except AttributeError: + pass + + if timeout: + deadline = time.time() + timeout + + try: + while True: + if attempted and timeout: + now = time.time() + if now >= deadline: + raise socket.error(errno.EWOULDBLOCK, "timed out") + else: + # Overwrite the timeout on the socket object + # to take into account elapsed time. + s.settimeout(deadline - now) + try: + attempted = True + return func(*args, **kwargs) + except socket.error as e: + if e.args[0] == errno.EINTR: + continue + raise + finally: + # Set the existing timeout back for future + # calls. + if timeout: + s.settimeout(timeout) + + def recv(sock, *args, **kwargs): + return _retryable_call(sock, sock.recv, *args, **kwargs) + + def recv_into(sock, *args, **kwargs): + return _retryable_call(sock, sock.recv_into, *args, **kwargs) + +else: # Python 3.5 and above automatically retry EINTR + def recv(sock, *args, **kwargs): + return sock.recv(*args, **kwargs) + + def recv_into(sock, *args, **kwargs): + return sock.recv_into(*args, **kwargs) if sys.version_info[0] < 3: from urllib import unquote |