[Zope-Checkins] CVS: ZODB3/ThreadedAsync - LoopCallback.py:1.6

Guido van Rossum guido@python.org
Tue, 5 Nov 2002 14:31:22 -0500


Update of /cvs-repository/ZODB3/ThreadedAsync
In directory cvs.zope.org:/tmp/cvs-serv10705

Modified Files:
	LoopCallback.py 
Log Message:
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.


=== ZODB3/ThreadedAsync/LoopCallback.py 1.5 => 1.6 ===
--- ZODB3/ThreadedAsync/LoopCallback.py:1.5	Fri Sep 27 16:49:08 2002
+++ ZODB3/ThreadedAsync/LoopCallback.py	Tue Nov  5 14:31:21 2002
@@ -34,6 +34,8 @@
 import asyncore
 import select
 import thread
+import time
+from errno import EINTR
 
 _loop_lock = thread.allocate_lock()
 _looping = None
@@ -79,6 +81,52 @@
     finally:
         _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):
     """Invoke asyncore mainloop
 
@@ -92,7 +140,7 @@
         else:
             poll_fun = asyncore.poll2
     else:
-        poll_fun = asyncore.poll
+        poll_fun = poll
 
     if map is None:
         map = asyncore.socket_map