Add comments to Timer
[god.git] / lib / god / timer.rb
bloba25b285abd54685853e8acecd32c06c60075ebea
1 module God
2   
3   class TimerEvent
4     attr_accessor :condition, :at
5     
6     # Instantiate a new TimerEvent that will be triggered after the specified delay
7     #   +condition+ is the Condition
8     #   +delay+ is the number of seconds from now at which to trigger
9     #
10     # Returns TimerEvent
11     def initialize(condition, delay)
12       self.condition = condition
13       self.at = Time.now.to_i + delay
14     end
15   end
16   
17   class Timer
18     INTERVAL = 0.25
19     
20     attr_reader :events, :timer
21     
22     @@timer = nil
23     
24     # Get the singleton Timer
25     #
26     # Returns Timer
27     def self.get
28       @@timer ||= Timer.new
29     end
30     
31     # Reset the singleton Timer so the next call to Timer.get will
32     # create a new one
33     #
34     # Returns nothing
35     def self.reset
36       @@timer = nil
37     end
38     
39     # Instantiate a new Timer and start the scheduler loop to handle events
40     #
41     # Returns Timer
42     def initialize
43       @events = []
44       @mutex = Mutex.new
45       
46       @timer = Thread.new do
47         loop do
48           begin
49             # get the current time
50             t = Time.now.to_i
51             
52             # iterate over each event and trigger any that are due
53             @mutex.synchronize do
54               triggered = []
55               
56               @events.each do |event|
57                 if t >= event.at
58                   # trigger the event and mark it for removal
59                   self.trigger(event)
60                   triggered << event
61                 else
62                   # events are ordered, so we can bail on first miss
63                   break
64                 end
65               end
66               
67               # remove all triggered events
68               triggered.each do |event|
69                 @events.delete(event)
70               end
71             end
72           rescue Exception => e
73             message = format("Unhandled exception (%s): %s\n%s",
74                              e.class, e.message, e.backtrace.join("\n"))
75             applog(nil, :fatal, message)
76           ensure
77             # sleep until next check
78             sleep INTERVAL
79           end
80         end
81       end
82     end
83     
84     # Create and register a new TimerEvent
85     #   +condition+ is the Condition
86     #   +delay+ is the number of seconds to delay (default: interval defined in condition)
87     #
88     # Returns nothing
89     def schedule(condition, delay = condition.interval)
90       @mutex.synchronize do
91         @events << TimerEvent.new(condition, delay)
92         @events.sort! { |x, y| x.at <=> y.at }
93       end
94     end
95     
96     # Remove any TimerEvents for the given condition
97     #   +condition+ is the Condition
98     #
99     # Returns nothing
100     def unschedule(condition)
101       @mutex.synchronize do
102         @events.reject! { |x| x.condition == condition }
103       end
104     end
105     
106     # Trigger the event's condition to be evaluated
107     #   +event+ is the TimerEvent to trigger
108     #
109     # Returns nothing
110     def trigger(event)
111       Hub.trigger(event.condition)
112     end
113     
114     # Join the timer thread
115     #
116     # Returns nothing
117     def join
118       @timer.join
119     end
120   end
121