2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003-2005
5 Copyright (C) Stefan Metzmacher 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 This is SAMBA's default event loop code
27 #include "system/time.h"
28 #include "system/filesys.h"
29 #include "system/select.h"
30 #include "lib/util/dlinklist.h"
31 #include "lib/events/events.h"
32 #include "lib/events/events_internal.h"
34 extern pid_t ctdbd_pid;
36 struct select_event_context {
37 /* a pointer back to the generic event_context */
38 struct event_context *ev;
40 /* list of filedescriptor events */
41 struct fd_event *fd_events;
43 /* list of timed events */
44 struct timed_event *timed_events;
46 /* the maximum file descriptor number in fd_events */
49 /* information for exiting from the event loop */
54 create a select_event_context structure.
56 static int select_event_context_init(struct event_context *ev)
58 struct select_event_context *select_ev;
60 select_ev = talloc_zero(ev, struct select_event_context);
61 if (!select_ev) return -1;
64 ev->additional_data = select_ev;
71 static void calc_maxfd(struct select_event_context *select_ev)
76 for (fde = select_ev->fd_events; fde; fde = fde->next) {
77 if (fde->fd > select_ev->maxfd) {
78 select_ev->maxfd = fde->fd;
84 /* to mark the ev->maxfd invalid
85 * this means we need to recalculate it
87 #define EVENT_INVALID_MAXFD (-1)
92 static int select_event_fd_destructor(struct fd_event *fde)
94 struct event_context *ev = fde->event_ctx;
95 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
96 struct select_event_context);
98 if (select_ev->maxfd == fde->fd) {
99 select_ev->maxfd = EVENT_INVALID_MAXFD;
102 DLIST_REMOVE(select_ev->fd_events, fde);
104 if (fde->flags & EVENT_FD_AUTOCLOSE) {
114 return NULL on failure (memory allocation error)
116 static struct fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
117 int fd, uint16_t flags,
118 event_fd_handler_t handler,
121 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
122 struct select_event_context);
123 struct fd_event *fde;
125 fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
126 if (!fde) return NULL;
131 fde->handler = handler;
132 fde->private_data = private_data;
133 fde->additional_flags = 0;
134 fde->additional_data = NULL;
136 DLIST_ADD(select_ev->fd_events, fde);
137 if (fde->fd > select_ev->maxfd) {
138 select_ev->maxfd = fde->fd;
140 talloc_set_destructor(fde, select_event_fd_destructor);
147 return the fd event flags
149 static uint16_t select_event_get_fd_flags(struct fd_event *fde)
155 set the fd event flags
157 static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
159 struct event_context *ev;
160 struct select_event_context *select_ev;
162 if (fde->flags == flags) return;
165 select_ev = talloc_get_type(ev->additional_data, struct select_event_context);
171 event loop handling using select()
173 static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
176 struct fd_event *fde;
179 /* we maybe need to recalculate the maxfd */
180 if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
181 calc_maxfd(select_ev);
187 /* setup any fd events */
188 for (fde = select_ev->fd_events; fde; fde = fde->next) {
189 if (fde->flags & EVENT_FD_READ) {
190 FD_SET(fde->fd, &r_fds);
192 if (fde->flags & EVENT_FD_WRITE) {
193 FD_SET(fde->fd, &w_fds);
197 if (select_ev->ev->num_signal_handlers &&
198 common_event_check_signal(select_ev->ev)) {
202 selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
204 if (selrtn == -1 && errno == EINTR &&
205 select_ev->ev->num_signal_handlers) {
206 common_event_check_signal(select_ev->ev);
210 if (selrtn == -1 && errno == EBADF) {
211 /* the socket is dead! this should never
212 happen as the socket should have first been
213 made readable and that should have removed
214 the event, so this must be a bug. This is a
216 DEBUG(0,("ERROR: EBADF on select_event_loop_once\n"));
217 select_ev->exit_code = EBADF;
221 if (selrtn == 0 && tvalp) {
222 /* we don't care about a possible delay here */
223 common_event_loop_timer_delay(select_ev->ev);
228 /* at least one file descriptor is ready - check
229 which ones and call the handler, being careful to allow
230 the handler to remove itself when called */
231 for (fde = select_ev->fd_events; fde; fde = fde->next) {
234 if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ;
235 if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
237 fde->handler(select_ev->ev, fde, flags, fde->private_data);
247 do a single event loop using the events defined in ev
249 static int select_event_loop_once(struct event_context *ev)
251 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
252 struct select_event_context);
255 tval = common_event_loop_timer_delay(ev);
256 if (timeval_is_zero(&tval)) {
260 return select_event_loop_select(select_ev, &tval);
264 return on failure or (with 0) if all fd events are removed
266 static int select_event_loop_wait(struct event_context *ev)
270 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
271 struct select_event_context);
272 select_ev->exit_code = 0;
274 while (select_ev->fd_events && select_ev->exit_code == 0) {
275 if (select_event_loop_once(ev) != 0) {
278 if (getpid() == ctdbd_pid) {
282 DEBUG(0,(__location__ " ERROR Time skipped backward by %d seconds\n", (int)(t-new_t)));
284 /* We assume here that we get at least one event every 5 seconds */
286 DEBUG(0,(__location__ " ERROR Time jumped forward by %d seconds\n", (int)(new_t-t)));
293 return select_ev->exit_code;
296 static const struct event_ops select_event_ops = {
297 .context_init = select_event_context_init,
298 .add_fd = select_event_add_fd,
299 .get_fd_flags = select_event_get_fd_flags,
300 .set_fd_flags = select_event_set_fd_flags,
301 .add_timed = common_event_add_timed,
302 .add_signal = common_event_add_signal,
303 .loop_once = select_event_loop_once,
304 .loop_wait = select_event_loop_wait,
307 bool events_select_init(void)
309 return event_register_backend("select", &select_event_ops);
313 NTSTATUS s4_events_select_init(void)
315 if (!events_select_init()) {
316 return NT_STATUS_INTERNAL_ERROR;