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,
40 struct poll_funcs_state {
42 * "watches" is the array of all watches that we have handed out via
43 * funcs->watch_new(). The "watches" array can contain NULL pointers.
45 struct poll_watch **watches;
48 * "contexts is the array of tevent_contexts that serve
49 * "watches". "contexts" can contain NULL pointers.
51 struct poll_funcs_tevent_context **contexts;
54 struct poll_funcs_tevent_context {
55 struct poll_funcs_tevent_handle *handles;
56 struct poll_funcs_state *state;
57 unsigned slot; /* index into state->contexts[] */
58 struct tevent_context *ev;
59 struct tevent_fd **fdes; /* same indexes as state->watches[] */
63 * poll_funcs_tevent_register() hands out a struct poll_funcs_tevent_handle as
64 * a void *. poll_funcs_tevent_register allows tevent_contexts to be
65 * registered multiple times, and we can't add a tevent_fd for the same fd's
66 * multiple times. So we have to share one poll_funcs_tevent_context.
68 struct poll_funcs_tevent_handle {
69 struct poll_funcs_tevent_handle *prev, *next;
70 struct poll_funcs_tevent_context *ctx;
73 static uint16_t poll_events_to_tevent(short events)
77 if (events & POLLIN) {
78 ret |= TEVENT_FD_READ;
80 if (events & POLLOUT) {
81 ret |= TEVENT_FD_WRITE;
86 static short tevent_to_poll_events(uint16_t flags)
90 if (flags & TEVENT_FD_READ) {
93 if (flags & TEVENT_FD_WRITE) {
100 * Find or create a free slot in state->watches[]
102 static bool poll_funcs_watch_find_slot(struct poll_funcs_state *state,
105 struct poll_watch **watches;
106 size_t i, num_watches, num_contexts;
108 num_watches = talloc_array_length(state->watches);
110 for (i=0; i<num_watches; i++) {
111 if (state->watches[i] == NULL) {
117 watches = talloc_realloc(state, state->watches, struct poll_watch *,
119 if (watches == NULL) {
122 watches[num_watches] = NULL;
123 state->watches = watches;
125 num_contexts = talloc_array_length(state->contexts);
127 for (i=0; i<num_contexts; i++) {
128 struct tevent_fd **fdes;
129 struct poll_funcs_tevent_context *c = state->contexts[i];
133 fdes = talloc_realloc(c, c->fdes, struct tevent_fd *,
136 state->watches = talloc_realloc(
137 state, state->watches, struct poll_watch *,
143 fdes[num_watches] = NULL;
151 static void poll_funcs_fde_handler(struct tevent_context *ev,
152 struct tevent_fd *fde, uint16_t flags,
154 static int poll_watch_destructor(struct poll_watch *w);
156 static struct poll_watch *tevent_watch_new(
157 const struct poll_funcs *funcs, int fd, short events,
158 void (*callback)(struct poll_watch *w, int fd, short events,
162 struct poll_funcs_state *state = talloc_get_type_abort(
163 funcs->private_data, struct poll_funcs_state);
164 struct poll_watch *w;
165 size_t i, slot, num_contexts;
167 if (!poll_funcs_watch_find_slot(state, &slot)) {
171 w = talloc(state->watches, struct poll_watch);
178 w->events = poll_events_to_tevent(events);
180 w->callback = callback;
181 w->private_data = private_data;
182 state->watches[slot] = w;
184 talloc_set_destructor(w, poll_watch_destructor);
186 num_contexts = talloc_array_length(state->contexts);
188 for (i=0; i<num_contexts; i++) {
189 struct poll_funcs_tevent_context *c = state->contexts[i];
193 c->fdes[slot] = tevent_add_fd(c->ev, c->fdes, w->fd, w->events,
194 poll_funcs_fde_handler, w);
195 if (c->fdes[slot] == NULL) {
206 static int poll_watch_destructor(struct poll_watch *w)
208 struct poll_funcs_state *state = w->state;
209 size_t num_contexts = talloc_array_length(state->contexts);
210 size_t slot = w->slot;
213 TALLOC_FREE(state->watches[slot]);
215 for (i=0; i<num_contexts; i++) {
216 struct poll_funcs_tevent_context *c = state->contexts[i];
220 TALLOC_FREE(c->fdes[slot]);
226 static void tevent_watch_update(struct poll_watch *w, short events)
228 struct poll_funcs_state *state = w->state;
229 size_t num_contexts = talloc_array_length(state->contexts);
230 size_t slot = w->slot;
233 w->events = poll_events_to_tevent(events);
235 for (i=0; i<num_contexts; i++) {
236 struct poll_funcs_tevent_context *c = state->contexts[i];
240 tevent_fd_set_flags(c->fdes[slot], w->events);
244 static short tevent_watch_get_events(struct poll_watch *w)
246 return tevent_to_poll_events(w->events);
249 static void tevent_watch_free(struct poll_watch *w)
254 static struct poll_timeout *tevent_timeout_new(
255 const struct poll_funcs *funcs, const struct timeval tv,
256 void (*callback)(struct poll_timeout *t, void *private_data),
259 /* not implemented yet */
263 static void tevent_timeout_update(struct poll_timeout *t,
264 const struct timeval tv)
269 static void tevent_timeout_free(struct poll_timeout *t)
274 static int poll_funcs_state_destructor(struct poll_funcs_state *state);
276 struct poll_funcs *poll_funcs_init_tevent(TALLOC_CTX *mem_ctx)
278 struct poll_funcs *f;
279 struct poll_funcs_state *state;
281 f = talloc(mem_ctx, struct poll_funcs);
285 state = talloc_zero(f, struct poll_funcs_state);
290 talloc_set_destructor(state, poll_funcs_state_destructor);
292 f->watch_new = tevent_watch_new;
293 f->watch_update = tevent_watch_update;
294 f->watch_get_events = tevent_watch_get_events;
295 f->watch_free = tevent_watch_free;
296 f->timeout_new = tevent_timeout_new;
297 f->timeout_update = tevent_timeout_update;
298 f->timeout_free = tevent_timeout_free;
299 f->private_data = state;
303 static int poll_funcs_state_destructor(struct poll_funcs_state *state)
305 size_t num_watches = talloc_array_length(state->watches);
308 * Make sure the watches are cleared before the contexts. The watches
309 * have destructors attached to them that clean up the fde's
311 for (i=0; i<num_watches; i++) {
312 TALLOC_FREE(state->watches[i]);
318 * Find or create a free slot in state->contexts[]
320 static bool poll_funcs_context_slot_find(struct poll_funcs_state *state,
321 struct tevent_context *ev,
324 struct poll_funcs_tevent_context **contexts;
325 size_t num_contexts = talloc_array_length(state->contexts);
328 for (i=0; i<num_contexts; i++) {
329 struct poll_funcs_tevent_context *ctx = state->contexts[i];
331 if ((ctx == NULL) || (ctx->ev == ev)) {
337 contexts = talloc_realloc(state, state->contexts,
338 struct poll_funcs_tevent_context *,
340 if (contexts == NULL) {
343 state->contexts = contexts;
344 state->contexts[num_contexts] = NULL;
346 *slot = num_contexts;
351 static int poll_funcs_tevent_context_destructor(
352 struct poll_funcs_tevent_context *ctx);
354 static struct poll_funcs_tevent_context *poll_funcs_tevent_context_new(
355 TALLOC_CTX *mem_ctx, struct poll_funcs_state *state,
356 struct tevent_context *ev, unsigned slot)
358 struct poll_funcs_tevent_context *ctx;
359 size_t num_watches = talloc_array_length(state->watches);
362 ctx = talloc(mem_ctx, struct poll_funcs_tevent_context);
372 ctx->fdes = talloc_array(ctx, struct tevent_fd *, num_watches);
373 if (ctx->fdes == NULL) {
377 for (i=0; i<num_watches; i++) {
378 struct poll_watch *w = state->watches[i];
384 ctx->fdes[i] = tevent_add_fd(ev, ctx->fdes, w->fd, w->events,
385 poll_funcs_fde_handler, w);
386 if (ctx->fdes[i] == NULL) {
390 talloc_set_destructor(ctx, poll_funcs_tevent_context_destructor);
397 static int poll_funcs_tevent_context_destructor(
398 struct poll_funcs_tevent_context *ctx)
400 struct poll_funcs_tevent_handle *h;
402 ctx->state->contexts[ctx->slot] = NULL;
404 for (h = ctx->handles; h != NULL; h = h->next) {
411 static void poll_funcs_fde_handler(struct tevent_context *ev,
412 struct tevent_fd *fde, uint16_t flags,
415 struct poll_watch *w = talloc_get_type_abort(
416 private_data, struct poll_watch);
417 short events = tevent_to_poll_events(flags);
418 w->callback(w, w->fd, events, w->private_data);
421 static int poll_funcs_tevent_handle_destructor(
422 struct poll_funcs_tevent_handle *handle);
424 void *poll_funcs_tevent_register(TALLOC_CTX *mem_ctx, struct poll_funcs *f,
425 struct tevent_context *ev)
427 struct poll_funcs_state *state = talloc_get_type_abort(
428 f->private_data, struct poll_funcs_state);
429 struct poll_funcs_tevent_handle *handle;
432 handle = talloc(mem_ctx, struct poll_funcs_tevent_handle);
433 if (handle == NULL) {
437 if (!poll_funcs_context_slot_find(state, ev, &slot)) {
440 if (state->contexts[slot] == NULL) {
441 state->contexts[slot] = poll_funcs_tevent_context_new(
442 state->contexts, state, ev, slot);
443 if (state->contexts[slot] == NULL) {
448 handle->ctx = state->contexts[slot];
449 DLIST_ADD(handle->ctx->handles, handle);
450 talloc_set_destructor(handle, poll_funcs_tevent_handle_destructor);
457 static int poll_funcs_tevent_handle_destructor(
458 struct poll_funcs_tevent_handle *handle)
460 if (handle->ctx == NULL) {
463 if (handle->ctx->handles == NULL) {
467 DLIST_REMOVE(handle->ctx->handles, handle);
469 if (handle->ctx->handles == NULL) {
470 TALLOC_FREE(handle->ctx);