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 */
52 /* this is incremented when the loop over events causes something which
53 could change the events yet to be processed */
54 uint32_t destruction_count;
58 create a select_event_context structure.
60 static int select_event_context_init(struct event_context *ev)
62 struct select_event_context *select_ev;
64 select_ev = talloc_zero(ev, struct select_event_context);
65 if (!select_ev) return -1;
68 ev->additional_data = select_ev;
75 static void calc_maxfd(struct select_event_context *select_ev)
80 for (fde = select_ev->fd_events; fde; fde = fde->next) {
81 if (fde->fd > select_ev->maxfd) {
82 select_ev->maxfd = fde->fd;
88 /* to mark the ev->maxfd invalid
89 * this means we need to recalculate it
91 #define EVENT_INVALID_MAXFD (-1)
96 static int select_event_fd_destructor(struct fd_event *fde)
98 struct event_context *ev = fde->event_ctx;
99 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
100 struct select_event_context);
102 if (select_ev->maxfd == fde->fd) {
103 select_ev->maxfd = EVENT_INVALID_MAXFD;
106 DLIST_REMOVE(select_ev->fd_events, fde);
107 select_ev->destruction_count++;
109 if (fde->flags & EVENT_FD_AUTOCLOSE) {
119 return NULL on failure (memory allocation error)
121 static struct fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
122 int fd, uint16_t flags,
123 event_fd_handler_t handler,
126 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
127 struct select_event_context);
128 struct fd_event *fde;
130 fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
131 if (!fde) return NULL;
136 fde->handler = handler;
137 fde->private_data = private_data;
138 fde->additional_flags = 0;
139 fde->additional_data = NULL;
141 DLIST_ADD(select_ev->fd_events, fde);
142 if (fde->fd > select_ev->maxfd) {
143 select_ev->maxfd = fde->fd;
145 talloc_set_destructor(fde, select_event_fd_destructor);
152 return the fd event flags
154 static uint16_t select_event_get_fd_flags(struct fd_event *fde)
160 set the fd event flags
162 static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
164 struct event_context *ev;
165 struct select_event_context *select_ev;
167 if (fde->flags == flags) return;
170 select_ev = talloc_get_type(ev->additional_data, struct select_event_context);
176 event loop handling using select()
178 static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
181 struct fd_event *fde;
183 uint32_t destruction_count = ++select_ev->destruction_count;
185 /* we maybe need to recalculate the maxfd */
186 if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
187 calc_maxfd(select_ev);
193 /* setup any fd events */
194 for (fde = select_ev->fd_events; fde; fde = fde->next) {
195 if (fde->flags & EVENT_FD_READ) {
196 FD_SET(fde->fd, &r_fds);
198 if (fde->flags & EVENT_FD_WRITE) {
199 FD_SET(fde->fd, &w_fds);
203 if (select_ev->ev->num_signal_handlers &&
204 common_event_check_signal(select_ev->ev)) {
208 selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
210 if (selrtn == -1 && errno == EINTR &&
211 select_ev->ev->num_signal_handlers) {
212 common_event_check_signal(select_ev->ev);
216 if (selrtn == -1 && errno == EBADF) {
217 /* the socket is dead! this should never
218 happen as the socket should have first been
219 made readable and that should have removed
220 the event, so this must be a bug. This is a
222 DEBUG(0,("ERROR: EBADF on select_event_loop_once\n"));
223 select_ev->exit_code = EBADF;
227 if (selrtn == 0 && tvalp) {
228 /* we don't care about a possible delay here */
229 common_event_loop_timer_delay(select_ev->ev);
234 /* at least one file descriptor is ready - check
235 which ones and call the handler, being careful to allow
236 the handler to remove itself when called */
237 for (fde = select_ev->fd_events; fde; fde = fde->next) {
240 if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ;
241 if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
243 fde->handler(select_ev->ev, fde, flags, fde->private_data);
253 do a single event loop using the events defined in ev
255 static int select_event_loop_once(struct event_context *ev)
257 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
258 struct select_event_context);
261 tval = common_event_loop_timer_delay(ev);
262 if (timeval_is_zero(&tval)) {
266 return select_event_loop_select(select_ev, &tval);
270 return on failure or (with 0) if all fd events are removed
272 static int select_event_loop_wait(struct event_context *ev)
276 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
277 struct select_event_context);
278 select_ev->exit_code = 0;
280 while (select_ev->fd_events && select_ev->exit_code == 0) {
281 if (select_event_loop_once(ev) != 0) {
284 if (getpid() == ctdbd_pid) {
288 DEBUG(0,(__location__ " ERROR Time skipped backward by %d seconds\n", (int)(t-new_t)));
290 /* We assume here that we get at least one event every 5 seconds */
292 DEBUG(0,(__location__ " ERROR Time jumped forward by %d seconds\n", (int)(new_t-t)));
299 return select_ev->exit_code;
302 static const struct event_ops select_event_ops = {
303 .context_init = select_event_context_init,
304 .add_fd = select_event_add_fd,
305 .get_fd_flags = select_event_get_fd_flags,
306 .set_fd_flags = select_event_set_fd_flags,
307 .add_timed = common_event_add_timed,
308 .add_signal = common_event_add_signal,
309 .loop_once = select_event_loop_once,
310 .loop_wait = select_event_loop_wait,
313 bool events_select_init(void)
315 return event_register_backend("select", &select_event_ops);
319 NTSTATUS s4_events_select_init(void)
321 if (!events_select_init()) {
322 return NT_STATUS_INTERNAL_ERROR;