Prevent possible race conditions in scheduler.

This commit is contained in:
Valentin Lorentz 2012-06-09 16:54:19 +02:00
parent 32eef54a65
commit 9723e14a4d

View File

@ -32,8 +32,11 @@ Schedule plugin with a subclass of drivers.IrcDriver in order to be run as a
Supybot driver. Supybot driver.
""" """
from __future__ import with_statement
import time import time
import heapq import heapq
from threading import Lock
import supybot.log as log import supybot.log as log
import supybot.world as world import supybot.world as world
@ -61,8 +64,10 @@ class Schedule(drivers.IrcDriver):
self.schedule = [] self.schedule = []
self.events = {} self.events = {}
self.counter = 0 self.counter = 0
self.lock = Lock()
def reset(self): def reset(self):
with self.lock:
self.events.clear() self.events.clear()
self.schedule[:] = [] self.schedule[:] = []
# We don't reset the counter here because if someone has held an id of # We don't reset the counter here because if someone has held an id of
@ -82,6 +87,7 @@ class Schedule(drivers.IrcDriver):
self.counter += 1 self.counter += 1
assert name not in self.events, \ assert name not in self.events, \
'An event with the same name has already been scheduled.' 'An event with the same name has already been scheduled.'
with self.lock:
self.events[name] = f self.events[name] = f
heapq.heappush(self.schedule, mytuple((t, name, args, kwargs))) heapq.heappush(self.schedule, mytuple((t, name, args, kwargs)))
return name return name
@ -89,12 +95,13 @@ class Schedule(drivers.IrcDriver):
def removeEvent(self, name): def removeEvent(self, name):
"""Removes the event with the given name from the schedule.""" """Removes the event with the given name from the schedule."""
f = self.events.pop(name) f = self.events.pop(name)
self.schedule = [x for x in self.schedule if f != name]
# We must heapify here because the heap property may not be preserved # We must heapify here because the heap property may not be preserved
# by the above list comprehension. We could, conceivably, just mark # by the above list comprehension. We could, conceivably, just mark
# the elements of the heap as removed and ignore them when we heappop, # the elements of the heap as removed and ignore them when we heappop,
# but that would only save a constant factor (we're already linear for # but that would only save a constant factor (we're already linear for
# the listcomp) so I'm not worried about it right now. # the listcomp) so I'm not worried about it right now.
with self.lock:
self.schedule = [x for x in self.schedule if f != name]
heapq.heapify(self.schedule) heapq.heapify(self.schedule)
return f return f
@ -123,6 +130,7 @@ class Schedule(drivers.IrcDriver):
'why do we continue to live?') 'why do we continue to live?')
time.sleep(1) # We're the only driver; let's pause to think. time.sleep(1) # We're the only driver; let's pause to think.
while self.schedule and self.schedule[0][0] < time.time(): while self.schedule and self.schedule[0][0] < time.time():
with self.lock:
(t, name, args, kwargs) = heapq.heappop(self.schedule) (t, name, args, kwargs) = heapq.heappop(self.schedule)
f = self.events[name] f = self.events[name]
del self.events[name] del self.events[name]