2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003-2005
5 Copyright (C) Stefan Metzmacher 2005-2009
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include "system/filesys.h"
27 #include "system/select.h"
29 #include "tevent_util.h"
30 #include "tevent_internal.h"
32 struct poll_event_context {
33 /* a pointer back to the generic event_context */
34 struct tevent_context *ev;
37 * A DLIST for fresh fde's
39 struct tevent_fd *fresh;
42 * These two arrays are maintained together.
45 struct tevent_fd **fdes;
48 /* information for exiting from the event loop */
53 create a select_event_context structure.
55 static int poll_event_context_init(struct tevent_context *ev)
57 struct poll_event_context *poll_ev;
59 poll_ev = talloc_zero(ev, struct poll_event_context);
60 if (poll_ev == NULL) {
64 ev->additional_data = poll_ev;
71 static int poll_event_fd_destructor(struct tevent_fd *fde)
73 struct tevent_context *ev = fde->event_ctx;
74 struct poll_event_context *poll_ev = NULL;
75 uint64_t del_idx = fde->additional_flags;
81 poll_ev = talloc_get_type_abort(
82 ev->additional_data, struct poll_event_context);
84 poll_ev->fdes[del_idx] = NULL;
86 return tevent_common_fd_destructor(fde);
89 static int poll_fresh_fde_destructor(struct tevent_fd *fde)
91 struct poll_event_context *poll_ev = talloc_get_type_abort(
92 fde->event_ctx->additional_data, struct poll_event_context);
93 DLIST_REMOVE(poll_ev->fresh, fde);
99 return NULL on failure (memory allocation error)
101 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
103 int fd, uint16_t flags,
104 tevent_fd_handler_t handler,
106 const char *handler_name,
107 const char *location)
109 struct poll_event_context *poll_ev = talloc_get_type_abort(
110 ev->additional_data, struct poll_event_context);
111 struct tevent_fd *fde;
117 fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
124 fde->handler = handler;
125 fde->close_fn = NULL;
126 fde->private_data = private_data;
127 fde->handler_name = handler_name;
128 fde->location = location;
129 fde->additional_flags = 0;
130 fde->additional_data = NULL;
132 DLIST_ADD(poll_ev->fresh, fde);
133 talloc_set_destructor(fde, poll_fresh_fde_destructor);
136 * poll_event_loop_poll will take care of the rest in
137 * poll_event_setup_fresh
143 set the fd event flags
145 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
147 struct poll_event_context *poll_ev = talloc_get_type_abort(
148 fde->event_ctx->additional_data, struct poll_event_context);
149 uint64_t idx = fde->additional_flags;
150 uint16_t pollflags = 0;
152 if (flags & TEVENT_FD_READ) {
153 pollflags |= (POLLIN|POLLHUP);
155 if (flags & TEVENT_FD_WRITE) {
156 pollflags |= (POLLOUT);
159 poll_ev->fds[idx].events = pollflags;
164 static bool poll_event_setup_fresh(struct tevent_context *ev,
165 struct poll_event_context *poll_ev)
167 struct tevent_fd *fde, *next;
168 unsigned num_fresh, num_fds;
170 if (poll_ev->fresh == NULL) {
175 for (fde = poll_ev->fresh; fde; fde = fde->next) {
178 num_fds = poll_ev->num_fds + num_fresh;
181 * We check the length of fdes here. It is the last one
182 * enlarged, so if the realloc for poll_fd->fdes fails,
183 * poll_fd->fds will have at least the size of poll_fd->fdes
186 if (num_fds >= talloc_array_length(poll_ev->fdes)) {
187 struct pollfd *tmp_fds;
188 struct tevent_fd **tmp_fdes;
189 unsigned array_length;
191 array_length = (num_fds + 15) & ~15; /* round up to 16 */
193 tmp_fds = talloc_realloc(
194 poll_ev, poll_ev->fds, struct pollfd, array_length);
195 if (tmp_fds == NULL) {
198 poll_ev->fds = tmp_fds;
200 tmp_fdes = talloc_realloc(
201 poll_ev, poll_ev->fdes, struct tevent_fd *,
203 if (tmp_fdes == NULL) {
206 poll_ev->fdes = tmp_fdes;
209 for (fde = poll_ev->fresh; fde; fde = next) {
212 pfd = &poll_ev->fds[poll_ev->num_fds];
218 if (fde->flags & TEVENT_FD_READ) {
219 pfd->events |= (POLLIN|POLLHUP);
221 if (fde->flags & TEVENT_FD_WRITE) {
222 pfd->events |= (POLLOUT);
225 fde->additional_flags = poll_ev->num_fds;
226 poll_ev->fdes[poll_ev->num_fds] = fde;
229 DLIST_REMOVE(poll_ev->fresh, fde);
230 DLIST_ADD(ev->fd_events, fde);
232 talloc_set_destructor(fde, poll_event_fd_destructor);
234 poll_ev->num_fds += 1;
240 event loop handling using poll()
242 static int poll_event_loop_poll(struct tevent_context *ev,
243 struct timeval *tvalp)
245 struct poll_event_context *poll_ev = talloc_get_type_abort(
246 ev->additional_data, struct poll_event_context);
251 if (ev->signal_events && tevent_common_check_signal(ev)) {
256 timeout = tvalp->tv_sec * 1000;
257 timeout += (tvalp->tv_usec + 999) / 1000;
260 if (!poll_event_setup_fresh(ev, poll_ev)) {
264 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
265 pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
266 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
268 if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
269 tevent_common_check_signal(ev);
273 if (pollrtn == 0 && tvalp) {
274 /* we don't care about a possible delay here */
275 tevent_common_loop_timer_delay(ev);
286 /* at least one file descriptor is ready - check
287 which ones and call the handler, being careful to allow
288 the handler to remove itself when called */
290 for (i=0; i<poll_ev->num_fds; i++) {
292 struct tevent_fd *fde;
295 fde = poll_ev->fdes[i];
298 * This fde was talloc_free()'ed. Delete it
301 poll_ev->num_fds -= 1;
302 poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
303 poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
304 if (poll_ev->fdes[i] != NULL) {
305 poll_ev->fdes[i]->additional_flags = i;
310 pfd = &poll_ev->fds[i];
312 if (pfd->revents & (POLLHUP|POLLERR)) {
313 /* If we only wait for TEVENT_FD_WRITE, we
314 should not tell the event handler about it,
315 and remove the writable flag, as we only
316 report errors when waiting for read events
317 to match the select behavior. */
318 if (!(fde->flags & TEVENT_FD_READ)) {
319 TEVENT_FD_NOT_WRITEABLE(fde);
322 flags |= TEVENT_FD_READ;
324 if (pfd->revents & POLLIN) {
325 flags |= TEVENT_FD_READ;
327 if (pfd->revents & POLLOUT) {
328 flags |= TEVENT_FD_WRITE;
331 fde->handler(ev, fde, flags, fde->private_data);
340 do a single event loop using the events defined in ev
342 static int poll_event_loop_once(struct tevent_context *ev,
343 const char *location)
347 if (ev->signal_events &&
348 tevent_common_check_signal(ev)) {
352 if (ev->immediate_events &&
353 tevent_common_loop_immediate(ev)) {
357 tval = tevent_common_loop_timer_delay(ev);
358 if (tevent_timeval_is_zero(&tval)) {
362 return poll_event_loop_poll(ev, &tval);
365 static const struct tevent_ops poll_event_ops = {
366 .context_init = poll_event_context_init,
367 .add_fd = poll_event_add_fd,
368 .set_fd_close_fn = tevent_common_fd_set_close_fn,
369 .get_fd_flags = tevent_common_fd_get_flags,
370 .set_fd_flags = poll_event_set_fd_flags,
371 .add_timer = tevent_common_add_timer,
372 .schedule_immediate = tevent_common_schedule_immediate,
373 .add_signal = tevent_common_add_signal,
374 .loop_once = poll_event_loop_once,
375 .loop_wait = tevent_common_loop_wait,
378 _PRIVATE_ bool tevent_poll_init(void)
380 return tevent_register_backend("poll", &poll_event_ops);