s3:events: debug sys_select() errors
[samba.git] / source3 / lib / events.c
1 /*
2    Unix SMB/CIFS implementation.
3    Timed event library.
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Volker Lendecke 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 #include "includes.h"
22 #include <tevent_internal.h>
23
24 void event_fd_set_writeable(struct tevent_fd *fde)
25 {
26         TEVENT_FD_WRITEABLE(fde);
27 }
28
29 void event_fd_set_not_writeable(struct tevent_fd *fde)
30 {
31         TEVENT_FD_NOT_WRITEABLE(fde);
32 }
33
34 void event_fd_set_readable(struct tevent_fd *fde)
35 {
36         TEVENT_FD_READABLE(fde);
37 }
38
39 void event_fd_set_not_readable(struct tevent_fd *fde)
40 {
41         TEVENT_FD_NOT_READABLE(fde);
42 }
43
44 /*
45  * Return if there's something in the queue
46  */
47
48 bool event_add_to_select_args(struct tevent_context *ev,
49                               const struct timeval *now,
50                               fd_set *read_fds, fd_set *write_fds,
51                               struct timeval *timeout, int *maxfd)
52 {
53         struct tevent_fd *fde;
54         struct timeval diff;
55         bool ret = false;
56
57         for (fde = ev->fd_events; fde; fde = fde->next) {
58                 if (fde->flags & EVENT_FD_READ) {
59                         FD_SET(fde->fd, read_fds);
60                         ret = true;
61                 }
62                 if (fde->flags & EVENT_FD_WRITE) {
63                         FD_SET(fde->fd, write_fds);
64                         ret = true;
65                 }
66
67                 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
68                     && (fde->fd > *maxfd)) {
69                         *maxfd = fde->fd;
70                 }
71         }
72
73         if (ev->timer_events == NULL) {
74                 return ret;
75         }
76
77         diff = timeval_until(now, &ev->timer_events->next_event);
78         *timeout = timeval_min(timeout, &diff);
79
80         return true;
81 }
82
83 bool run_events(struct tevent_context *ev,
84                 int selrtn, fd_set *read_fds, fd_set *write_fds)
85 {
86         bool fired = false;
87         struct tevent_fd *fde, *next;
88
89         /* Run all events that are pending, not just one (as we
90            did previously. */
91
92         while (ev->timer_events) {
93                 struct timeval now;
94                 GetTimeOfDay(&now);
95
96                 if (timeval_compare(
97                             &now, &ev->timer_events->next_event) < 0) {
98                         /* Nothing to do yet */
99                         DEBUG(11, ("run_events: Nothing to do\n"));
100                         break;
101                 }
102
103                 DEBUG(10, ("Running event \"%s\" %p\n",
104                            ev->timer_events->handler_name,
105                            ev->timer_events));
106
107                 ev->timer_events->handler(
108                         ev,
109                         ev->timer_events, now,
110                         ev->timer_events->private_data);
111
112                 fired = true;
113         }
114
115         if (fired) {
116                 /*
117                  * We might have changed the socket status during the timed
118                  * events, return to run select again.
119                  */
120                 return true;
121         }
122
123         if (selrtn == 0) {
124                 /*
125                  * No fd ready
126                  */
127                 return fired;
128         }
129
130         for (fde = ev->fd_events; fde; fde = next) {
131                 uint16 flags = 0;
132
133                 next = fde->next;
134                 if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
135                 if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
136
137                 if (flags & fde->flags) {
138                         fde->handler(ev, fde, flags, fde->private_data);
139                         fired = true;
140                 }
141         }
142
143         return fired;
144 }
145
146
147 struct timeval *get_timed_events_timeout(struct tevent_context *ev,
148                                          struct timeval *to_ret)
149 {
150         struct timeval now;
151
152         if (ev->timer_events == NULL) {
153                 return NULL;
154         }
155
156         now = timeval_current();
157         *to_ret = timeval_until(&now, &ev->timer_events->next_event);
158
159         DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
160                 (int)to_ret->tv_usec));
161
162         return to_ret;
163 }
164
165 static int s3_event_loop_once(struct tevent_context *ev)
166 {
167         struct timeval now, to;
168         fd_set r_fds, w_fds;
169         int maxfd = 0;
170         int ret;
171
172         FD_ZERO(&r_fds);
173         FD_ZERO(&w_fds);
174
175         to.tv_sec = 9999;       /* Max timeout */
176         to.tv_usec = 0;
177
178         GetTimeOfDay(&now);
179
180         if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
181                 return -1;
182         }
183
184         if (timeval_is_zero(&to)) {
185                 run_events(ev, 0, NULL, NULL);
186                 return 0;
187         }
188
189         ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
190
191         if (ret == -1 && errno != EINTR) {
192                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
193                              "sys_select() failed: %d:%s\n",
194                              errno, strerror(errno));
195                 return -1;
196         }
197
198         run_events(ev, ret, &r_fds, &w_fds);
199         return 0;
200 }
201
202 static int s3_event_loop_wait(struct tevent_context *ev)
203 {
204         int ret = 0;
205
206         while (ret == 0) {
207                 ret = s3_event_loop_once(ev);
208         }
209
210         return ret;
211 }
212
213 void event_context_reinit(struct tevent_context *ev)
214 {
215         tevent_common_context_destructor(ev);
216         return;
217 }
218
219 static int s3_event_context_init(struct tevent_context *ev)
220 {
221         return 0;
222 }
223
224 void dump_event_list(struct tevent_context *ev)
225 {
226         struct tevent_timer *te;
227         struct tevent_fd *fe;
228         struct timeval evt, now;
229
230         if (!ev) {
231                 return;
232         }
233
234         now = timeval_current();
235
236         DEBUG(10,("dump_event_list:\n"));
237
238         for (te = ev->timer_events; te; te = te->next) {
239
240                 evt = timeval_until(&now, &te->next_event);
241
242                 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
243                            te->handler_name,
244                            te,
245                            (int)evt.tv_sec,
246                            http_timestring(talloc_tos(), te->next_event.tv_sec)));
247         }
248
249         for (fe = ev->fd_events; fe; fe = fe->next) {
250
251                 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
252                            fe->fd,
253                            fe,
254                            fe->flags));
255         }
256 }
257
258 static const struct tevent_ops s3_event_ops = {
259         .context_init   = s3_event_context_init,
260         .add_fd         = tevent_common_add_fd,
261         .set_fd_close_fn= tevent_common_fd_set_close_fn,
262         .get_fd_flags   = tevent_common_fd_get_flags,
263         .set_fd_flags   = tevent_common_fd_set_flags,
264         .add_timer      = tevent_common_add_timer,
265         .loop_once      = s3_event_loop_once,
266         .loop_wait      = s3_event_loop_wait,
267 };
268
269 static bool s3_tevent_init(void)
270 {
271         static bool initialized;
272         if (initialized) {
273                 return true;
274         }
275         initialized = tevent_register_backend("s3", &s3_event_ops);
276         tevent_set_default_backend("s3");
277         return initialized;
278 }
279
280 /*
281   this is used to catch debug messages from events
282 */
283 static void s3_event_debug(void *context, enum tevent_debug_level level,
284                            const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
285
286 static void s3_event_debug(void *context, enum tevent_debug_level level,
287                            const char *fmt, va_list ap)
288 {
289         int samba_level = -1;
290         char *s = NULL;
291         switch (level) {
292         case TEVENT_DEBUG_FATAL:
293                 samba_level = 0;
294                 break;
295         case TEVENT_DEBUG_ERROR:
296                 samba_level = 1;
297                 break;
298         case TEVENT_DEBUG_WARNING:
299                 samba_level = 2;
300                 break;
301         case TEVENT_DEBUG_TRACE:
302                 samba_level = 5;
303                 break;
304
305         };
306         vasprintf(&s, fmt, ap);
307         if (!s) return;
308         DEBUG(samba_level, ("s3_event: %s", s));
309         free(s);
310 }
311
312 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
313 {
314         struct tevent_context *ev;
315
316         s3_tevent_init();
317
318         ev = tevent_context_init_byname(mem_ctx, "s3");
319         if (ev) {
320                 tevent_set_debug(ev, s3_event_debug, NULL);
321         }
322
323         return ev;
324 }
325