Fix "cast from pointer to integer of different size" warnings on a 64-bit machine.
[samba.git] / lib / tevent / tevent_poll.c
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
6
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
10
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.
15
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.
20
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/>.
23 */
24
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"
31
32 struct poll_event_context {
33         /*
34          * These two arrays are maintained together.
35          */
36         struct pollfd *fds;
37         struct tevent_fd **fd_events;
38         int num_fds;
39
40         /* information for exiting from the event loop */
41         int exit_code;
42 };
43
44 /*
45   create a select_event_context structure.
46 */
47 static int poll_event_context_init(struct tevent_context *ev)
48 {
49         struct poll_event_context *poll_ev;
50
51         poll_ev = talloc_zero(ev, struct poll_event_context);
52         if (poll_ev == NULL) {
53                 return -1;
54         }
55         ev->additional_data = poll_ev;
56         return 0;
57 }
58
59 /*
60   destroy an fd_event
61 */
62 static int poll_event_fd_destructor(struct tevent_fd *fde)
63 {
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;
68
69         if (ev == NULL) {
70                 goto done;
71         }
72
73         poll_ev = talloc_get_type_abort(
74                 ev->additional_data, struct poll_event_context);
75
76         /*
77          * Assume a void * can carry enough bits to hold num_fds.
78          */
79         del_idx = (long)(fde->additional_data);
80
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;
85
86         poll_ev->num_fds -= 1;
87 done:
88         return tevent_common_fd_destructor(fde);
89 }
90
91 /*
92   add a fd based event
93   return NULL on failure (memory allocation error)
94 */
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)
102 {
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;
107
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;
113         }
114
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;
125                 }
126                 poll_ev->fds = tmp_fds;
127
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;
134                 }
135                 poll_ev->fd_events = tmp_fd_events;
136         }
137
138         pfd = &poll_ev->fds[poll_ev->num_fds];
139
140         pfd->fd = fd;
141
142         pfd->events = 0;
143         pfd->revents = 0;
144
145         if (flags & TEVENT_FD_READ) {
146                 pfd->events |= (POLLIN|POLLHUP);
147         }
148         if (flags & TEVENT_FD_WRITE) {
149                 pfd->events |= (POLLOUT);
150         }
151
152         /*
153          * Assume a void * can carry enough bits to hold num_fds.
154          */
155         fde->additional_data = (void *)(long)poll_ev->num_fds;
156         poll_ev->fd_events[poll_ev->num_fds] = fde;
157
158         poll_ev->num_fds += 1;
159
160         talloc_set_destructor(fde, poll_event_fd_destructor);
161
162         return fde;
163 }
164
165 /*
166   set the fd event flags
167 */
168 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
169 {
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;
174
175         if (flags & TEVENT_FD_READ) {
176                 pollflags |= (POLLIN|POLLHUP);
177         }
178         if (flags & TEVENT_FD_WRITE) {
179                 pollflags |= (POLLOUT);
180         }
181
182         idx = (long)(fde->additional_data);
183         poll_ev->fds[idx].events = pollflags;
184
185         fde->flags = flags;
186 }
187
188 /*
189   event loop handling using select()
190 */
191 static int poll_event_loop_poll(struct tevent_context *ev,
192                                 struct timeval *tvalp)
193 {
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;
199
200         if (ev->signal_events && tevent_common_check_signal(ev)) {
201                 return 0;
202         }
203
204         if (tvalp != NULL) {
205                 timeout = tvalp->tv_sec * 1000;
206                 timeout += (tvalp->tv_usec + 999) / 1000;
207         }
208
209         pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
210
211         if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
212                 tevent_common_check_signal(ev);
213                 return 0;
214         }
215
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;
226         }
227
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;
232         }
233
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;
242
243                         pfd_idx = (long)(fde->additional_data);
244
245                         pfd = &poll_ev->fds[pfd_idx];
246
247                         if (pfd->revents & (POLLIN|POLLHUP|POLLERR)) {
248                                 flags |= TEVENT_FD_READ;
249                         }
250                         if (pfd->revents & POLLOUT) {
251                                 flags |= TEVENT_FD_WRITE;
252                         }
253                         if (flags != 0) {
254                                 fde->handler(ev, fde, flags,
255                                              fde->private_data);
256                                 break;
257                         }
258                 }
259         }
260
261         return 0;
262 }
263
264 /*
265   do a single event loop using the events defined in ev
266 */
267 static int poll_event_loop_once(struct tevent_context *ev,
268                                 const char *location)
269 {
270         struct timeval tval;
271
272         if (ev->signal_events &&
273             tevent_common_check_signal(ev)) {
274                 return 0;
275         }
276
277         if (ev->immediate_events &&
278             tevent_common_loop_immediate(ev)) {
279                 return 0;
280         }
281
282         tval = tevent_common_loop_timer_delay(ev);
283         if (tevent_timeval_is_zero(&tval)) {
284                 return 0;
285         }
286
287         return poll_event_loop_poll(ev, &tval);
288 }
289
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,
301 };
302
303 _PRIVATE_ bool tevent_poll_init(void)
304 {
305         return tevent_register_backend("poll", &poll_event_ops);
306 }