s3:events: install a tevent debug handler that calls DEBUG()
[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                 return -1;
193         }
194
195         run_events(ev, ret, &r_fds, &w_fds);
196         return 0;
197 }
198
199 static int s3_event_loop_wait(struct tevent_context *ev)
200 {
201         int ret = 0;
202
203         while (ret == 0) {
204                 ret = s3_event_loop_once(ev);
205         }
206
207         return ret;
208 }
209
210 void event_context_reinit(struct tevent_context *ev)
211 {
212         tevent_common_context_destructor(ev);
213         return;
214 }
215
216 static int s3_event_context_init(struct tevent_context *ev)
217 {
218         return 0;
219 }
220
221 void dump_event_list(struct tevent_context *ev)
222 {
223         struct tevent_timer *te;
224         struct tevent_fd *fe;
225         struct timeval evt, now;
226
227         if (!ev) {
228                 return;
229         }
230
231         now = timeval_current();
232
233         DEBUG(10,("dump_event_list:\n"));
234
235         for (te = ev->timer_events; te; te = te->next) {
236
237                 evt = timeval_until(&now, &te->next_event);
238
239                 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
240                            te->handler_name,
241                            te,
242                            (int)evt.tv_sec,
243                            http_timestring(talloc_tos(), te->next_event.tv_sec)));
244         }
245
246         for (fe = ev->fd_events; fe; fe = fe->next) {
247
248                 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
249                            fe->fd,
250                            fe,
251                            fe->flags));
252         }
253 }
254
255 static const struct tevent_ops s3_event_ops = {
256         .context_init   = s3_event_context_init,
257         .add_fd         = tevent_common_add_fd,
258         .set_fd_close_fn= tevent_common_fd_set_close_fn,
259         .get_fd_flags   = tevent_common_fd_get_flags,
260         .set_fd_flags   = tevent_common_fd_set_flags,
261         .add_timer      = tevent_common_add_timer,
262         .loop_once      = s3_event_loop_once,
263         .loop_wait      = s3_event_loop_wait,
264 };
265
266 static bool s3_tevent_init(void)
267 {
268         static bool initialized;
269         if (initialized) {
270                 return true;
271         }
272         initialized = tevent_register_backend("s3", &s3_event_ops);
273         tevent_set_default_backend("s3");
274         return initialized;
275 }
276
277 /*
278   this is used to catch debug messages from events
279 */
280 static void s3_event_debug(void *context, enum tevent_debug_level level,
281                            const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
282
283 static void s3_event_debug(void *context, enum tevent_debug_level level,
284                            const char *fmt, va_list ap)
285 {
286         int samba_level = -1;
287         char *s = NULL;
288         switch (level) {
289         case TEVENT_DEBUG_FATAL:
290                 samba_level = 0;
291                 break;
292         case TEVENT_DEBUG_ERROR:
293                 samba_level = 1;
294                 break;
295         case TEVENT_DEBUG_WARNING:
296                 samba_level = 2;
297                 break;
298         case TEVENT_DEBUG_TRACE:
299                 samba_level = 5;
300                 break;
301
302         };
303         vasprintf(&s, fmt, ap);
304         if (!s) return;
305         DEBUG(samba_level, ("s3_event: %s", s));
306         free(s);
307 }
308
309 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
310 {
311         struct tevent_context *ev;
312
313         s3_tevent_init();
314
315         ev = tevent_context_init_byname(mem_ctx, "s3");
316         if (ev) {
317                 tevent_set_debug(ev, s3_event_debug, NULL);
318         }
319
320         return ev;
321 }
322