Statistics
| Branch: | Tag: | Revision:

root / lib / daemon.py @ 6c00d19a

History | View | Annotate | Download (8.1 kB)

1 821d9e43 Michael Hanselmann
#
2 821d9e43 Michael Hanselmann
#
3 821d9e43 Michael Hanselmann
4 821d9e43 Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 821d9e43 Michael Hanselmann
#
6 821d9e43 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 821d9e43 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 821d9e43 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 821d9e43 Michael Hanselmann
# (at your option) any later version.
10 821d9e43 Michael Hanselmann
#
11 821d9e43 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 821d9e43 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 821d9e43 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 821d9e43 Michael Hanselmann
# General Public License for more details.
15 821d9e43 Michael Hanselmann
#
16 821d9e43 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 821d9e43 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 821d9e43 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 821d9e43 Michael Hanselmann
# 02110-1301, USA.
20 821d9e43 Michael Hanselmann
21 821d9e43 Michael Hanselmann
22 821d9e43 Michael Hanselmann
"""Module with helper classes and functions for daemons"""
23 821d9e43 Michael Hanselmann
24 821d9e43 Michael Hanselmann
25 821d9e43 Michael Hanselmann
import select
26 821d9e43 Michael Hanselmann
import signal
27 821d9e43 Michael Hanselmann
import errno
28 b11c9e5c Michael Hanselmann
import time
29 821d9e43 Michael Hanselmann
30 821d9e43 Michael Hanselmann
from ganeti import utils
31 821d9e43 Michael Hanselmann
32 821d9e43 Michael Hanselmann
33 b11c9e5c Michael Hanselmann
class Timer(object):
34 b11c9e5c Michael Hanselmann
  def __init__(self, owner, timer_id, start, interval, repeat):
35 b11c9e5c Michael Hanselmann
    self.owner = owner
36 b11c9e5c Michael Hanselmann
    self.timer_id = timer_id
37 b11c9e5c Michael Hanselmann
    self.start = start
38 b11c9e5c Michael Hanselmann
    self.interval = interval
39 b11c9e5c Michael Hanselmann
    self.repeat = repeat
40 b11c9e5c Michael Hanselmann
41 b11c9e5c Michael Hanselmann
42 821d9e43 Michael Hanselmann
class Mainloop(object):
43 821d9e43 Michael Hanselmann
  """Generic mainloop for daemons
44 821d9e43 Michael Hanselmann

45 821d9e43 Michael Hanselmann
  """
46 821d9e43 Michael Hanselmann
  def __init__(self):
47 b14b975f Michael Hanselmann
    """Constructs a new Mainloop instance.
48 b14b975f Michael Hanselmann

49 b14b975f Michael Hanselmann
    """
50 b14b975f Michael Hanselmann
    self._io_wait = {}
51 b14b975f Michael Hanselmann
    self._io_wait_add = []
52 b14b975f Michael Hanselmann
    self._io_wait_remove = []
53 821d9e43 Michael Hanselmann
    self._signal_wait = []
54 b11c9e5c Michael Hanselmann
    self._timer_id_last = 0
55 b11c9e5c Michael Hanselmann
    self._timer = {}
56 b11c9e5c Michael Hanselmann
    self._timer_add = []
57 b11c9e5c Michael Hanselmann
    self._timer_remove = []
58 821d9e43 Michael Hanselmann
59 b14b975f Michael Hanselmann
  def Run(self, handle_sigchld=True, handle_sigterm=True, stop_on_empty=False):
60 b14b975f Michael Hanselmann
    """Runs the mainloop.
61 b14b975f Michael Hanselmann

62 b14b975f Michael Hanselmann
    @type handle_sigchld: bool
63 b14b975f Michael Hanselmann
    @param handle_sigchld: Whether to install handler for SIGCHLD
64 b14b975f Michael Hanselmann
    @type handle_sigterm: bool
65 b14b975f Michael Hanselmann
    @param handle_sigterm: Whether to install handler for SIGTERM
66 b14b975f Michael Hanselmann
    @type stop_on_empty: bool
67 b14b975f Michael Hanselmann
    @param stop_on_empty: Whether to stop mainloop once all I/O waiters
68 b14b975f Michael Hanselmann
                          unregistered
69 b14b975f Michael Hanselmann

70 b14b975f Michael Hanselmann
    """
71 821d9e43 Michael Hanselmann
    poller = select.poll()
72 821d9e43 Michael Hanselmann
73 b14b975f Michael Hanselmann
    # Setup signal handlers
74 b14b975f Michael Hanselmann
    if handle_sigchld:
75 b14b975f Michael Hanselmann
      sigchld_handler = utils.SignalHandler([signal.SIGCHLD])
76 b14b975f Michael Hanselmann
    else:
77 b14b975f Michael Hanselmann
      sigchld_handler = None
78 821d9e43 Michael Hanselmann
    try:
79 b14b975f Michael Hanselmann
      if handle_sigterm:
80 b14b975f Michael Hanselmann
        sigterm_handler = utils.SignalHandler([signal.SIGTERM])
81 b14b975f Michael Hanselmann
      else:
82 b14b975f Michael Hanselmann
        sigterm_handler = None
83 b14b975f Michael Hanselmann
84 b14b975f Michael Hanselmann
      try:
85 b14b975f Michael Hanselmann
        running = True
86 b11c9e5c Michael Hanselmann
        timeout = None
87 b11c9e5c Michael Hanselmann
        timeout_needs_update = True
88 b14b975f Michael Hanselmann
89 b14b975f Michael Hanselmann
        # Start actual main loop
90 b14b975f Michael Hanselmann
        while running:
91 b14b975f Michael Hanselmann
          # Entries could be added again afterwards, hence removing first
92 b14b975f Michael Hanselmann
          if self._io_wait_remove:
93 b14b975f Michael Hanselmann
            for fd in self._io_wait_remove:
94 b14b975f Michael Hanselmann
              try:
95 b14b975f Michael Hanselmann
                poller.unregister(fd)
96 b14b975f Michael Hanselmann
              except KeyError:
97 b14b975f Michael Hanselmann
                pass
98 b14b975f Michael Hanselmann
              try:
99 b14b975f Michael Hanselmann
                del self._io_wait[fd]
100 b14b975f Michael Hanselmann
              except KeyError:
101 b14b975f Michael Hanselmann
                pass
102 b14b975f Michael Hanselmann
            self._io_wait_remove = []
103 b14b975f Michael Hanselmann
104 b14b975f Michael Hanselmann
          # Add new entries
105 b14b975f Michael Hanselmann
          if self._io_wait_add:
106 b14b975f Michael Hanselmann
            for (owner, fd, conditions) in self._io_wait_add:
107 b14b975f Michael Hanselmann
              self._io_wait[fd] = owner
108 b14b975f Michael Hanselmann
              poller.register(fd, conditions)
109 b14b975f Michael Hanselmann
            self._io_wait_add = []
110 b14b975f Michael Hanselmann
111 b11c9e5c Michael Hanselmann
          # Add new timers
112 b11c9e5c Michael Hanselmann
          if self._timer_add:
113 b11c9e5c Michael Hanselmann
            timeout_needs_update = True
114 b11c9e5c Michael Hanselmann
            for timer in self._timer_add:
115 b11c9e5c Michael Hanselmann
              self._timer[timer.timer_id] = timer
116 b11c9e5c Michael Hanselmann
            del self._timer_add[:]
117 b11c9e5c Michael Hanselmann
118 b11c9e5c Michael Hanselmann
          # Remove timers
119 b11c9e5c Michael Hanselmann
          if self._timer_remove:
120 b11c9e5c Michael Hanselmann
            timeout_needs_update = True
121 b11c9e5c Michael Hanselmann
            for timer_id in self._timer_remove:
122 b11c9e5c Michael Hanselmann
              try:
123 b11c9e5c Michael Hanselmann
                del self._timer[timer_id]
124 b11c9e5c Michael Hanselmann
              except KeyError:
125 b11c9e5c Michael Hanselmann
                pass
126 b11c9e5c Michael Hanselmann
            del self._timer_remove[:]
127 b11c9e5c Michael Hanselmann
128 b14b975f Michael Hanselmann
          # Stop if nothing is listening anymore
129 b11c9e5c Michael Hanselmann
          if stop_on_empty and not (self._io_wait or self._timer):
130 b14b975f Michael Hanselmann
            break
131 b14b975f Michael Hanselmann
132 b11c9e5c Michael Hanselmann
          # Calculate timeout again if required
133 b11c9e5c Michael Hanselmann
          if timeout_needs_update:
134 b11c9e5c Michael Hanselmann
            timeout = self._CalcTimeout(time.time())
135 53d47a06 Guido Trotter
            timeout_needs_update = False
136 b11c9e5c Michael Hanselmann
137 b14b975f Michael Hanselmann
          # Wait for I/O events
138 b14b975f Michael Hanselmann
          try:
139 b11c9e5c Michael Hanselmann
            io_events = poller.poll(timeout)
140 b14b975f Michael Hanselmann
          except select.error, err:
141 b14b975f Michael Hanselmann
            # EINTR can happen when signals are sent
142 b14b975f Michael Hanselmann
            if err.args and err.args[0] in (errno.EINTR,):
143 b14b975f Michael Hanselmann
              io_events = None
144 b14b975f Michael Hanselmann
            else:
145 b14b975f Michael Hanselmann
              raise
146 b14b975f Michael Hanselmann
147 b11c9e5c Michael Hanselmann
          after_poll = time.time()
148 b11c9e5c Michael Hanselmann
149 b14b975f Michael Hanselmann
          if io_events:
150 b14b975f Michael Hanselmann
            # Check for I/O events
151 b14b975f Michael Hanselmann
            for (evfd, evcond) in io_events:
152 b14b975f Michael Hanselmann
              owner = self._io_wait.get(evfd, None)
153 b14b975f Michael Hanselmann
              if owner:
154 b14b975f Michael Hanselmann
                owner.OnIO(evfd, evcond)
155 b14b975f Michael Hanselmann
156 b11c9e5c Michael Hanselmann
          if self._timer:
157 b11c9e5c Michael Hanselmann
            self._CheckTimers(after_poll)
158 b11c9e5c Michael Hanselmann
159 b14b975f Michael Hanselmann
          # Check whether signal was raised
160 b14b975f Michael Hanselmann
          if sigchld_handler and sigchld_handler.called:
161 b14b975f Michael Hanselmann
            self._CallSignalWaiters(signal.SIGCHLD)
162 b14b975f Michael Hanselmann
            sigchld_handler.Clear()
163 b14b975f Michael Hanselmann
164 b14b975f Michael Hanselmann
          if sigterm_handler and sigterm_handler.called:
165 b14b975f Michael Hanselmann
            self._CallSignalWaiters(signal.SIGTERM)
166 b14b975f Michael Hanselmann
            running = False
167 b14b975f Michael Hanselmann
            sigterm_handler.Clear()
168 b14b975f Michael Hanselmann
      finally:
169 b14b975f Michael Hanselmann
        # Restore signal handlers
170 b14b975f Michael Hanselmann
        if sigterm_handler:
171 b14b975f Michael Hanselmann
          sigterm_handler.Reset()
172 821d9e43 Michael Hanselmann
    finally:
173 b14b975f Michael Hanselmann
      if sigchld_handler:
174 b14b975f Michael Hanselmann
        sigchld_handler.Reset()
175 a570e2a8 Guido Trotter
176 b11c9e5c Michael Hanselmann
  def _CalcTimeout(self, now):
177 b11c9e5c Michael Hanselmann
    if not self._timer:
178 b11c9e5c Michael Hanselmann
      return None
179 b11c9e5c Michael Hanselmann
180 b11c9e5c Michael Hanselmann
    timeout = None
181 b11c9e5c Michael Hanselmann
182 b11c9e5c Michael Hanselmann
    # TODO: Repeating timers
183 b11c9e5c Michael Hanselmann
184 b11c9e5c Michael Hanselmann
    min_timeout = 0.001
185 b11c9e5c Michael Hanselmann
186 b11c9e5c Michael Hanselmann
    for timer in self._timer.itervalues():
187 b11c9e5c Michael Hanselmann
      time_left = (timer.start + timer.interval) - now
188 b11c9e5c Michael Hanselmann
      if timeout is None or time_left < timeout:
189 b11c9e5c Michael Hanselmann
        timeout = time_left
190 b11c9e5c Michael Hanselmann
      if timeout < 0:
191 b11c9e5c Michael Hanselmann
        timeout = 0
192 b11c9e5c Michael Hanselmann
        break
193 b11c9e5c Michael Hanselmann
      elif timeout < min_timeout:
194 b11c9e5c Michael Hanselmann
        timeout = min_timeout
195 b11c9e5c Michael Hanselmann
        break
196 b11c9e5c Michael Hanselmann
197 b11c9e5c Michael Hanselmann
    return timeout * 1000.0
198 b11c9e5c Michael Hanselmann
199 b11c9e5c Michael Hanselmann
  def _CheckTimers(self, now):
200 b11c9e5c Michael Hanselmann
    # TODO: Repeating timers
201 b11c9e5c Michael Hanselmann
    for timer in self._timer.itervalues():
202 b11c9e5c Michael Hanselmann
      if now < (timer.start + timer.interval):
203 b11c9e5c Michael Hanselmann
        continue
204 b11c9e5c Michael Hanselmann
205 b11c9e5c Michael Hanselmann
      timer.owner.OnTimer(timer.timer_id)
206 b11c9e5c Michael Hanselmann
207 b11c9e5c Michael Hanselmann
      # TODO: Repeating timers should not be removed
208 b11c9e5c Michael Hanselmann
      self._timer_remove.append(timer.timer_id)
209 b11c9e5c Michael Hanselmann
210 b14b975f Michael Hanselmann
  def _CallSignalWaiters(self, signum):
211 b14b975f Michael Hanselmann
    """Calls all signal waiters for a certain signal.
212 b14b975f Michael Hanselmann

213 b14b975f Michael Hanselmann
    @type signum: int
214 b14b975f Michael Hanselmann
    @param signum: Signal number
215 b14b975f Michael Hanselmann

216 b14b975f Michael Hanselmann
    """
217 b14b975f Michael Hanselmann
    for owner in self._signal_wait:
218 b14b975f Michael Hanselmann
      owner.OnSignal(signal.SIGCHLD)
219 821d9e43 Michael Hanselmann
220 821d9e43 Michael Hanselmann
  def RegisterIO(self, owner, fd, condition):
221 821d9e43 Michael Hanselmann
    """Registers a receiver for I/O notifications
222 821d9e43 Michael Hanselmann

223 821d9e43 Michael Hanselmann
    The receiver must support a "OnIO(self, fd, conditions)" function.
224 821d9e43 Michael Hanselmann

225 821d9e43 Michael Hanselmann
    @type owner: instance
226 821d9e43 Michael Hanselmann
    @param owner: Receiver
227 821d9e43 Michael Hanselmann
    @type fd: int
228 821d9e43 Michael Hanselmann
    @param fd: File descriptor
229 821d9e43 Michael Hanselmann
    @type condition: int
230 821d9e43 Michael Hanselmann
    @param condition: ORed field of conditions to be notified
231 821d9e43 Michael Hanselmann
                      (see select module)
232 821d9e43 Michael Hanselmann

233 821d9e43 Michael Hanselmann
    """
234 b14b975f Michael Hanselmann
    # select.Poller also supports file() like objects, but we don't.
235 b14b975f Michael Hanselmann
    assert isinstance(fd, (int, long)), \
236 b14b975f Michael Hanselmann
      "Only integers are supported for file descriptors"
237 b14b975f Michael Hanselmann
238 b14b975f Michael Hanselmann
    self._io_wait_add.append((owner, fd, condition))
239 b14b975f Michael Hanselmann
240 b14b975f Michael Hanselmann
  def UnregisterIO(self, fd):
241 b14b975f Michael Hanselmann
    """Unregister a file descriptor.
242 b14b975f Michael Hanselmann

243 b14b975f Michael Hanselmann
    It'll be unregistered the next time the mainloop checks for it.
244 b14b975f Michael Hanselmann

245 b14b975f Michael Hanselmann
    @type fd: int
246 b14b975f Michael Hanselmann
    @param fd: File descriptor
247 b14b975f Michael Hanselmann

248 b14b975f Michael Hanselmann
    """
249 b14b975f Michael Hanselmann
    # select.Poller also supports file() like objects, but we don't.
250 b14b975f Michael Hanselmann
    assert isinstance(fd, (int, long)), \
251 b14b975f Michael Hanselmann
      "Only integers are supported for file descriptors"
252 b14b975f Michael Hanselmann
253 b14b975f Michael Hanselmann
    self._io_wait_remove.append(fd)
254 821d9e43 Michael Hanselmann
255 821d9e43 Michael Hanselmann
  def RegisterSignal(self, owner):
256 821d9e43 Michael Hanselmann
    """Registers a receiver for signal notifications
257 821d9e43 Michael Hanselmann

258 821d9e43 Michael Hanselmann
    The receiver must support a "OnSignal(self, signum)" function.
259 821d9e43 Michael Hanselmann

260 821d9e43 Michael Hanselmann
    @type owner: instance
261 821d9e43 Michael Hanselmann
    @param owner: Receiver
262 821d9e43 Michael Hanselmann

263 821d9e43 Michael Hanselmann
    """
264 821d9e43 Michael Hanselmann
    self._signal_wait.append(owner)
265 b11c9e5c Michael Hanselmann
266 b11c9e5c Michael Hanselmann
  def AddTimer(self, owner, interval, repeat):
267 b11c9e5c Michael Hanselmann
    """Add a new timer.
268 b11c9e5c Michael Hanselmann

269 b11c9e5c Michael Hanselmann
    The receiver must support a "OnTimer(self, timer_id)" function.
270 b11c9e5c Michael Hanselmann

271 b11c9e5c Michael Hanselmann
    @type owner: instance
272 b11c9e5c Michael Hanselmann
    @param owner: Receiver
273 b11c9e5c Michael Hanselmann
    @type interval: int or float
274 b11c9e5c Michael Hanselmann
    @param interval: Timer interval in seconds
275 b11c9e5c Michael Hanselmann
    @type repeat: bool
276 b11c9e5c Michael Hanselmann
    @param repeat: Whether this is a repeating timer or one-off
277 b11c9e5c Michael Hanselmann

278 b11c9e5c Michael Hanselmann
    """
279 b11c9e5c Michael Hanselmann
    # TODO: Implement repeating timers
280 b11c9e5c Michael Hanselmann
    assert not repeat, "Repeating timers are not yet supported"
281 b11c9e5c Michael Hanselmann
282 b11c9e5c Michael Hanselmann
    # Get new ID
283 b11c9e5c Michael Hanselmann
    self._timer_id_last += 1
284 b11c9e5c Michael Hanselmann
285 b11c9e5c Michael Hanselmann
    timer_id = self._timer_id_last
286 b11c9e5c Michael Hanselmann
287 b11c9e5c Michael Hanselmann
    self._timer_add.append(Timer(owner, timer_id, time.time(),
288 b11c9e5c Michael Hanselmann
                                 float(interval), repeat))
289 b11c9e5c Michael Hanselmann
290 b11c9e5c Michael Hanselmann
    return timer_id
291 b11c9e5c Michael Hanselmann
292 b11c9e5c Michael Hanselmann
  def RemoveTimer(self, timer_id):
293 b11c9e5c Michael Hanselmann
    """Removes a timer.
294 b11c9e5c Michael Hanselmann

295 b11c9e5c Michael Hanselmann
    @type timer_id: int
296 b11c9e5c Michael Hanselmann
    @param timer_id: Timer ID
297 b11c9e5c Michael Hanselmann

298 b11c9e5c Michael Hanselmann
    """
299 b11c9e5c Michael Hanselmann
    self._timer_remove.append(timer_id)