Fix "cast from pointer to integer of different size" warnings on a 64-bit machine.
[Samba.git] / lib / tevent / tevent_poll.c
blobcda028a964bf8c723eb211571af9f1762eac18d9
1 /*
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
9 ** under the LGPL
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/>.
25 #include "replace.h"
26 #include "system/filesys.h"
27 #include "system/select.h"
28 #include "tevent.h"
29 #include "tevent_util.h"
30 #include "tevent_internal.h"
32 struct poll_event_context {
34 * These two arrays are maintained together.
36 struct pollfd *fds;
37 struct tevent_fd **fd_events;
38 int num_fds;
40 /* information for exiting from the event loop */
41 int exit_code;
45 create a select_event_context structure.
47 static int poll_event_context_init(struct tevent_context *ev)
49 struct poll_event_context *poll_ev;
51 poll_ev = talloc_zero(ev, struct poll_event_context);
52 if (poll_ev == NULL) {
53 return -1;
55 ev->additional_data = poll_ev;
56 return 0;
60 destroy an fd_event
62 static int poll_event_fd_destructor(struct tevent_fd *fde)
64 struct tevent_context *ev = fde->event_ctx;
65 struct poll_event_context *poll_ev = NULL;
66 struct tevent_fd *moved_fde;
67 long del_idx;
69 if (ev == NULL) {
70 goto done;
73 poll_ev = talloc_get_type_abort(
74 ev->additional_data, struct poll_event_context);
77 * Assume a void * can carry enough bits to hold num_fds.
79 del_idx = (long)(fde->additional_data);
81 moved_fde = poll_ev->fd_events[poll_ev->num_fds-1];
82 poll_ev->fd_events[del_idx] = moved_fde;
83 poll_ev->fds[del_idx] = poll_ev->fds[poll_ev->num_fds-1];
84 moved_fde->additional_data = (void *)del_idx;
86 poll_ev->num_fds -= 1;
87 done:
88 return tevent_common_fd_destructor(fde);
92 add a fd based event
93 return NULL on failure (memory allocation error)
95 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
96 TALLOC_CTX *mem_ctx,
97 int fd, uint16_t flags,
98 tevent_fd_handler_t handler,
99 void *private_data,
100 const char *handler_name,
101 const char *location)
103 struct poll_event_context *poll_ev = talloc_get_type_abort(
104 ev->additional_data, struct poll_event_context);
105 struct pollfd *pfd;
106 struct tevent_fd *fde;
108 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
109 handler, private_data,
110 handler_name, location);
111 if (fde == NULL) {
112 return NULL;
115 /* we allocate 16 slots to avoid a lot of reallocations */
116 if (talloc_array_length(poll_ev->fds) == poll_ev->num_fds) {
117 struct pollfd *tmp_fds;
118 struct tevent_fd **tmp_fd_events;
119 tmp_fds = talloc_realloc(
120 poll_ev, poll_ev->fds, struct pollfd,
121 poll_ev->num_fds + 16);
122 if (tmp_fds == NULL) {
123 TALLOC_FREE(fde);
124 return NULL;
126 poll_ev->fds = tmp_fds;
128 tmp_fd_events = talloc_realloc(
129 poll_ev, poll_ev->fd_events, struct tevent_fd *,
130 poll_ev->num_fds + 16);
131 if (tmp_fd_events == NULL) {
132 TALLOC_FREE(fde);
133 return NULL;
135 poll_ev->fd_events = tmp_fd_events;
138 pfd = &poll_ev->fds[poll_ev->num_fds];
140 pfd->fd = fd;
142 pfd->events = 0;
143 pfd->revents = 0;
145 if (flags & TEVENT_FD_READ) {
146 pfd->events |= (POLLIN|POLLHUP);
148 if (flags & TEVENT_FD_WRITE) {
149 pfd->events |= (POLLOUT);
153 * Assume a void * can carry enough bits to hold num_fds.
155 fde->additional_data = (void *)(long)poll_ev->num_fds;
156 poll_ev->fd_events[poll_ev->num_fds] = fde;
158 poll_ev->num_fds += 1;
160 talloc_set_destructor(fde, poll_event_fd_destructor);
162 return fde;
166 set the fd event flags
168 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
170 struct poll_event_context *poll_ev = talloc_get_type_abort(
171 fde->event_ctx->additional_data, struct poll_event_context);
172 long idx;
173 uint16_t pollflags = 0;
175 if (flags & TEVENT_FD_READ) {
176 pollflags |= (POLLIN|POLLHUP);
178 if (flags & TEVENT_FD_WRITE) {
179 pollflags |= (POLLOUT);
182 idx = (long)(fde->additional_data);
183 poll_ev->fds[idx].events = pollflags;
185 fde->flags = flags;
189 event loop handling using select()
191 static int poll_event_loop_poll(struct tevent_context *ev,
192 struct timeval *tvalp)
194 struct poll_event_context *poll_ev = talloc_get_type_abort(
195 ev->additional_data, struct poll_event_context);
196 struct tevent_fd *fde;
197 int pollrtn;
198 int timeout = -1;
200 if (ev->signal_events && tevent_common_check_signal(ev)) {
201 return 0;
204 if (tvalp != NULL) {
205 timeout = tvalp->tv_sec * 1000;
206 timeout += (tvalp->tv_usec + 999) / 1000;
209 pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
211 if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
212 tevent_common_check_signal(ev);
213 return 0;
216 if (pollrtn == -1 && errno == EBADF) {
217 /* the socket is dead! this should never
218 happen as the socket should have first been
219 made readable and that should have removed
220 the event, so this must be a bug. This is a
221 fatal error. */
222 tevent_debug(ev, TEVENT_DEBUG_FATAL,
223 "ERROR: EBADF on poll_event_loop_once\n");
224 poll_ev->exit_code = EBADF;
225 return -1;
228 if (pollrtn == 0 && tvalp) {
229 /* we don't care about a possible delay here */
230 tevent_common_loop_timer_delay(ev);
231 return 0;
234 if (pollrtn > 0) {
235 /* at least one file descriptor is ready - check
236 which ones and call the handler, being careful to allow
237 the handler to remove itself when called */
238 for (fde = ev->fd_events; fde; fde = fde->next) {
239 struct pollfd *pfd;
240 long pfd_idx;
241 uint16_t flags = 0;
243 pfd_idx = (long)(fde->additional_data);
245 pfd = &poll_ev->fds[pfd_idx];
247 if (pfd->revents & (POLLIN|POLLHUP|POLLERR)) {
248 flags |= TEVENT_FD_READ;
250 if (pfd->revents & POLLOUT) {
251 flags |= TEVENT_FD_WRITE;
253 if (flags != 0) {
254 fde->handler(ev, fde, flags,
255 fde->private_data);
256 break;
261 return 0;
265 do a single event loop using the events defined in ev
267 static int poll_event_loop_once(struct tevent_context *ev,
268 const char *location)
270 struct timeval tval;
272 if (ev->signal_events &&
273 tevent_common_check_signal(ev)) {
274 return 0;
277 if (ev->immediate_events &&
278 tevent_common_loop_immediate(ev)) {
279 return 0;
282 tval = tevent_common_loop_timer_delay(ev);
283 if (tevent_timeval_is_zero(&tval)) {
284 return 0;
287 return poll_event_loop_poll(ev, &tval);
290 static const struct tevent_ops poll_event_ops = {
291 .context_init = poll_event_context_init,
292 .add_fd = poll_event_add_fd,
293 .set_fd_close_fn = tevent_common_fd_set_close_fn,
294 .get_fd_flags = tevent_common_fd_get_flags,
295 .set_fd_flags = poll_event_set_fd_flags,
296 .add_timer = tevent_common_add_timer,
297 .schedule_immediate = tevent_common_schedule_immediate,
298 .add_signal = tevent_common_add_signal,
299 .loop_once = poll_event_loop_once,
300 .loop_wait = tevent_common_loop_wait,
303 _PRIVATE_ bool tevent_poll_init(void)
305 return tevent_register_backend("poll", &poll_event_ops);