s3-utils/net_rpc_printer.c: print more info on write error
[Samba/gebeck_regimport.git] / source3 / lib / events.c
blobb0d3ce53626dede0caa6650574732d44ea8a880a
1 /*
2 Unix SMB/CIFS implementation.
3 Timed event library.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Volker Lendecke 2005-2007
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.
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.
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/>.
21 #include "includes.h"
22 #include "lib/tevent/tevent_internal.h"
23 #include "../lib/util/select.h"
24 #include "system/select.h"
26 struct tevent_poll_private {
28 * Index from file descriptor into the pollfd array
30 int *pollfd_idx;
33 * Cache for s3_event_loop_once to avoid reallocs
35 struct pollfd *pfds;
38 static struct tevent_poll_private *tevent_get_poll_private(
39 struct tevent_context *ev)
41 struct tevent_poll_private *state;
43 state = (struct tevent_poll_private *)ev->additional_data;
44 if (state == NULL) {
45 state = talloc_zero(ev, struct tevent_poll_private);
46 ev->additional_data = (void *)state;
47 if (state == NULL) {
48 DEBUG(10, ("talloc failed\n"));
51 return state;
54 static void count_fds(struct tevent_context *ev,
55 int *pnum_fds, int *pmax_fd)
57 struct tevent_fd *fde;
58 int num_fds = 0;
59 int max_fd = 0;
61 for (fde = ev->fd_events; fde != NULL; fde = fde->next) {
62 if (fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) {
63 num_fds += 1;
64 if (fde->fd > max_fd) {
65 max_fd = fde->fd;
69 *pnum_fds = num_fds;
70 *pmax_fd = max_fd;
73 bool event_add_to_poll_args(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
74 struct pollfd **pfds, int *pnum_pfds,
75 int *ptimeout)
77 struct tevent_poll_private *state;
78 struct tevent_fd *fde;
79 int i, num_fds, max_fd, num_pollfds, idx_len;
80 struct pollfd *fds;
81 struct timeval now, diff;
82 int timeout;
84 state = tevent_get_poll_private(ev);
85 if (state == NULL) {
86 return false;
88 count_fds(ev, &num_fds, &max_fd);
90 idx_len = max_fd+1;
92 if (talloc_array_length(state->pollfd_idx) < idx_len) {
93 state->pollfd_idx = talloc_realloc(
94 state, state->pollfd_idx, int, idx_len);
95 if (state->pollfd_idx == NULL) {
96 DEBUG(10, ("talloc_realloc failed\n"));
97 return false;
101 fds = *pfds;
102 num_pollfds = *pnum_pfds;
105 * The +1 is for the sys_poll calling convention. It expects
106 * an array 1 longer for the signal pipe
109 if (talloc_array_length(fds) < num_pollfds + num_fds + 1) {
110 fds = talloc_realloc(mem_ctx, fds, struct pollfd,
111 num_pollfds + num_fds + 1);
112 if (fds == NULL) {
113 DEBUG(10, ("talloc_realloc failed\n"));
114 return false;
118 memset(&fds[num_pollfds], 0, sizeof(struct pollfd) * num_fds);
121 * This needs tuning. We need to cope with multiple fde's for a file
122 * descriptor. The problem is that we need to re-use pollfd_idx across
123 * calls for efficiency. One way would be a direct bitmask that might
124 * be initialized quicker, but our bitmap_init implementation is
125 * pretty heavy-weight as well.
127 for (i=0; i<idx_len; i++) {
128 state->pollfd_idx[i] = -1;
131 for (fde = ev->fd_events; fde; fde = fde->next) {
132 struct pollfd *pfd;
134 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) == 0) {
135 continue;
138 if (state->pollfd_idx[fde->fd] == -1) {
140 * We haven't seen this fd yet. Allocate a new pollfd.
142 state->pollfd_idx[fde->fd] = num_pollfds;
143 pfd = &fds[num_pollfds];
144 num_pollfds += 1;
145 } else {
147 * We have already seen this fd. OR in the flags.
149 pfd = &fds[state->pollfd_idx[fde->fd]];
152 pfd->fd = fde->fd;
154 if (fde->flags & EVENT_FD_READ) {
155 pfd->events |= (POLLIN|POLLHUP);
157 if (fde->flags & EVENT_FD_WRITE) {
158 pfd->events |= POLLOUT;
161 *pfds = fds;
162 *pnum_pfds = num_pollfds;
164 if (ev->immediate_events != NULL) {
165 *ptimeout = 0;
166 return true;
168 if (ev->timer_events == NULL) {
169 *ptimeout = MIN(*ptimeout, INT_MAX);
170 return true;
173 now = timeval_current();
174 diff = timeval_until(&now, &ev->timer_events->next_event);
175 timeout = timeval_to_msec(diff);
177 if (timeout < *ptimeout) {
178 *ptimeout = timeout;
181 return true;
184 bool run_events_poll(struct tevent_context *ev, int pollrtn,
185 struct pollfd *pfds, int num_pfds)
187 struct tevent_poll_private *state;
188 int *pollfd_idx;
189 struct tevent_fd *fde;
190 struct timeval now;
192 if (ev->signal_events &&
193 tevent_common_check_signal(ev)) {
194 return true;
197 if (ev->immediate_events &&
198 tevent_common_loop_immediate(ev)) {
199 return true;
202 GetTimeOfDay(&now);
204 if ((ev->timer_events != NULL)
205 && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
206 /* this older events system did not auto-free timed
207 events on running them, and had a race condition
208 where the event could be called twice if the
209 talloc_free of the te happened after the callback
210 made a call which invoked the event loop. To avoid
211 this while still allowing old code which frees the
212 te, we need to create a temporary context which
213 will be used to ensure the te is freed. We also
214 remove the te from the timed event list before we
215 call the handler, to ensure we can't loop */
217 struct tevent_timer *te = ev->timer_events;
218 TALLOC_CTX *tmp_ctx = talloc_new(ev);
220 DEBUG(10, ("Running timed event \"%s\" %p\n",
221 ev->timer_events->handler_name, ev->timer_events));
223 DLIST_REMOVE(ev->timer_events, te);
224 talloc_steal(tmp_ctx, te);
226 te->handler(ev, te, now, te->private_data);
228 talloc_free(tmp_ctx);
229 return true;
232 if (pollrtn <= 0) {
234 * No fd ready
236 return false;
239 state = (struct tevent_poll_private *)ev->additional_data;
240 pollfd_idx = state->pollfd_idx;
242 for (fde = ev->fd_events; fde; fde = fde->next) {
243 struct pollfd *pfd;
244 uint16 flags = 0;
246 if (pollfd_idx[fde->fd] >= num_pfds) {
247 DEBUG(1, ("internal error: pollfd_idx[fde->fd] (%d) "
248 ">= num_pfds (%d)\n", pollfd_idx[fde->fd],
249 num_pfds));
250 return false;
252 pfd = &pfds[pollfd_idx[fde->fd]];
254 if (pfd->fd != fde->fd) {
255 DEBUG(1, ("internal error: pfd->fd (%d) "
256 "!= fde->fd (%d)\n", pollfd_idx[fde->fd],
257 num_pfds));
258 return false;
261 if (pfd->revents & (POLLHUP|POLLERR)) {
262 /* If we only wait for EVENT_FD_WRITE, we
263 should not tell the event handler about it,
264 and remove the writable flag, as we only
265 report errors when waiting for read events
266 to match the select behavior. */
267 if (!(fde->flags & EVENT_FD_READ)) {
268 EVENT_FD_NOT_WRITEABLE(fde);
269 continue;
271 flags |= EVENT_FD_READ;
274 if (pfd->revents & POLLIN) {
275 flags |= EVENT_FD_READ;
277 if (pfd->revents & POLLOUT) {
278 flags |= EVENT_FD_WRITE;
280 if (flags & fde->flags) {
281 DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
282 fde->handler(ev, fde, flags, fde->private_data);
283 return true;
287 return false;
290 struct timeval *get_timed_events_timeout(struct tevent_context *ev,
291 struct timeval *to_ret)
293 struct timeval now;
295 if ((ev->timer_events == NULL) && (ev->immediate_events == NULL)) {
296 return NULL;
298 if (ev->immediate_events != NULL) {
299 *to_ret = timeval_zero();
300 return to_ret;
303 now = timeval_current();
304 *to_ret = timeval_until(&now, &ev->timer_events->next_event);
306 DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
307 (int)to_ret->tv_usec));
309 return to_ret;
312 static int s3_event_loop_once(struct tevent_context *ev, const char *location)
314 struct tevent_poll_private *state;
315 int timeout;
316 int num_pfds;
317 int ret;
319 timeout = INT_MAX;
321 state = tevent_get_poll_private(ev);
322 if (state == NULL) {
323 errno = ENOMEM;
324 return -1;
327 if (run_events_poll(ev, 0, NULL, 0)) {
328 return 0;
331 num_pfds = 0;
332 if (!event_add_to_poll_args(ev, state,
333 &state->pfds, &num_pfds, &timeout)) {
334 return -1;
337 ret = sys_poll(state->pfds, num_pfds, timeout);
338 if (ret == -1 && errno != EINTR) {
339 tevent_debug(ev, TEVENT_DEBUG_FATAL,
340 "poll() failed: %d:%s\n",
341 errno, strerror(errno));
342 return -1;
345 run_events_poll(ev, ret, state->pfds, num_pfds);
346 return 0;
349 static int s3_event_context_init(struct tevent_context *ev)
351 return 0;
354 void dump_event_list(struct tevent_context *ev)
356 struct tevent_timer *te;
357 struct tevent_fd *fe;
358 struct timeval evt, now;
360 if (!ev) {
361 return;
364 now = timeval_current();
366 DEBUG(10,("dump_event_list:\n"));
368 for (te = ev->timer_events; te; te = te->next) {
370 evt = timeval_until(&now, &te->next_event);
372 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
373 te->handler_name,
375 (int)evt.tv_sec,
376 http_timestring(talloc_tos(), te->next_event.tv_sec)));
379 for (fe = ev->fd_events; fe; fe = fe->next) {
381 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
382 fe->fd,
384 fe->flags));
388 static const struct tevent_ops s3_event_ops = {
389 .context_init = s3_event_context_init,
390 .add_fd = tevent_common_add_fd,
391 .set_fd_close_fn = tevent_common_fd_set_close_fn,
392 .get_fd_flags = tevent_common_fd_get_flags,
393 .set_fd_flags = tevent_common_fd_set_flags,
394 .add_timer = tevent_common_add_timer,
395 .schedule_immediate = tevent_common_schedule_immediate,
396 .add_signal = tevent_common_add_signal,
397 .loop_once = s3_event_loop_once,
398 .loop_wait = tevent_common_loop_wait,
401 static bool s3_tevent_init(void)
403 static bool initialized;
404 if (initialized) {
405 return true;
407 initialized = tevent_register_backend("s3", &s3_event_ops);
408 tevent_set_default_backend("s3");
409 return initialized;
413 this is used to catch debug messages from events
415 static void s3_event_debug(void *context, enum tevent_debug_level level,
416 const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
418 static void s3_event_debug(void *context, enum tevent_debug_level level,
419 const char *fmt, va_list ap)
421 int samba_level = -1;
422 char *s = NULL;
423 switch (level) {
424 case TEVENT_DEBUG_FATAL:
425 samba_level = 0;
426 break;
427 case TEVENT_DEBUG_ERROR:
428 samba_level = 1;
429 break;
430 case TEVENT_DEBUG_WARNING:
431 samba_level = 2;
432 break;
433 case TEVENT_DEBUG_TRACE:
434 samba_level = 11;
435 break;
438 if (vasprintf(&s, fmt, ap) == -1) {
439 return;
441 DEBUG(samba_level, ("s3_event: %s", s));
442 free(s);
445 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
447 struct tevent_context *ev;
449 s3_tevent_init();
451 ev = tevent_context_init_byname(mem_ctx, "s3");
452 if (ev) {
453 tevent_set_debug(ev, s3_event_debug, NULL);
456 return ev;
459 struct idle_event {
460 struct timed_event *te;
461 struct timeval interval;
462 char *name;
463 bool (*handler)(const struct timeval *now, void *private_data);
464 void *private_data;
467 static void smbd_idle_event_handler(struct event_context *ctx,
468 struct timed_event *te,
469 struct timeval now,
470 void *private_data)
472 struct idle_event *event =
473 talloc_get_type_abort(private_data, struct idle_event);
475 TALLOC_FREE(event->te);
477 DEBUG(10,("smbd_idle_event_handler: %s %p called\n",
478 event->name, event->te));
480 if (!event->handler(&now, event->private_data)) {
481 DEBUG(10,("smbd_idle_event_handler: %s %p stopped\n",
482 event->name, event->te));
483 /* Don't repeat, delete ourselves */
484 TALLOC_FREE(event);
485 return;
488 DEBUG(10,("smbd_idle_event_handler: %s %p rescheduled\n",
489 event->name, event->te));
491 event->te = event_add_timed(ctx, event,
492 timeval_sum(&now, &event->interval),
493 smbd_idle_event_handler, event);
495 /* We can't do much but fail here. */
496 SMB_ASSERT(event->te != NULL);
499 struct idle_event *event_add_idle(struct event_context *event_ctx,
500 TALLOC_CTX *mem_ctx,
501 struct timeval interval,
502 const char *name,
503 bool (*handler)(const struct timeval *now,
504 void *private_data),
505 void *private_data)
507 struct idle_event *result;
508 struct timeval now = timeval_current();
510 result = talloc(mem_ctx, struct idle_event);
511 if (result == NULL) {
512 DEBUG(0, ("talloc failed\n"));
513 return NULL;
516 result->interval = interval;
517 result->handler = handler;
518 result->private_data = private_data;
520 if (!(result->name = talloc_asprintf(result, "idle_evt(%s)", name))) {
521 DEBUG(0, ("talloc failed\n"));
522 TALLOC_FREE(result);
523 return NULL;
526 result->te = event_add_timed(event_ctx, result,
527 timeval_sum(&now, &interval),
528 smbd_idle_event_handler, result);
529 if (result->te == NULL) {
530 DEBUG(0, ("event_add_timed failed\n"));
531 TALLOC_FREE(result);
532 return NULL;
535 DEBUG(10,("event_add_idle: %s %p\n", result->name, result->te));
536 return result;