This patch make it possible to build the events library completely
[Samba/aatanasov.git] / source4 / lib / events / events_select.c
blob9e97d2b39f2e002ddac035acba2c94df876bb493
1 /*
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
26 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/select.h"
29 #include "events.h"
30 #include "events_internal.h"
32 struct select_event_context {
33 /* a pointer back to the generic event_context */
34 struct event_context *ev;
36 /* list of filedescriptor events */
37 struct fd_event *fd_events;
39 /* list of timed events */
40 struct timed_event *timed_events;
42 /* the maximum file descriptor number in fd_events */
43 int maxfd;
45 /* information for exiting from the event loop */
46 int exit_code;
48 /* this is incremented when the loop over events causes something which
49 could change the events yet to be processed */
50 uint32_t destruction_count;
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;
62 select_ev->ev = ev;
64 ev->additional_data = select_ev;
65 return 0;
69 recalculate the maxfd
71 static void calc_maxfd(struct select_event_context *select_ev)
73 struct fd_event *fde;
75 select_ev->maxfd = 0;
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)
90 destroy an fd_event
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);
103 select_ev->destruction_count++;
105 if (fde->flags & EVENT_FD_AUTOCLOSE) {
106 close(fde->fd);
107 fde->fd = -1;
110 return 0;
114 add a fd based event
115 return NULL on failure (memory allocation error)
117 static struct fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
118 int fd, uint16_t flags,
119 event_fd_handler_t handler,
120 void *private_data)
122 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
123 struct select_event_context);
124 struct fd_event *fde;
126 fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
127 if (!fde) return NULL;
129 fde->event_ctx = ev;
130 fde->fd = fd;
131 fde->flags = flags;
132 fde->handler = handler;
133 fde->private_data = private_data;
134 fde->additional_flags = 0;
135 fde->additional_data = NULL;
137 DLIST_ADD(select_ev->fd_events, fde);
138 if (fde->fd > select_ev->maxfd) {
139 select_ev->maxfd = fde->fd;
141 talloc_set_destructor(fde, select_event_fd_destructor);
143 return fde;
148 return the fd event flags
150 static uint16_t select_event_get_fd_flags(struct fd_event *fde)
152 return fde->flags;
156 set the fd event flags
158 static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
160 struct event_context *ev;
161 struct select_event_context *select_ev;
163 if (fde->flags == flags) return;
165 ev = fde->event_ctx;
166 select_ev = talloc_get_type(ev->additional_data, struct select_event_context);
168 fde->flags = flags;
172 event loop handling using select()
174 static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
176 fd_set r_fds, w_fds;
177 struct fd_event *fde;
178 int selrtn;
179 uint32_t destruction_count = ++select_ev->destruction_count;
181 /* we maybe need to recalculate the maxfd */
182 if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
183 calc_maxfd(select_ev);
186 FD_ZERO(&r_fds);
187 FD_ZERO(&w_fds);
189 /* setup any fd events */
190 for (fde = select_ev->fd_events; fde; fde = fde->next) {
191 if (fde->flags & EVENT_FD_READ) {
192 FD_SET(fde->fd, &r_fds);
194 if (fde->flags & EVENT_FD_WRITE) {
195 FD_SET(fde->fd, &w_fds);
199 if (select_ev->ev->num_signal_handlers &&
200 common_event_check_signal(select_ev->ev)) {
201 return 0;
204 selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
206 if (selrtn == -1 && errno == EINTR &&
207 select_ev->ev->num_signal_handlers) {
208 common_event_check_signal(select_ev->ev);
209 return 0;
212 if (selrtn == -1 && errno == EBADF) {
213 /* the socket is dead! this should never
214 happen as the socket should have first been
215 made readable and that should have removed
216 the event, so this must be a bug. This is a
217 fatal error. */
218 ev_debug(select_ev->ev, EV_DEBUG_FATAL,
219 "ERROR: EBADF on select_event_loop_once\n");
220 select_ev->exit_code = EBADF;
221 return -1;
224 if (selrtn == 0 && tvalp) {
225 /* we don't care about a possible delay here */
226 common_event_loop_timer_delay(select_ev->ev);
227 return 0;
230 if (selrtn > 0) {
231 /* at least one file descriptor is ready - check
232 which ones and call the handler, being careful to allow
233 the handler to remove itself when called */
234 for (fde = select_ev->fd_events; fde; fde = fde->next) {
235 uint16_t flags = 0;
237 if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ;
238 if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
239 if (flags) {
240 fde->handler(select_ev->ev, fde, flags, fde->private_data);
241 if (destruction_count != select_ev->destruction_count) {
242 break;
248 return 0;
252 do a single event loop using the events defined in ev
254 static int select_event_loop_once(struct event_context *ev)
256 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
257 struct select_event_context);
258 struct timeval tval;
260 tval = common_event_loop_timer_delay(ev);
261 if (ev_timeval_is_zero(&tval)) {
262 return 0;
265 return select_event_loop_select(select_ev, &tval);
269 return on failure or (with 0) if all fd events are removed
271 static int select_event_loop_wait(struct event_context *ev)
273 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
274 struct select_event_context);
275 select_ev->exit_code = 0;
277 while (select_ev->fd_events && select_ev->exit_code == 0) {
278 if (select_event_loop_once(ev) != 0) {
279 break;
283 return select_ev->exit_code;
286 static const struct event_ops select_event_ops = {
287 .context_init = select_event_context_init,
288 .add_fd = select_event_add_fd,
289 .get_fd_flags = select_event_get_fd_flags,
290 .set_fd_flags = select_event_set_fd_flags,
291 .add_timed = common_event_add_timed,
292 .add_signal = common_event_add_signal,
293 .loop_once = select_event_loop_once,
294 .loop_wait = select_event_loop_wait,
297 bool events_select_init(void)
299 return event_register_backend("select", &select_event_ops);