Talloc doc: talloc_asprintf_append_buffer()
[idra/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         uint64_t 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         uint64_t del_idx = fde->additional_flags;
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         moved_fde = poll_ev->fd_events[poll_ev->num_fds-1];
77         poll_ev->fd_events[del_idx] = moved_fde;
78         poll_ev->fds[del_idx] = poll_ev->fds[poll_ev->num_fds-1];
79         moved_fde->additional_flags = del_idx;
80
81         poll_ev->num_fds -= 1;
82 done:
83         return tevent_common_fd_destructor(fde);
84 }
85
86 /*
87   add a fd based event
88   return NULL on failure (memory allocation error)
89 */
90 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
91                                            TALLOC_CTX *mem_ctx,
92                                            int fd, uint16_t flags,
93                                            tevent_fd_handler_t handler,
94                                            void *private_data,
95                                            const char *handler_name,
96                                            const char *location)
97 {
98         struct poll_event_context *poll_ev = talloc_get_type_abort(
99                 ev->additional_data, struct poll_event_context);
100         struct pollfd *pfd;
101         struct tevent_fd *fde;
102
103         fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
104                                    handler, private_data,
105                                    handler_name, location);
106         if (fde == NULL) {
107                 return NULL;
108         }
109
110         /* we allocate 16 slots to avoid a lot of reallocations */
111         if (talloc_array_length(poll_ev->fds) == poll_ev->num_fds) {
112                 struct pollfd *tmp_fds;
113                 struct tevent_fd **tmp_fd_events;
114                 tmp_fds = talloc_realloc(
115                         poll_ev, poll_ev->fds, struct pollfd,
116                         poll_ev->num_fds + 16);
117                 if (tmp_fds == NULL) {
118                         TALLOC_FREE(fde);
119                         return NULL;
120                 }
121                 poll_ev->fds = tmp_fds;
122
123                 tmp_fd_events = talloc_realloc(
124                         poll_ev, poll_ev->fd_events, struct tevent_fd *,
125                         poll_ev->num_fds + 16);
126                 if (tmp_fd_events == NULL) {
127                         TALLOC_FREE(fde);
128                         return NULL;
129                 }
130                 poll_ev->fd_events = tmp_fd_events;
131         }
132
133         pfd = &poll_ev->fds[poll_ev->num_fds];
134
135         pfd->fd = fd;
136
137         pfd->events = 0;
138         pfd->revents = 0;
139
140         if (flags & TEVENT_FD_READ) {
141                 pfd->events |= (POLLIN|POLLHUP);
142         }
143         if (flags & TEVENT_FD_WRITE) {
144                 pfd->events |= (POLLOUT);
145         }
146
147         fde->additional_flags = poll_ev->num_fds;
148         poll_ev->fd_events[poll_ev->num_fds] = fde;
149
150         poll_ev->num_fds += 1;
151
152         talloc_set_destructor(fde, poll_event_fd_destructor);
153
154         return fde;
155 }
156
157 /*
158   set the fd event flags
159 */
160 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
161 {
162         struct poll_event_context *poll_ev = talloc_get_type_abort(
163                 fde->event_ctx->additional_data, struct poll_event_context);
164         uint64_t idx = fde->additional_flags;
165         uint16_t pollflags = 0;
166
167         if (flags & TEVENT_FD_READ) {
168                 pollflags |= (POLLIN|POLLHUP);
169         }
170         if (flags & TEVENT_FD_WRITE) {
171                 pollflags |= (POLLOUT);
172         }
173
174         poll_ev->fds[idx].events = pollflags;
175
176         fde->flags = flags;
177 }
178
179 /*
180   event loop handling using poll()
181 */
182 static int poll_event_loop_poll(struct tevent_context *ev,
183                                 struct timeval *tvalp)
184 {
185         struct poll_event_context *poll_ev = talloc_get_type_abort(
186                 ev->additional_data, struct poll_event_context);
187         struct tevent_fd *fde;
188         int pollrtn;
189         int timeout = -1;
190
191         if (ev->signal_events && tevent_common_check_signal(ev)) {
192                 return 0;
193         }
194
195         if (tvalp != NULL) {
196                 timeout = tvalp->tv_sec * 1000;
197                 timeout += (tvalp->tv_usec + 999) / 1000;
198         }
199
200         pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
201
202         if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
203                 tevent_common_check_signal(ev);
204                 return 0;
205         }
206
207         if (pollrtn == -1 && errno == EBADF) {
208                 /* the socket is dead! this should never
209                    happen as the socket should have first been
210                    made readable and that should have removed
211                    the event, so this must be a bug. This is a
212                    fatal error. */
213                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
214                              "ERROR: EBADF on poll_event_loop_once\n");
215                 poll_ev->exit_code = EBADF;
216                 return -1;
217         }
218
219         if (pollrtn == 0 && tvalp) {
220                 /* we don't care about a possible delay here */
221                 tevent_common_loop_timer_delay(ev);
222                 return 0;
223         }
224
225         if (pollrtn <= 0) {
226                 /*
227                  * No fd's ready
228                  */
229                 return 0;
230         }
231
232         /* at least one file descriptor is ready - check
233            which ones and call the handler, being careful to allow
234            the handler to remove itself when called */
235
236         for (fde = ev->fd_events; fde; fde = fde->next) {
237                 struct pollfd *pfd;
238                 uint64_t pfd_idx = fde->additional_flags;
239                 uint16_t flags = 0;
240
241                 pfd = &poll_ev->fds[pfd_idx];
242
243                 if (pfd->revents & (POLLHUP|POLLERR)) {
244                         /* If we only wait for TEVENT_FD_WRITE, we
245                            should not tell the event handler about it,
246                            and remove the writable flag, as we only
247                            report errors when waiting for read events
248                            to match the select behavior. */
249                         if (!(fde->flags & TEVENT_FD_READ)) {
250                                 TEVENT_FD_NOT_WRITEABLE(fde);
251                                 continue;
252                         }
253                         flags |= TEVENT_FD_READ;
254                 }
255                 if (pfd->revents & POLLIN) {
256                         flags |= TEVENT_FD_READ;
257                 }
258                 if (pfd->revents & POLLOUT) {
259                         flags |= TEVENT_FD_WRITE;
260                 }
261                 if (flags != 0) {
262                         fde->handler(ev, fde, flags, fde->private_data);
263                         break;
264                 }
265         }
266
267         return 0;
268 }
269
270 /*
271   do a single event loop using the events defined in ev
272 */
273 static int poll_event_loop_once(struct tevent_context *ev,
274                                 const char *location)
275 {
276         struct timeval tval;
277
278         if (ev->signal_events &&
279             tevent_common_check_signal(ev)) {
280                 return 0;
281         }
282
283         if (ev->immediate_events &&
284             tevent_common_loop_immediate(ev)) {
285                 return 0;
286         }
287
288         tval = tevent_common_loop_timer_delay(ev);
289         if (tevent_timeval_is_zero(&tval)) {
290                 return 0;
291         }
292
293         return poll_event_loop_poll(ev, &tval);
294 }
295
296 static const struct tevent_ops poll_event_ops = {
297         .context_init           = poll_event_context_init,
298         .add_fd                 = poll_event_add_fd,
299         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
300         .get_fd_flags           = tevent_common_fd_get_flags,
301         .set_fd_flags           = poll_event_set_fd_flags,
302         .add_timer              = tevent_common_add_timer,
303         .schedule_immediate     = tevent_common_schedule_immediate,
304         .add_signal             = tevent_common_add_signal,
305         .loop_once              = poll_event_loop_once,
306         .loop_wait              = tevent_common_loop_wait,
307 };
308
309 _PRIVATE_ bool tevent_poll_init(void)
310 {
311         return tevent_register_backend("poll", &poll_event_ops);
312 }