tdb: Fix bug 7248, avoid the nanosleep dependency
[metze/ctdb/wip.git] / 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/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"
33
34 extern pid_t ctdbd_pid;
35
36 struct select_event_context {
37         /* a pointer back to the generic event_context */
38         struct event_context *ev;
39
40         /* list of filedescriptor events */
41         struct fd_event *fd_events;
42
43         /* list of timed events */
44         struct timed_event *timed_events;
45
46         /* the maximum file descriptor number in fd_events */
47         int maxfd;
48
49         /* information for exiting from the event loop */
50         int exit_code;
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
104         if (fde->flags & EVENT_FD_AUTOCLOSE) {
105                 close(fde->fd);
106                 fde->fd = -1;
107         }
108
109         return 0;
110 }
111
112 /*
113   add a fd based event
114   return NULL on failure (memory allocation error)
115 */
116 static struct fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
117                                          int fd, uint16_t flags,
118                                          event_fd_handler_t handler,
119                                          void *private_data)
120 {
121         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
122                                                            struct select_event_context);
123         struct fd_event *fde;
124
125         fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
126         if (!fde) return NULL;
127
128         fde->event_ctx          = ev;
129         fde->fd                 = fd;
130         fde->flags              = flags;
131         fde->handler            = handler;
132         fde->private_data       = private_data;
133         fde->additional_flags   = 0;
134         fde->additional_data    = NULL;
135
136         DLIST_ADD(select_ev->fd_events, fde);
137         if (fde->fd > select_ev->maxfd) {
138                 select_ev->maxfd = fde->fd;
139         }
140         talloc_set_destructor(fde, select_event_fd_destructor);
141
142         return fde;
143 }
144
145
146 /*
147   return the fd event flags
148 */
149 static uint16_t select_event_get_fd_flags(struct fd_event *fde)
150 {
151         return fde->flags;
152 }
153
154 /*
155   set the fd event flags
156 */
157 static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
158 {
159         struct event_context *ev;
160         struct select_event_context *select_ev;
161
162         if (fde->flags == flags) return;
163
164         ev = fde->event_ctx;
165         select_ev = talloc_get_type(ev->additional_data, struct select_event_context);
166
167         fde->flags = flags;
168 }
169
170 /*
171   event loop handling using select()
172 */
173 static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
174 {
175         fd_set r_fds, w_fds;
176         struct fd_event *fde;
177         int selrtn;
178
179         /* we maybe need to recalculate the maxfd */
180         if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
181                 calc_maxfd(select_ev);
182         }
183
184         FD_ZERO(&r_fds);
185         FD_ZERO(&w_fds);
186
187         /* setup any fd events */
188         for (fde = select_ev->fd_events; fde; fde = fde->next) {
189                 if (fde->flags & EVENT_FD_READ) {
190                         FD_SET(fde->fd, &r_fds);
191                 }
192                 if (fde->flags & EVENT_FD_WRITE) {
193                         FD_SET(fde->fd, &w_fds);
194                 }
195         }
196
197         if (select_ev->ev->num_signal_handlers && 
198             common_event_check_signal(select_ev->ev)) {
199                 return 0;
200         }
201
202         selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
203
204         if (selrtn == -1 && errno == EINTR && 
205             select_ev->ev->num_signal_handlers) {
206                 common_event_check_signal(select_ev->ev);
207                 return 0;
208         }
209
210         if (selrtn == -1 && errno == EBADF) {
211                 /* the socket is dead! this should never
212                    happen as the socket should have first been
213                    made readable and that should have removed
214                    the event, so this must be a bug. This is a
215                    fatal error. */
216                 DEBUG(0,("ERROR: EBADF on select_event_loop_once\n"));
217                 select_ev->exit_code = EBADF;
218                 return -1;
219         }
220
221         if (selrtn == 0 && tvalp) {
222                 /* we don't care about a possible delay here */
223                 common_event_loop_timer_delay(select_ev->ev);
224                 return 0;
225         }
226
227         if (selrtn > 0) {
228                 /* at least one file descriptor is ready - check
229                    which ones and call the handler, being careful to allow
230                    the handler to remove itself when called */
231                 for (fde = select_ev->fd_events; fde; fde = fde->next) {
232                         uint16_t flags = 0;
233
234                         if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ;
235                         if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
236                         if (flags) {
237                                 fde->handler(select_ev->ev, fde, flags, fde->private_data);
238                                 break;
239                         }
240                 }
241         }
242
243         return 0;
244 }               
245
246 /*
247   do a single event loop using the events defined in ev 
248 */
249 static int select_event_loop_once(struct event_context *ev)
250 {
251         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
252                                                            struct select_event_context);
253         struct timeval tval;
254
255         tval = common_event_loop_timer_delay(ev);
256         if (timeval_is_zero(&tval)) {
257                 return 0;
258         }
259
260         return select_event_loop_select(select_ev, &tval);
261 }
262
263 /*
264   return on failure or (with 0) if all fd events are removed
265 */
266 static int select_event_loop_wait(struct event_context *ev)
267 {
268         static time_t t=0;
269         time_t new_t;
270         struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
271                                                            struct select_event_context);
272         select_ev->exit_code = 0;
273
274         while (select_ev->fd_events && select_ev->exit_code == 0) {
275                 if (select_event_loop_once(ev) != 0) {
276                         break;
277                 }
278                 if (getpid() == ctdbd_pid) {
279                         new_t=time(NULL);
280                         if (t != 0) {
281                                 if (t > new_t) {
282                                         DEBUG(0,(__location__ " ERROR Time skipped backward by %d seconds\n", (int)(t-new_t)));
283                                 }
284                                 /* We assume here that we get at least one event every 5 seconds */
285                                 if (new_t > (t+5)) {
286                                         DEBUG(0,(__location__ " ERROR Time jumped forward by %d seconds\n", (int)(new_t-t)));
287                                 }
288                         }
289                         t=new_t;
290                 }
291         }
292
293         return select_ev->exit_code;
294 }
295
296 static const struct event_ops select_event_ops = {
297         .context_init   = select_event_context_init,
298         .add_fd         = select_event_add_fd,
299         .get_fd_flags   = select_event_get_fd_flags,
300         .set_fd_flags   = select_event_set_fd_flags,
301         .add_timed      = common_event_add_timed,
302         .add_signal     = common_event_add_signal,
303         .loop_once      = select_event_loop_once,
304         .loop_wait      = select_event_loop_wait,
305 };
306
307 bool events_select_init(void)
308 {
309         return event_register_backend("select", &select_event_ops);
310 }
311
312 #if _SAMBA_BUILD_
313 NTSTATUS s4_events_select_init(void)
314 {
315         if (!events_select_init()) {
316                 return NT_STATUS_INTERNAL_ERROR;
317         }
318         return NT_STATUS_OK;
319 }
320 #endif