Revision 577c90a3

b/lib/daemon.py
26 26
import select
27 27
import signal
28 28
import errno
29
import time
30 29
import logging
31 30

  
32 31
from ganeti import utils
33 32
from ganeti import constants
34 33

  
35 34

  
36
class Timer(object):
37
  def __init__(self, owner, timer_id, start, interval, repeat):
38
    self.owner = owner
39
    self.timer_id = timer_id
40
    self.start = start
41
    self.interval = interval
42
    self.repeat = repeat
43

  
44

  
45 35
class Mainloop(object):
46 36
  """Generic mainloop for daemons
47 37

  
......
54 44
    self._io_wait_add = []
55 45
    self._io_wait_remove = []
56 46
    self._signal_wait = []
57
    self._timer_id_last = 0
58
    self._timer = {}
59
    self._timer_add = []
60
    self._timer_remove = []
61 47

  
62 48
  def Run(self, handle_sigchld=True, handle_sigterm=True, stop_on_empty=False):
63 49
    """Runs the mainloop.
......
86 72

  
87 73
      try:
88 74
        running = True
89
        timeout = None
90
        timeout_needs_update = True
91 75

  
92 76
        # Start actual main loop
93 77
        while running:
......
111 95
              poller.register(fd, conditions)
112 96
            self._io_wait_add = []
113 97

  
114
          # Add new timers
115
          if self._timer_add:
116
            timeout_needs_update = True
117
            for timer in self._timer_add:
118
              self._timer[timer.timer_id] = timer
119
            del self._timer_add[:]
120

  
121
          # Remove timers
122
          if self._timer_remove:
123
            timeout_needs_update = True
124
            for timer_id in self._timer_remove:
125
              try:
126
                del self._timer[timer_id]
127
              except KeyError:
128
                pass
129
            del self._timer_remove[:]
130

  
131 98
          # Stop if nothing is listening anymore
132
          if stop_on_empty and not (self._io_wait or self._timer):
99
          if stop_on_empty and not (self._io_wait):
133 100
            break
134 101

  
135
          # Calculate timeout again if required
136
          if timeout_needs_update:
137
            timeout = self._CalcTimeout(time.time())
138
            timeout_needs_update = False
139

  
140 102
          # Wait for I/O events
141 103
          try:
142
            io_events = poller.poll(timeout)
104
            io_events = poller.poll(None)
143 105
          except select.error, err:
144 106
            # EINTR can happen when signals are sent
145 107
            if err.args and err.args[0] in (errno.EINTR,):
......
147 109
            else:
148 110
              raise
149 111

  
150
          after_poll = time.time()
151

  
152 112
          if io_events:
153 113
            # Check for I/O events
154 114
            for (evfd, evcond) in io_events:
......
156 116
              if owner:
157 117
                owner.OnIO(evfd, evcond)
158 118

  
159
          if self._timer:
160
            self._CheckTimers(after_poll)
161

  
162 119
          # Check whether signal was raised
163 120
          if sigchld_handler and sigchld_handler.called:
164 121
            self._CallSignalWaiters(signal.SIGCHLD)
......
176 133
      if sigchld_handler:
177 134
        sigchld_handler.Reset()
178 135

  
179
  def _CalcTimeout(self, now):
180
    if not self._timer:
181
      return None
182

  
183
    timeout = None
184

  
185
    # TODO: Repeating timers
186

  
187
    min_timeout = 0.001
188

  
189
    for timer in self._timer.itervalues():
190
      time_left = (timer.start + timer.interval) - now
191
      if timeout is None or time_left < timeout:
192
        timeout = time_left
193
      if timeout < 0:
194
        timeout = 0
195
        break
196
      elif timeout < min_timeout:
197
        timeout = min_timeout
198
        break
199

  
200
    return timeout * 1000.0
201

  
202
  def _CheckTimers(self, now):
203
    # TODO: Repeating timers
204
    for timer in self._timer.itervalues():
205
      if now < (timer.start + timer.interval):
206
        continue
207

  
208
      timer.owner.OnTimer(timer.timer_id)
209

  
210
      # TODO: Repeating timers should not be removed
211
      self._timer_remove.append(timer.timer_id)
212

  
213 136
  def _CallSignalWaiters(self, signum):
214 137
    """Calls all signal waiters for a certain signal.
215 138

  
......
266 189
    """
267 190
    self._signal_wait.append(owner)
268 191

  
269
  def AddTimer(self, owner, interval, repeat):
270
    """Add a new timer.
271

  
272
    The receiver must support a "OnTimer(self, timer_id)" function.
273

  
274
    @type owner: instance
275
    @param owner: Receiver
276
    @type interval: int or float
277
    @param interval: Timer interval in seconds
278
    @type repeat: bool
279
    @param repeat: Whether this is a repeating timer or one-off
280

  
281
    """
282
    # TODO: Implement repeating timers
283
    assert not repeat, "Repeating timers are not yet supported"
284

  
285
    # Get new ID
286
    self._timer_id_last += 1
287

  
288
    timer_id = self._timer_id_last
289

  
290
    self._timer_add.append(Timer(owner, timer_id, time.time(),
291
                                 float(interval), repeat))
292

  
293
    return timer_id
294

  
295
  def RemoveTimer(self, timer_id):
296
    """Removes a timer.
297

  
298
    @type timer_id: int
299
    @param timer_id: Timer ID
300

  
301
    """
302
    self._timer_remove.append(timer_id)
303

  
304 192

  
305 193
def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn):
306 194
  """Shared main function for daemons.

Also available in: Unified diff