]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Use remove and add instead of update_handler in curl_httpclient.
authorBen Darnell <ben@bendarnell.com>
Sat, 25 May 2013 19:26:37 +0000 (15:26 -0400)
committerBen Darnell <ben@bendarnell.com>
Sat, 25 May 2013 19:26:37 +0000 (15:26 -0400)
Curl sometimes fails to tell us that it has closed a socket
and reopened a new one with the same file descriptor, leading
to problems in some IOLoops.  This should fix the recurring problem
of update_handler errors in various less-common use cases.

Closes #801.
Closes #538.

tornado/curl_httpclient.py

index 7d063b7716cca7eb86fc4b6db7487f4765a57a04..e09005691b3ed7f5f179affeeff750f1c94c9930 100644 (file)
@@ -111,13 +111,19 @@ class CurlAsyncHTTPClient(AsyncHTTPClient):
                 del self._fds[fd]
         else:
             ioloop_event = event_map[event]
-            if fd not in self._fds:
-                self.io_loop.add_handler(fd, self._handle_events,
-                                         ioloop_event)
-                self._fds[fd] = ioloop_event
-            else:
-                self.io_loop.update_handler(fd, ioloop_event)
-                self._fds[fd] = ioloop_event
+            # libcurl sometimes closes a socket and then opens a new
+            # one using the same FD without giving us a POLL_NONE in
+            # between.  This is a problem with the epoll IOLoop,
+            # because the kernel can tell when a socket is closed and
+            # removes it from the epoll automatically, causing future
+            # update_handler calls to fail.  Since we can't tell when
+            # this has happened, always use remove and re-add
+            # instead of update.
+            if fd in self._fds:
+                self.io_loop.remove_handler(fd)
+            self.io_loop.add_handler(fd, self._handle_events,
+                                     ioloop_event)
+            self._fds[fd] = ioloop_event
 
     def _set_timeout(self, msecs):
         """Called by libcurl to schedule a timeout."""