Revision b14b975f
b/lib/daemon.py | ||
---|---|---|
34 | 34 |
|
35 | 35 |
""" |
36 | 36 |
def __init__(self): |
37 |
self._io_wait = [] |
|
37 |
"""Constructs a new Mainloop instance. |
|
38 |
|
|
39 |
""" |
|
40 |
self._io_wait = {} |
|
41 |
self._io_wait_add = [] |
|
42 |
self._io_wait_remove = [] |
|
38 | 43 |
self._signal_wait = [] |
39 |
self.sigchld_handler = None |
|
40 |
self.sigterm_handler = None |
|
41 |
self.quit = False |
|
42 | 44 |
|
43 |
def Run(self): |
|
44 |
# TODO: Does not yet support adding new event sources while running |
|
45 |
def Run(self, handle_sigchld=True, handle_sigterm=True, stop_on_empty=False): |
|
46 |
"""Runs the mainloop. |
|
47 |
|
|
48 |
@type handle_sigchld: bool |
|
49 |
@param handle_sigchld: Whether to install handler for SIGCHLD |
|
50 |
@type handle_sigterm: bool |
|
51 |
@param handle_sigterm: Whether to install handler for SIGTERM |
|
52 |
@type stop_on_empty: bool |
|
53 |
@param stop_on_empty: Whether to stop mainloop once all I/O waiters |
|
54 |
unregistered |
|
55 |
|
|
56 |
""" |
|
45 | 57 |
poller = select.poll() |
46 |
for (owner, fd, conditions) in self._io_wait: |
|
47 |
poller.register(fd, conditions) |
|
48 | 58 |
|
49 |
self.sigchld_handler = utils.SignalHandler([signal.SIGCHLD]) |
|
50 |
self.sigterm_handler = utils.SignalHandler([signal.SIGTERM]) |
|
59 |
# Setup signal handlers |
|
60 |
if handle_sigchld: |
|
61 |
sigchld_handler = utils.SignalHandler([signal.SIGCHLD]) |
|
62 |
else: |
|
63 |
sigchld_handler = None |
|
51 | 64 |
try: |
52 |
while not self.quit: |
|
53 |
try: |
|
54 |
io_events = poller.poll() |
|
55 |
except select.error, err: |
|
56 |
# EINTR can happen when signals are sent |
|
57 |
if err.args and err.args[0] in (errno.EINTR,): |
|
58 |
io_events = None |
|
59 |
else: |
|
60 |
raise |
|
61 |
|
|
62 |
if io_events: |
|
63 |
# Check for I/O events |
|
64 |
for (evfd, evcond) in io_events: |
|
65 |
for (owner, fd, conditions) in self._io_wait: |
|
66 |
if fd == evfd and evcond & conditions: |
|
67 |
owner.OnIO(fd, evcond) |
|
68 |
|
|
69 |
# Check whether signal was raised |
|
70 |
if self.sigchld_handler.called: |
|
71 |
for owner in self._signal_wait: |
|
72 |
owner.OnSignal(signal.SIGCHLD) |
|
73 |
self.sigchld_handler.Clear() |
|
74 |
|
|
75 |
if self.sigterm_handler.called: |
|
76 |
self.quit = True |
|
77 |
self.sigterm_handler.Clear() |
|
65 |
if handle_sigterm: |
|
66 |
sigterm_handler = utils.SignalHandler([signal.SIGTERM]) |
|
67 |
else: |
|
68 |
sigterm_handler = None |
|
69 |
|
|
70 |
try: |
|
71 |
running = True |
|
72 |
|
|
73 |
# Start actual main loop |
|
74 |
while running: |
|
75 |
# Entries could be added again afterwards, hence removing first |
|
76 |
if self._io_wait_remove: |
|
77 |
for fd in self._io_wait_remove: |
|
78 |
try: |
|
79 |
poller.unregister(fd) |
|
80 |
except KeyError: |
|
81 |
pass |
|
82 |
try: |
|
83 |
del self._io_wait[fd] |
|
84 |
except KeyError: |
|
85 |
pass |
|
86 |
self._io_wait_remove = [] |
|
87 |
|
|
88 |
# Add new entries |
|
89 |
if self._io_wait_add: |
|
90 |
for (owner, fd, conditions) in self._io_wait_add: |
|
91 |
self._io_wait[fd] = owner |
|
92 |
poller.register(fd, conditions) |
|
93 |
self._io_wait_add = [] |
|
94 |
|
|
95 |
# Stop if nothing is listening anymore |
|
96 |
if stop_on_empty and not self._io_wait: |
|
97 |
break |
|
98 |
|
|
99 |
# Wait for I/O events |
|
100 |
try: |
|
101 |
io_events = poller.poll() |
|
102 |
except select.error, err: |
|
103 |
# EINTR can happen when signals are sent |
|
104 |
if err.args and err.args[0] in (errno.EINTR,): |
|
105 |
io_events = None |
|
106 |
else: |
|
107 |
raise |
|
108 |
|
|
109 |
if io_events: |
|
110 |
# Check for I/O events |
|
111 |
for (evfd, evcond) in io_events: |
|
112 |
owner = self._io_wait.get(evfd, None) |
|
113 |
if owner: |
|
114 |
owner.OnIO(evfd, evcond) |
|
115 |
|
|
116 |
# Check whether signal was raised |
|
117 |
if sigchld_handler and sigchld_handler.called: |
|
118 |
self._CallSignalWaiters(signal.SIGCHLD) |
|
119 |
sigchld_handler.Clear() |
|
120 |
|
|
121 |
if sigterm_handler and sigterm_handler.called: |
|
122 |
self._CallSignalWaiters(signal.SIGTERM) |
|
123 |
running = False |
|
124 |
sigterm_handler.Clear() |
|
125 |
finally: |
|
126 |
# Restore signal handlers |
|
127 |
if sigterm_handler: |
|
128 |
sigterm_handler.Reset() |
|
78 | 129 |
finally: |
79 |
self.sigchld_handler.Reset() |
|
80 |
self.sigchld_handler = None |
|
81 |
self.sigterm_handler.Reset() |
|
82 |
self.sigterm_handler = None |
|
130 |
if sigchld_handler: |
|
131 |
sigchld_handler.Reset() |
|
83 | 132 |
|
133 |
def _CallSignalWaiters(self, signum): |
|
134 |
"""Calls all signal waiters for a certain signal. |
|
135 |
|
|
136 |
@type signum: int |
|
137 |
@param signum: Signal number |
|
138 |
|
|
139 |
""" |
|
140 |
for owner in self._signal_wait: |
|
141 |
owner.OnSignal(signal.SIGCHLD) |
|
84 | 142 |
|
85 | 143 |
def RegisterIO(self, owner, fd, condition): |
86 | 144 |
"""Registers a receiver for I/O notifications |
... | ... | |
96 | 154 |
(see select module) |
97 | 155 |
|
98 | 156 |
""" |
99 |
self._io_wait.append((owner, fd, condition)) |
|
157 |
# select.Poller also supports file() like objects, but we don't. |
|
158 |
assert isinstance(fd, (int, long)), \ |
|
159 |
"Only integers are supported for file descriptors" |
|
160 |
|
|
161 |
self._io_wait_add.append((owner, fd, condition)) |
|
162 |
|
|
163 |
def UnregisterIO(self, fd): |
|
164 |
"""Unregister a file descriptor. |
|
165 |
|
|
166 |
It'll be unregistered the next time the mainloop checks for it. |
|
167 |
|
|
168 |
@type fd: int |
|
169 |
@param fd: File descriptor |
|
170 |
|
|
171 |
""" |
|
172 |
# select.Poller also supports file() like objects, but we don't. |
|
173 |
assert isinstance(fd, (int, long)), \ |
|
174 |
"Only integers are supported for file descriptors" |
|
175 |
|
|
176 |
self._io_wait_remove.append(fd) |
|
100 | 177 |
|
101 | 178 |
def RegisterSignal(self, owner): |
102 | 179 |
"""Registers a receiver for signal notifications |
Also available in: Unified diff