From 063c7ed99d7b8597ae59fd337b3d7c3a81a81087 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 7 Jan 2008 15:25:08 -0800 Subject: [PATCH] redo timer mutexing --- History.txt | 4 ++++ lib/god/timer.rb | 56 ++++++++++++++++++++++++++++++------------------------ test/test_timer.rb | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/History.txt b/History.txt index 650d34d..13b05ed 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,7 @@ +== 0.6.6 / 2008-01-07 + * Bug Fixes + * Redo Timer mutexing to reduce synchronization needs + == 0.6.5 / 2008-01-04 * Bug Fixes * Fix Timer descheduling deadlock issue diff --git a/lib/god/timer.rb b/lib/god/timer.rb index 67713e8..658e453 100644 --- a/lib/god/timer.rb +++ b/lib/god/timer.rb @@ -20,7 +20,7 @@ module God class Timer INTERVAL = 0.25 - attr_reader :events, :conditions, :timer + attr_reader :events, :pending_events, :conditions, :timer @@timer = nil @@ -44,38 +44,45 @@ module God # Returns Timer def initialize @events = [] + @pending_events = [] @conditions = [] - @mutex = Monitor.new + @pending_mutex = Mutex.new @timer = Thread.new do loop do # applog(nil, :debug, "timer main loop, #{@events.size} events pending") begin + # pull in pending events + @pending_mutex.synchronize do + @pending_events.each { |e| @events << e } + @pending_events.clear + end + + @events.sort! { |x, y| x.at <=> y.at } + # get the current time t = Time.now.to_i # iterate over each event and trigger any that are due - @mutex.synchronize do - triggered = [] - - @events.each do |event| - if t >= event.at - # trigger the event and mark it for removal - self.trigger(event) - triggered << event - else - # events are ordered, so we can bail on first miss - break - end - end - - # remove all triggered events - triggered.each do |event| - @conditions.delete(event.condition) - @events.delete(event) + triggered = [] + + @events.each do |event| + if t >= event.at + # trigger the event and mark it for removal + self.trigger(event) + triggered << event + else + # events are ordered, so we can bail on first miss + break end end + + # remove all triggered events + triggered.each do |event| + @conditions.delete(event.condition) + @events.delete(event) + end rescue Exception => e message = format("Unhandled exception (%s): %s\n%s", e.class, e.message, e.backtrace.join("\n")) @@ -95,12 +102,11 @@ module God # Returns nothing def schedule(condition, delay = condition.interval) applog(nil, :debug, "timer schedule #{condition} in #{delay} seconds") - @mutex.synchronize do - unless @conditions.include?(condition) - @events << TimerEvent.new(condition, delay) - @conditions << condition - @events.sort! { |x, y| x.at <=> y.at } + unless @conditions.include?(condition) + @pending_mutex.synchronize do + @pending_events << TimerEvent.new(condition, delay) end + @conditions << condition end end diff --git a/test/test_timer.rb b/test/test_timer.rb index 4ff88b4..9f9f876 100644 --- a/test/test_timer.rb +++ b/test/test_timer.rb @@ -13,7 +13,7 @@ class TestTimer < Test::Unit::TestCase def test_schedule_should_queue_event w = Watch.new @t.schedule(stub(:interval => 20, :watch => w)) - + sleep(0.3) assert_equal 1, @t.events.size end -- 2.11.4.GIT