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): try: data = self.socket.recv(buffer_size) if not data: # a closed connection is indicated by signaling # a read condition, and having recv() return 0. self.handle_close() return '' else: return data except socket.error, why: # winsock sometimes throws ENOTCONN if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]: self.handle_close() return ''
# no data available elif why[0] in [EWOULDBLOCK, EAGAIN]: return ''
else: 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): try: 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.