Statistics
| Branch: | Tag: | Revision:

root / lib / daemon.py @ bf75f132

History | View | Annotate | Download (8 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 b11c9e5c Michael Hanselmann
136 b14b975f Michael Hanselmann
          # Wait for I/O events
137 b14b975f Michael Hanselmann
          try:
138 b11c9e5c Michael Hanselmann
            io_events = poller.poll(timeout)
139 b14b975f Michael Hanselmann
          except select.error, err:
140 b14b975f Michael Hanselmann
            # EINTR can happen when signals are sent
141 b14b975f Michael Hanselmann
            if err.args and err.args[0] in (errno.EINTR,):
142 b14b975f Michael Hanselmann
              io_events = None
143 b14b975f Michael Hanselmann
            else:
144 b14b975f Michael Hanselmann
              raise
145 b14b975f Michael Hanselmann
146 b11c9e5c Michael Hanselmann
          after_poll = time.time()
147 b11c9e5c Michael Hanselmann
148 b14b975f Michael Hanselmann
          if io_events:
149 b14b975f Michael Hanselmann
            # Check for I/O events
150 b14b975f Michael Hanselmann
            for (evfd, evcond) in io_events:
151 b14b975f Michael Hanselmann
              owner = self._io_wait.get(evfd, None)
152 b14b975f Michael Hanselmann
              if owner:
153 b14b975f Michael Hanselmann
                owner.OnIO(evfd, evcond)
154 b14b975f Michael Hanselmann
155 b11c9e5c Michael Hanselmann
          if self._timer:
156 b11c9e5c Michael Hanselmann
            self._CheckTimers(after_poll)
157 b11c9e5c Michael Hanselmann
158 b14b975f Michael Hanselmann
          # Check whether signal was raised
159 b14b975f Michael Hanselmann
          if sigchld_handler and sigchld_handler.called:
160 b14b975f Michael Hanselmann
            self._CallSignalWaiters(signal.SIGCHLD)
161 b14b975f Michael Hanselmann
            sigchld_handler.Clear()
162 b14b975f Michael Hanselmann
163 b14b975f Michael Hanselmann
          if sigterm_handler and sigterm_handler.called:
164 b14b975f Michael Hanselmann
            self._CallSignalWaiters(signal.SIGTERM)
165 b14b975f Michael Hanselmann
            running = False
166 b14b975f Michael Hanselmann
            sigterm_handler.Clear()
167 b14b975f Michael Hanselmann
      finally:
168 b14b975f Michael Hanselmann
        # Restore signal handlers
169 b14b975f Michael Hanselmann
        if sigterm_handler:
170 b14b975f Michael Hanselmann
          sigterm_handler.Reset()
171 821d9e43 Michael Hanselmann
    finally:
172 b14b975f Michael Hanselmann
      if sigchld_handler:
173 b14b975f Michael Hanselmann
        sigchld_handler.Reset()
174 a570e2a8 Guido Trotter
175 b11c9e5c Michael Hanselmann
  def _CalcTimeout(self, now):
176 b11c9e5c Michael Hanselmann
    if not self._timer:
177 b11c9e5c Michael Hanselmann
      return None
178 b11c9e5c Michael Hanselmann
179 b11c9e5c Michael Hanselmann
    timeout = None
180 b11c9e5c Michael Hanselmann
181 b11c9e5c Michael Hanselmann
    # TODO: Repeating timers
182 b11c9e5c Michael Hanselmann
183 b11c9e5c Michael Hanselmann
    min_timeout = 0.001
184 b11c9e5c Michael Hanselmann
185 b11c9e5c Michael Hanselmann
    for timer in self._timer.itervalues():
186 b11c9e5c Michael Hanselmann
      time_left = (timer.start + timer.interval) - now
187 b11c9e5c Michael Hanselmann
      if timeout is None or time_left < timeout:
188 b11c9e5c Michael Hanselmann
        timeout = time_left
189 b11c9e5c Michael Hanselmann
      if timeout < 0:
190 b11c9e5c Michael Hanselmann
        timeout = 0
191 b11c9e5c Michael Hanselmann
        break
192 b11c9e5c Michael Hanselmann
      elif timeout < min_timeout:
193 b11c9e5c Michael Hanselmann
        timeout = min_timeout
194 b11c9e5c Michael Hanselmann
        break
195 b11c9e5c Michael Hanselmann
196 b11c9e5c Michael Hanselmann
    return timeout * 1000.0
197 b11c9e5c Michael Hanselmann
198 b11c9e5c Michael Hanselmann
  def _CheckTimers(self, now):
199 b11c9e5c Michael Hanselmann
    # TODO: Repeating timers
200 b11c9e5c Michael Hanselmann
    for timer in self._timer.itervalues():
201 b11c9e5c Michael Hanselmann
      if now < (timer.start + timer.interval):
202 b11c9e5c Michael Hanselmann
        continue
203 b11c9e5c Michael Hanselmann
204 b11c9e5c Michael Hanselmann
      timer.owner.OnTimer(timer.timer_id)
205 b11c9e5c Michael Hanselmann
206 b11c9e5c Michael Hanselmann
      # TODO: Repeating timers should not be removed
207 b11c9e5c Michael Hanselmann
      self._timer_remove.append(timer.timer_id)
208 b11c9e5c Michael Hanselmann
209 b14b975f Michael Hanselmann
  def _CallSignalWaiters(self, signum):
210 b14b975f Michael Hanselmann
    """Calls all signal waiters for a certain signal.
211 b14b975f Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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