r23792: convert Samba4 to GPLv3
[jelmer/samba4-debian.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 "includes.h"
27 #include "system/filesys.h"
28 #include "system/select.h"
29 #include "lib/util/dlinklist.h"
30 #include "lib/events/events.h"
31 #include "lib/events/events_internal.h"
32
33 struct select_event_context {
34         /* a pointer back to the generic event_context */
35         struct event_context *ev;
36
37         /* list of filedescriptor events */
38         struct fd_event *fd_events;
39
40         /* list of timed events */
41         struct timed_event *timed_events;
42
43         /* the maximum file descriptor number in fd_events */
44         int maxfd;
45
46         /* information for exiting from the event loop */
47         int exit_code;
48
49         /* this is incremented when the loop over events causes something which
50            could change the events yet to be processed */
51         uint32_t destruction_count;
52 };
53
54 /*
55   create a select_event_context structure.
56 */
57 static int select_event_context_init(struct event_context *ev)
58 {
59         struct select_event_context *select_ev;
60
61         select_ev = talloc_zero(ev, struct select_event_context);
62         if (!select_ev) return -1;
63         select_ev->ev = ev;
64
65         ev->additional_data = select_ev;
66         return 0;
67 }
68
69 /*
70   recalculate the maxfd
71 */
72 static void calc_maxfd(struct select_event_context *select_ev)
73 {
74         struct fd_event *fde;
75
76         select_ev->maxfd = 0;
77         for (fde = select_ev->fd_events; fde; fde = fde->next) {
78                 if (fde->fd > select_ev->maxfd) {
79                         select_ev->maxfd = fde->fd;
80                 }
81         }
82 }
83
84
85 /* to mark the ev->maxfd invalid
86  * this means we need to recalculate it
87  */
88 #define EVENT_INVALID_MAXFD (-1)
89
90 /*
91   destroy an fd_event
92 */
93 static int select_event_fd_destructor(struct fd_event *fde)
94 {
95         struct event_context *ev = fde->event_ctx;
96         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
97                                                            struct select_event_context);
98
99         if (select_ev->maxfd == fde->fd) {
100                 select_ev->maxfd = EVENT_INVALID_MAXFD;
101         }
102
103         DLIST_REMOVE(select_ev->fd_events, fde);
104         select_ev->destruction_count++;
105
106         if (fde->flags & EVENT_FD_AUTOCLOSE) {
107                 close(fde->fd);
108                 fde->fd = -1;
109         }
110
111         return 0;
112 }
113
114 /*
115   add a fd based event
116   return NULL on failure (memory allocation error)
117 */
118 static struct fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
119                                          int fd, uint16_t flags,
120                                          event_fd_handler_t handler,
121                                          void *private_data)
122 {
123         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
124                                                            struct select_event_context);
125         struct fd_event *fde;
126
127         fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
128         if (!fde) return NULL;
129
130         fde->event_ctx          = ev;
131         fde->fd                 = fd;
132         fde->flags              = flags;
133         fde->handler            = handler;
134         fde->private_data       = private_data;
135         fde->additional_flags   = 0;
136         fde->additional_data    = NULL;
137
138         DLIST_ADD(select_ev->fd_events, fde);
139         if (fde->fd > select_ev->maxfd) {
140                 select_ev->maxfd = fde->fd;
141         }
142         talloc_set_destructor(fde, select_event_fd_destructor);
143
144         return fde;
145 }
146
147
148 /*
149   return the fd event flags
150 */
151 static uint16_t select_event_get_fd_flags(struct fd_event *fde)
152 {
153         return fde->flags;
154 }
155
156 /*
157   set the fd event flags
158 */
159 static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
160 {
161         struct event_context *ev;
162         struct select_event_context *select_ev;
163
164         if (fde->flags == flags) return;
165
166         ev = fde->event_ctx;
167         select_ev = talloc_get_type(ev->additional_data, struct select_event_context);
168
169         fde->flags = flags;
170 }
171
172 /*
173   event loop handling using select()
174 */
175 static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
176 {
177         fd_set r_fds, w_fds;
178         struct fd_event *fde;
179         int selrtn;
180         uint32_t destruction_count = ++select_ev->destruction_count;
181
182         /* we maybe need to recalculate the maxfd */
183         if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
184                 calc_maxfd(select_ev);
185         }
186
187         FD_ZERO(&r_fds);
188         FD_ZERO(&w_fds);
189
190         /* setup any fd events */
191         for (fde = select_ev->fd_events; fde; fde = fde->next) {
192                 if (fde->flags & EVENT_FD_READ) {
193                         FD_SET(fde->fd, &r_fds);
194                 }
195                 if (fde->flags & EVENT_FD_WRITE) {
196                         FD_SET(fde->fd, &w_fds);
197                 }
198         }
199
200         if (select_ev->ev->num_signal_handlers && 
201             common_event_check_signal(select_ev->ev)) {
202                 return 0;
203         }
204
205         selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
206
207         if (selrtn == -1 && errno == EINTR && 
208             select_ev->ev->num_signal_handlers) {
209                 common_event_check_signal(select_ev->ev);
210                 return 0;
211         }
212
213         if (selrtn == -1 && errno == EBADF) {
214                 /* the socket is dead! this should never
215                    happen as the socket should have first been
216                    made readable and that should have removed
217                    the event, so this must be a bug. This is a
218                    fatal error. */
219                 DEBUG(0,("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 (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
302 #if _SAMBA_BUILD_
303 NTSTATUS s4_events_select_init(void)
304 {
305         if (!events_select_init()) {
306                 return NT_STATUS_INTERNAL_ERROR;
307         }
308         return NT_STATUS_OK;
309 }
310 #endif