Commits

Floris Bruynooghe committed 6dacb39

Make BaseHub.schedule_call_global() thread-safe

This makes it thread-safe to call .schedule_call_global() from another
thread. While the call itself is safe the other functions manipulating
the .next_timers list, which are still being executed by the tread of
the hub while you call .schedule_call_global(), did so in an unsafe way.
By slightly tweaking those to manipulate the list in place we can avoid
any timers getting lost and it is now thread-safe to call
.schedule_call_global() from another thread.

  • Participants
  • Parent commits 76be391

Comments (0)

Files changed (1)

 # HG changeset patch
-# Parent f30a2fa65f30e993cf7cf6e2d76e23b302e30990
+# Parent e2a73a7f7e459d258010b40d0ce3b55aca4aa179
 # User Floris Bruynooghe <flub@devork.be>
-# Date 1314663268 -3600
+# Date 1337897116 -3600
 
 Create xthread package
 
  from eventlet import timeout
  def trampoline(fd, read=None, write=None, timeout=None, 
                 timeout_exc=timeout.Timeout):
+diff --git a/eventlet/hubs/hub.py b/eventlet/hubs/hub.py
+--- a/eventlet/hubs/hub.py
++++ b/eventlet/hubs/hub.py
+@@ -276,18 +276,23 @@ class BaseHub(object):
+         if len_timers > 1000 and len_timers/2 <= self.timers_canceled:
+             self.timers_canceled = 0
+             self.timers = [t for t in self.timers if not t[1].called]
+-            self.next_timers = [t for t in self.next_timers if not t[1].called]
++            for item in self.next_timers:
++                if item[1].called:
++                    self.next_timers.remove(item)
+             heapq.heapify(self.timers)
+ 
+     def prepare_timers(self):
+         heappush = heapq.heappush
+         t = self.timers
+-        for item in self.next_timers:
++        while 1:
++            try:
++                item = self.next_timers.pop()
++            except IndexError:
++                break
+             if item[1].called:
+                 self.timers_canceled -= 1
+             else:
+                 heappush(t, item)
+-        del self.next_timers[:]
+ 
+     def schedule_call_local(self, seconds, cb, *args, **kw):
+         """Schedule a callable to be called after 'seconds' seconds have
 diff --git a/eventlet/xthread.py b/eventlet/xthread.py
 new file mode 100644
 --- /dev/null