Commit 0dc7ce85 authored by Guido van Rossum's avatar Guido van Rossum

I fixed a bug in asyncore.poll() in Python 2.3; quoting the Python cvs

log:

    Fix an old bug in poll().  When a signal is handled while we're
    blocked in select(), this will raise select.error with errno set
    to EINTR.  The except clauses correctly ignores this error, but
    the rest of the logic will then call read() for all objects in
    select's *input* list of read file descriptors.  Then when an
    object's read_handler() is naive, it will call recv() on its
    socket, which will raise an IOError, and then asyncore decides to
    close the socket.  To fix this, we simply return in this case.

Rather than incorporating a fixed copy of asyncore.py in Zope2 and
ZODB3, I'm incorporating a fixed copy of just asyncore.poll() in this
file, since we already have a copy of asyncore.loop() here.
parent cfbe7cbf
...@@ -29,11 +29,13 @@ This module rebinds loop() in the asyncore module; i.e. once this ...@@ -29,11 +29,13 @@ This module rebinds loop() in the asyncore module; i.e. once this
module is imported, any client of the asyncore module will get module is imported, any client of the asyncore module will get
ThreadedAsync.loop() when it calls asyncore.loop(). ThreadedAsync.loop() when it calls asyncore.loop().
""" """
__version__ = '$Revision: 1.5 $'[11:-2] __version__ = '$Revision: 1.6 $'[11:-2]
import asyncore import asyncore
import select import select
import thread import thread
import time
from errno import EINTR
_loop_lock = thread.allocate_lock() _loop_lock = thread.allocate_lock()
_looping = None _looping = None
...@@ -79,6 +81,52 @@ def _stop_loop(): ...@@ -79,6 +81,52 @@ def _stop_loop():
finally: finally:
_loop_lock.release() _loop_lock.release()
def poll(timeout=0.0, map=None):
"""A copy of asyncore.poll() with a bug fixed (see comment).
(asyncore.poll2() and .poll3() don't have this bug.)
"""
if map is None:
map = asyncore.socket_map
if map:
r = []; w = []; e = []
for fd, obj in map.items():
if obj.readable():
r.append(fd)
if obj.writable():
w.append(fd)
if [] == r == w == e:
time.sleep(timeout)
else:
try:
r, w, e = select.select(r, w, e, timeout)
except select.error, err:
if err[0] != EINTR:
raise
else:
# This part is missing in asyncore before Python 2.3
return
for fd in r:
obj = map.get(fd)
if obj is not None:
try:
obj.handle_read_event()
except asyncore.ExitNow:
raise asyncore.ExitNow
except:
obj.handle_error()
for fd in w:
obj = map.get(fd)
if obj is not None:
try:
obj.handle_write_event()
except asyncore.ExitNow:
raise asyncore.ExitNow
except:
obj.handle_error()
def loop(timeout=30.0, use_poll=0, map=None): def loop(timeout=30.0, use_poll=0, map=None):
"""Invoke asyncore mainloop """Invoke asyncore mainloop
...@@ -92,7 +140,7 @@ def loop(timeout=30.0, use_poll=0, map=None): ...@@ -92,7 +140,7 @@ def loop(timeout=30.0, use_poll=0, map=None):
else: else:
poll_fun = asyncore.poll2 poll_fun = asyncore.poll2
else: else:
poll_fun = asyncore.poll poll_fun = poll
if map is None: if map is None:
map = asyncore.socket_map map = asyncore.socket_map
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment