EINTR ... was Re: [Zope-dev] browser closing connection

Matthew T. Kromer matt@zope.com
Mon, 10 Dec 2001 18:11:14 -0500


This is a multi-part message in MIME format.
--------------040300040001020308050803
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

>
>
>>>Also, for the record we usually get a bunch of these quite often:
>>>
>>>2001-11-04T09:04:33 ERROR(200) ZServer uncaptured
>>> python exception, closing channel <zhttp_channel connected
>>> XXX.XXX.XXX.XXX:2181 at fb4edc channel#: 2286 requests:4>
>>> (socket.error:(32, 'Broken pipe')
>>>
>>>[/usr/local/zope/dist/Zope-2.4.1/ZServer/medusa/asynchat.py|initiate_send|21
>>>4] [/usr/local/zope/dist/Zope-2.4.1/ZServer/medusa/http_server.py|send|414]
>>>[/usr/local/zope/sw/Python2.1.1/lib/python2.1/asyncore.py|send|330])
>>>
>>>
>>>We were seeing the same error (asyncore.py|send|330, etc) on solaris.
>>>
>>>
>
>


For what its worth, I tracked this down in the sources and confirmed 
that in Zope 2.3, we shipped a modified asyncore.py with Medusa that 
handled EINTR, but in Zope 2.4 we used stock Python's asyncore which 
does NOT handle EINTR being returned from select().  IMHO, the 
distributed Python 2.1 asyncore behavior is incorrect.

I've attached a diff of a portion of the differences (manually edited to 
take out other patches).

I suspect this patch never got integrated due to ugliness of "while 1"

Also, the "what should this be" comment relates to NT's error numbers. 
 Visual C++ has an errno.h that lists EINTR as 4 -- And winsock.h 
defines WSAEINTR as 10004 (ie add 10,000 to the errno).  SO that number 
should be 10004, not 0 for correctness on Windows.

--------------040300040001020308050803
Content-Type: text/plain;
 name="eintr.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="eintr.diff"

--- /usr/local/python-2.1.1/lib/python2.1/asyncore.py	Fri Nov  9 16:28:15 2001
+++ asyncore.py	Sun Oct  1 11:58:56 2000
@@ -59,8 +39,10 @@
     ECONNRESET  = 10054
     ENOTCONN    = 10057
     ESHUTDOWN   = 10058
+    EINTR       = 0 # what should this be?
 else:
-    from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN
+    from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET
+    from errno import ENOTCONN, ESHUTDOWN, EINTR
 
 try:
     socket_map
@@ -83,7 +65,13 @@
                 r.append (fd)
             if obj.writable():
                 w.append (fd)
-        r,w,e = select.select (r,w,e, timeout)
+
+        while 1:
+            try: r,w,e = select.select (r,w,e, timeout)
+            except select.error, v:
+                if v[0] != EINTR: raise
+            else: break
+            
 
         if DEBUG:
             print r,w,e

--------------040300040001020308050803--