This patch make it possible to build the events library completely
[metze/samba/wip.git] / source / lib / events / events_select.c
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
6    
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.
11    
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.
16    
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/>.
19 */
20
21 /*
22   This is SAMBA's default event loop code
23
24 */
25
26 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/select.h"
29 #include "events.h"
30 #include "events_internal.h"
31
32 struct select_event_context {
33         /* a pointer back to the generic event_context */
34         struct event_context *ev;
35
36         /* list of filedescriptor events */
37         struct fd_event *fd_events;
38
39         /* list of timed events */
40         struct timed_event *timed_events;
41
42         /* the maximum file descriptor number in fd_events */
43         int maxfd;
44
45         /* information for exiting from the event loop */
46         int exit_code;
47
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;
51 };
52
53 /*
54   create a select_event_context structure.
55 */
56 static int select_event_context_init(struct event_context *ev)
57 {
58         struct select_event_context *select_ev;
59
60         select_ev = talloc_zero(ev, struct select_event_context);
61         if (!select_ev) return -1;
62         select_ev->ev = ev;
63
64         ev->additional_data = select_ev;
65         return 0;
66 }
67
68 /*
69   recalculate the maxfd
70 */
71 static void calc_maxfd(struct select_event_context *select_ev)
72 {
73         struct fd_event *fde;
74
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;
79                 }
80         }
81 }
82
83
84 /* to mark the ev->maxfd invalid
85  * this means we need to recalculate it
86  */
87 #define EVENT_INVALID_MAXFD (-1)
88
89 /*
90   destroy an fd_event
91 */
92 static int select_event_fd_destructor(struct fd_event *fde)
93 {
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);
97
98         if (select_ev->maxfd == fde->fd) {
99                 select_ev->maxfd = EVENT_INVALID_MAXFD;
100         }
101
102         DLIST_REMOVE(select_ev->fd_events, fde);
103         select_ev->destruction_count++;
104
105         if (fde->flags & EVENT_FD_AUTOCLOSE) {
106                 close(fde->fd);
107                 fde->fd = -1;
108         }
109
110         return 0;
111 }
112
113 /*
114   add a fd based event
115   return NULL on failure (memory allocation error)
116 */
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)
121 {
122         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
123                                                            struct select_event_context);
124         struct fd_event *fde;
125
126         fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
127         if (!fde) return NULL;
128
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;
136
137         DLIST_ADD(select_ev->fd_events, fde);
138         if (fde->fd > select_ev->maxfd) {
139                 select_ev->maxfd = fde->fd;
140         }
141         talloc_set_destructor(fde, select_event_fd_destructor);
142
143         return fde;
144 }
145
146
147 /*
148   return the fd event flags
149 */
150 static uint16_t select_event_get_fd_flags(struct fd_event *fde)
151 {
152         return fde->flags;
153 }
154
155 /*
156   set the fd event flags
157 */
158 static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
159 {
160         struct event_context *ev;
161         struct select_event_context *select_ev;
162
163         if (fde->flags == flags) return;
164
165         ev = fde->event_ctx;
166         select_ev = talloc_get_type(ev->additional_data, struct select_event_context);
167
168         fde->flags = flags;
169 }
170
171 /*
172   event loop handling using select()
173 */
174 static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
175 {
176         fd_set r_fds, w_fds;
177         struct fd_event *fde;
178         int selrtn;
179         uint32_t destruction_count = ++select_ev->destruction_count;
180
181         /* we maybe need to recalculate the maxfd */
182         if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
183                 calc_maxfd(select_ev);
184         }
185
186         FD_ZERO(&r_fds);
187         FD_ZERO(&w_fds);
188
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);
193                 }
194                 if (fde->flags & EVENT_FD_WRITE) {
195                         FD_SET(fde->fd, &w_fds);
196                 }
197         }
198
199         if (select_ev->ev->num_signal_handlers && 
200             common_event_check_signal(select_ev->ev)) {
201                 return 0;
202         }
203
204         selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
205
206         if (selrtn == -1 && errno == EINTR && 
207             select_ev->ev->num_signal_handlers) {
208                 common_event_check_signal(select_ev->ev);
209                 return 0;
210         }
211
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;
222         }
223
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;
228         }
229
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;
236
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;
243                                 }
244                         }
245                 }
246         }
247
248         return 0;
249 }               
250
251 /*
252   do a single event loop using the events defined in ev 
253 */
254 static int select_event_loop_once(struct event_context *ev)
255 {
256         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
257                                                            struct select_event_context);
258         struct timeval tval;
259
260         tval = common_event_loop_timer_delay(ev);
261         if (ev_timeval_is_zero(&tval)) {
262                 return 0;
263         }
264
265         return select_event_loop_select(select_ev, &tval);
266 }
267
268 /*
269   return on failure or (with 0) if all fd events are removed
270 */
271 static int select_event_loop_wait(struct event_context *ev)
272 {
273         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
274                                                            struct select_event_context);
275         select_ev->exit_code = 0;
276
277         while (select_ev->fd_events && select_ev->exit_code == 0) {
278                 if (select_event_loop_once(ev) != 0) {
279                         break;
280                 }
281         }
282
283         return select_ev->exit_code;
284 }
285
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,
295 };
296
297 bool events_select_init(void)
298 {
299         return event_register_backend("select", &select_event_ops);
300 }
301