Merge Samba3 and Samba4 together
[amitay/samba.git] / source4 / 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_util.h"
31 #include "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                 ev_debug(select_ev->ev, EV_DEBUG_FATAL,
220                          "ERROR: EBADF on select_event_loop_once\n");
221                 select_ev->exit_code = EBADF;
222                 return -1;
223         }
224
225         if (selrtn == 0 && tvalp) {
226                 /* we don't care about a possible delay here */
227                 common_event_loop_timer_delay(select_ev->ev);
228                 return 0;
229         }
230
231         if (selrtn > 0) {
232                 /* at least one file descriptor is ready - check
233                    which ones and call the handler, being careful to allow
234                    the handler to remove itself when called */
235                 for (fde = select_ev->fd_events; fde; fde = fde->next) {
236                         uint16_t flags = 0;
237
238                         if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ;
239                         if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
240                         if (flags) {
241                                 fde->handler(select_ev->ev, fde, flags, fde->private_data);
242                                 if (destruction_count != select_ev->destruction_count) {
243                                         break;
244                                 }
245                         }
246                 }
247         }
248
249         return 0;
250 }               
251
252 /*
253   do a single event loop using the events defined in ev 
254 */
255 static int select_event_loop_once(struct event_context *ev)
256 {
257         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
258                                                            struct select_event_context);
259         struct timeval tval;
260
261         tval = common_event_loop_timer_delay(ev);
262         if (ev_timeval_is_zero(&tval)) {
263                 return 0;
264         }
265
266         return select_event_loop_select(select_ev, &tval);
267 }
268
269 /*
270   return on failure or (with 0) if all fd events are removed
271 */
272 static int select_event_loop_wait(struct event_context *ev)
273 {
274         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
275                                                            struct select_event_context);
276         select_ev->exit_code = 0;
277
278         while (select_ev->fd_events && select_ev->exit_code == 0) {
279                 if (select_event_loop_once(ev) != 0) {
280                         break;
281                 }
282         }
283
284         return select_ev->exit_code;
285 }
286
287 static const struct event_ops select_event_ops = {
288         .context_init   = select_event_context_init,
289         .add_fd         = select_event_add_fd,
290         .get_fd_flags   = select_event_get_fd_flags,
291         .set_fd_flags   = select_event_set_fd_flags,
292         .add_timed      = common_event_add_timed,
293         .add_signal     = common_event_add_signal,
294         .loop_once      = select_event_loop_once,
295         .loop_wait      = select_event_loop_wait,
296 };
297
298 bool events_select_init(void)
299 {
300         return event_register_backend("select", &select_event_ops);
301 }
302