We're back after a server migration that caused effbot.org to fall over a bit harder than expected. Expect some glitches.

Asyncore and Signals

July 10, 2002 | Fredrik Lundh (with help from Erik Heneryd)

The asyncore module can misbehave on some platforms (Linux, at least), when the process is receiving signals. What usually happens is that asyncore generates bogus handle_recv or handle_accept calls.

bogus calls to handle_recv: recv fails

When this happens, the recv call will raise a socket error exception with the error code set to EWOULDBLOCK or EAGAIN.

To work around this, it’s easiest to simply modify the asyncore module. Just add code to check for EWOULDBLOCK and EAGAIN to the recv call, like this:

    # in asyncore.py
    def recv(self, buffer_size):
            data = self.socket.recv(buffer_size)
            if not data:
                # a closed connection is indicated by signaling
                # a read condition, and having recv() return 0.
                return ''
                return data
        except socket.error, why:
            # winsock sometimes throws ENOTCONN
            if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
                return ''
            # no data available
            elif why[0] in [EWOULDBLOCK, EAGAIN]:
                return ''
                raise socket.error, why

Note that on Linux, EWOULDBLOCK is the same thing as EAGAIN. Cannot hurt to look for them both, though…

bogus calls to handle_accept: accept fails

When this happens, the accept method will return None instead of a (socket, address) tuple. The workaround is to check for this condition inside your handle_accept event handler:

    def handle_accept(self):
            sock, addr = self.accept()
        except TypeError:
            return # ignore this event

The underlying problem is that the socket’s accept call may raise an EWOULDBLOCK exception. Unfortunately, there’s no obvious way to detect this without actually calling the method.