2 * Unix SMB/CIFS implementation.
3 * Copyright (C) Volker Lendecke 2013,2014
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "poll_funcs_tevent.h"
21 #include "system/select.h"
22 #include "lib/util/dlinklist.h"
25 * A poll_watch is asked for by the engine using this library via
26 * funcs->watch_new(). It represents interest in "fd" becoming readable or
31 struct poll_funcs_state *state;
32 size_t slot; /* index into state->watches[] */
35 void (*callback)(struct poll_watch *w, int fd, short events,
41 struct poll_funcs_state *state;
42 size_t slot; /* index into state->timeouts[] */
44 void (*callback)(struct poll_timeout *t, void *private_data);
48 struct poll_funcs_state {
50 * "watches" is the array of all watches that we have handed out via
51 * funcs->watch_new(). The "watches" array can contain NULL pointers.
53 struct poll_watch **watches;
56 * Like "watches" for timeouts;
58 struct poll_timeout **timeouts;
61 * "contexts is the array of tevent_contexts that serve
62 * "watches". "contexts" can contain NULL pointers.
64 struct poll_funcs_tevent_context **contexts;
67 struct poll_funcs_tevent_context {
68 struct poll_funcs_tevent_handle *handles;
69 struct poll_funcs_state *state;
70 unsigned slot; /* index into state->contexts[] */
71 struct tevent_context *ev;
72 struct tevent_fd **fdes; /* same indexes as state->watches[] */
73 struct tevent_timer **timers; /* same indexes as state->timeouts[] */
77 * poll_funcs_tevent_register() hands out a struct poll_funcs_tevent_handle as
78 * a void *. poll_funcs_tevent_register allows tevent_contexts to be
79 * registered multiple times, and we can't add a tevent_fd for the same fd's
80 * multiple times. So we have to share one poll_funcs_tevent_context.
82 struct poll_funcs_tevent_handle {
83 struct poll_funcs_tevent_handle *prev, *next;
84 struct poll_funcs_tevent_context *ctx;
87 static uint16_t poll_events_to_tevent(short events)
91 if (events & POLLIN) {
92 ret |= TEVENT_FD_READ;
94 if (events & POLLOUT) {
95 ret |= TEVENT_FD_WRITE;
100 static short tevent_to_poll_events(uint16_t flags)
104 if (flags & TEVENT_FD_READ) {
107 if (flags & TEVENT_FD_WRITE) {
114 * Find or create a free slot in state->watches[]
116 static bool poll_funcs_watch_find_slot(struct poll_funcs_state *state,
119 struct poll_watch **watches;
120 size_t i, num_watches, num_contexts;
122 num_watches = talloc_array_length(state->watches);
124 for (i=0; i<num_watches; i++) {
125 if (state->watches[i] == NULL) {
131 watches = talloc_realloc(state, state->watches, struct poll_watch *,
133 if (watches == NULL) {
136 watches[num_watches] = NULL;
137 state->watches = watches;
139 num_contexts = talloc_array_length(state->contexts);
141 for (i=0; i<num_contexts; i++) {
142 struct tevent_fd **fdes;
143 struct poll_funcs_tevent_context *c = state->contexts[i];
147 fdes = talloc_realloc(c, c->fdes, struct tevent_fd *,
150 state->watches = talloc_realloc(
151 state, state->watches, struct poll_watch *,
157 fdes[num_watches] = NULL;
165 static void poll_funcs_fde_handler(struct tevent_context *ev,
166 struct tevent_fd *fde, uint16_t flags,
168 static int poll_watch_destructor(struct poll_watch *w);
170 static struct poll_watch *tevent_watch_new(
171 const struct poll_funcs *funcs, int fd, short events,
172 void (*callback)(struct poll_watch *w, int fd, short events,
176 struct poll_funcs_state *state = talloc_get_type_abort(
177 funcs->private_data, struct poll_funcs_state);
178 struct poll_watch *w;
179 size_t i, slot, num_contexts;
181 if (!poll_funcs_watch_find_slot(state, &slot)) {
185 w = talloc(state->watches, struct poll_watch);
192 w->events = poll_events_to_tevent(events);
194 w->callback = callback;
195 w->private_data = private_data;
196 state->watches[slot] = w;
198 talloc_set_destructor(w, poll_watch_destructor);
200 num_contexts = talloc_array_length(state->contexts);
202 for (i=0; i<num_contexts; i++) {
203 struct poll_funcs_tevent_context *c = state->contexts[i];
207 c->fdes[slot] = tevent_add_fd(c->ev, c->fdes, w->fd, w->events,
208 poll_funcs_fde_handler, w);
209 if (c->fdes[slot] == NULL) {
220 static int poll_watch_destructor(struct poll_watch *w)
222 struct poll_funcs_state *state = w->state;
223 size_t num_contexts = talloc_array_length(state->contexts);
224 size_t slot = w->slot;
227 TALLOC_FREE(state->watches[slot]);
229 for (i=0; i<num_contexts; i++) {
230 struct poll_funcs_tevent_context *c = state->contexts[i];
234 TALLOC_FREE(c->fdes[slot]);
240 static void tevent_watch_update(struct poll_watch *w, short events)
242 struct poll_funcs_state *state = w->state;
243 size_t num_contexts = talloc_array_length(state->contexts);
244 size_t slot = w->slot;
247 w->events = poll_events_to_tevent(events);
249 for (i=0; i<num_contexts; i++) {
250 struct poll_funcs_tevent_context *c = state->contexts[i];
254 tevent_fd_set_flags(c->fdes[slot], w->events);
258 static short tevent_watch_get_events(struct poll_watch *w)
260 return tevent_to_poll_events(w->events);
263 static void tevent_watch_free(struct poll_watch *w)
268 static bool poll_funcs_timeout_find_slot(struct poll_funcs_state *state,
271 struct poll_timeout **timeouts;
272 size_t i, num_timeouts, num_contexts;
274 num_timeouts = talloc_array_length(state->timeouts);
276 for (i=0; i<num_timeouts; i++) {
277 if (state->timeouts[i] == NULL) {
283 timeouts = talloc_realloc(state, state->timeouts,
284 struct poll_timeout *,
286 if (timeouts == NULL) {
289 timeouts[num_timeouts] = NULL;
290 state->timeouts = timeouts;
292 num_contexts = talloc_array_length(state->contexts);
294 for (i=0; i<num_contexts; i++) {
295 struct tevent_timer **timers;
296 struct poll_funcs_tevent_context *c = state->contexts[i];
300 timers = talloc_realloc(c, c->timers, struct tevent_timer *,
302 if (timers == NULL) {
303 state->timeouts = talloc_realloc(
304 state, state->timeouts, struct poll_timeout *,
310 timers[num_timeouts] = NULL;
313 *slot = num_timeouts;
318 static void poll_funcs_timer_handler(struct tevent_context *ev,
319 struct tevent_timer *te,
320 struct timeval current_time,
322 static int poll_timeout_destructor(struct poll_timeout *t);
324 static struct poll_timeout *tevent_timeout_new(
325 const struct poll_funcs *funcs, const struct timeval tv,
326 void (*callback)(struct poll_timeout *t, void *private_data),
329 struct poll_funcs_state *state = talloc_get_type_abort(
330 funcs->private_data, struct poll_funcs_state);
331 struct poll_timeout *t;
332 size_t i, slot, num_contexts;
334 if (!poll_funcs_timeout_find_slot(state, &slot)) {
338 t = talloc(state->timeouts, struct poll_timeout);
345 t->callback = callback;
346 t->private_data = private_data;
348 talloc_set_destructor(t, poll_timeout_destructor);
350 num_contexts = talloc_array_length(state->contexts);
352 for (i=0; i<num_contexts; i++) {
353 struct poll_funcs_tevent_context *c = state->contexts[i];
357 c->timers[slot] = tevent_add_timer(
358 c->ev, c->timers, tv, poll_funcs_timer_handler, t);
359 if (c->timers[slot] == NULL) {
370 static int poll_timeout_destructor(struct poll_timeout *t)
372 struct poll_funcs_state *state = t->state;
373 size_t num_contexts = talloc_array_length(state->contexts);
374 size_t slot = t->slot;
377 TALLOC_FREE(state->timeouts[slot]);
379 for (i=0; i<num_contexts; i++) {
380 struct poll_funcs_tevent_context *c = state->contexts[i];
384 TALLOC_FREE(c->timers[slot]);
390 static void poll_funcs_timer_handler(struct tevent_context *ev,
391 struct tevent_timer *te,
392 struct timeval current_time,
395 struct poll_timeout *t = talloc_get_type_abort(
396 private_data, struct poll_timeout);
397 struct poll_funcs_state *state = t->state;
398 size_t slot = t->slot;
399 size_t i, num_contexts;
401 num_contexts = talloc_array_length(state->contexts);
403 for (i=0; i<num_contexts; i++) {
404 struct poll_funcs_tevent_context *c = state->contexts[i];
408 TALLOC_FREE(c->timers[slot]);
411 t->callback(t, t->private_data);
414 static void tevent_timeout_update(struct poll_timeout *t,
415 const struct timeval tv)
417 struct poll_funcs_state *state = t->state;
418 size_t num_contexts = talloc_array_length(state->contexts);
419 size_t slot = t->slot;
422 for (i=0; i<num_contexts; i++) {
423 struct poll_funcs_tevent_context *c = state->contexts[i];
427 TALLOC_FREE(c->timers[slot]);
429 c->timers[slot] = tevent_add_timer(
430 c->ev, c->timers, tv, poll_funcs_timer_handler, t);
431 if (c->timers[slot] == NULL) {
433 * We just free'ed the space, why did this fail??
440 static void tevent_timeout_free(struct poll_timeout *t)
445 static int poll_funcs_state_destructor(struct poll_funcs_state *state);
447 struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx)
449 struct poll_funcs *f;
450 struct poll_funcs_state *state;
452 f = talloc(mem_ctx, struct poll_funcs);
456 state = talloc_zero(f, struct poll_funcs_state);
461 talloc_set_destructor(state, poll_funcs_state_destructor);
463 f->watch_new = tevent_watch_new;
464 f->watch_update = tevent_watch_update;
465 f->watch_get_events = tevent_watch_get_events;
466 f->watch_free = tevent_watch_free;
467 f->timeout_new = tevent_timeout_new;
468 f->timeout_update = tevent_timeout_update;
469 f->timeout_free = tevent_timeout_free;
470 f->private_data = state;
474 static int poll_funcs_state_destructor(struct poll_funcs_state *state)
476 size_t num_watches = talloc_array_length(state->watches);
477 size_t num_timeouts = talloc_array_length(state->timeouts);
478 size_t num_contexts = talloc_array_length(state->contexts);
481 * Make sure the watches are cleared before the contexts. The watches
482 * have destructors attached to them that clean up the fde's
484 for (i=0; i<num_watches; i++) {
485 TALLOC_FREE(state->watches[i]);
487 for (i=0; i<num_timeouts; i++) {
488 TALLOC_FREE(state->timeouts[i]);
490 for (i=0; i<num_contexts; i++) {
491 TALLOC_FREE(state->contexts[i]);
497 * Find or create a free slot in state->contexts[]
499 static bool poll_funcs_context_slot_find(struct poll_funcs_state *state,
500 struct tevent_context *ev,
503 struct poll_funcs_tevent_context **contexts;
504 size_t num_contexts = talloc_array_length(state->contexts);
507 /* Look for an existing match first. */
508 for (i=0; i<num_contexts; i++) {
509 struct poll_funcs_tevent_context *ctx = state->contexts[i];
511 if (ctx != NULL && ctx->ev == ev) {
517 /* Now look for a free slot. */
518 for (i=0; i<num_contexts; i++) {
519 struct poll_funcs_tevent_context *ctx = state->contexts[i];
527 contexts = talloc_realloc(state, state->contexts,
528 struct poll_funcs_tevent_context *,
530 if (contexts == NULL) {
533 state->contexts = contexts;
534 state->contexts[num_contexts] = NULL;
536 *slot = num_contexts;
541 static int poll_funcs_tevent_context_destructor(
542 struct poll_funcs_tevent_context *ctx);
544 static struct poll_funcs_tevent_context *poll_funcs_tevent_context_new(
545 TALLOC_CTX *mem_ctx, struct poll_funcs_state *state,
546 struct tevent_context *ev, unsigned slot)
548 struct poll_funcs_tevent_context *ctx;
549 size_t num_watches = talloc_array_length(state->watches);
550 size_t num_timeouts = talloc_array_length(state->timeouts);
553 ctx = talloc(mem_ctx, struct poll_funcs_tevent_context);
563 ctx->fdes = talloc_array(ctx, struct tevent_fd *, num_watches);
564 if (ctx->fdes == NULL) {
568 for (i=0; i<num_watches; i++) {
569 struct poll_watch *w = state->watches[i];
575 ctx->fdes[i] = tevent_add_fd(ev, ctx->fdes, w->fd, w->events,
576 poll_funcs_fde_handler, w);
577 if (ctx->fdes[i] == NULL) {
582 ctx->timers = talloc_array(ctx, struct tevent_timer *, num_timeouts);
583 if (ctx->timers == NULL) {
587 for (i=0; i<num_timeouts; i++) {
588 struct poll_timeout *t = state->timeouts[i];
591 ctx->timers[i] = NULL;
594 ctx->timers[i] = tevent_add_timer(ctx->ev, ctx->timers, t->tv,
595 poll_funcs_timer_handler, t);
596 if (ctx->timers[i] == 0) {
601 talloc_set_destructor(ctx, poll_funcs_tevent_context_destructor);
608 static int poll_funcs_tevent_context_destructor(
609 struct poll_funcs_tevent_context *ctx)
611 struct poll_funcs_tevent_handle *h;
613 ctx->state->contexts[ctx->slot] = NULL;
615 for (h = ctx->handles; h != NULL; h = h->next) {
622 static void poll_funcs_fde_handler(struct tevent_context *ev,
623 struct tevent_fd *fde, uint16_t flags,
626 struct poll_watch *w = talloc_get_type_abort(
627 private_data, struct poll_watch);
628 short events = tevent_to_poll_events(flags);
629 w->callback(w, w->fd, events, w->private_data);
632 static int poll_funcs_tevent_handle_destructor(
633 struct poll_funcs_tevent_handle *handle);
635 void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
636 struct tevent_context *ev)
638 struct poll_funcs_state *state = talloc_get_type_abort(
639 f->private_data, struct poll_funcs_state);
640 struct poll_funcs_tevent_handle *handle;
643 handle = talloc(mem_ctx, struct poll_funcs_tevent_handle);
644 if (handle == NULL) {
648 if (!poll_funcs_context_slot_find(state, ev, &slot)) {
651 if (state->contexts[slot] == NULL) {
652 state->contexts[slot] = poll_funcs_tevent_context_new(
653 state->contexts, state, ev, slot);
654 if (state->contexts[slot] == NULL) {
659 handle->ctx = state->contexts[slot];
660 DLIST_ADD(handle->ctx->handles, handle);
661 talloc_set_destructor(handle, poll_funcs_tevent_handle_destructor);
668 static int poll_funcs_tevent_handle_destructor(
669 struct poll_funcs_tevent_handle *handle)
671 if (handle->ctx == NULL) {
674 if (handle->ctx->handles == NULL) {
678 DLIST_REMOVE(handle->ctx->handles, handle);
680 if (handle->ctx->handles == NULL) {
681 TALLOC_FREE(handle->ctx);