s4:librpc/rpc: add DCERPC_SCHANNEL_AES support
[Samba.git] / lib / tevent / tevent_poll.c
blob7ae3c42188de1aec1b8e70d26cb9c8bbf9683f42
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 {
33 /* a pointer back to the generic event_context */
34 struct tevent_context *ev;
37 * These two arrays are maintained together.
39 struct pollfd *fds;
40 struct tevent_fd **fd_events;
41 uint64_t num_fds;
43 /* information for exiting from the event loop */
44 int exit_code;
48 create a select_event_context structure.
50 static int poll_event_context_init(struct tevent_context *ev)
52 struct poll_event_context *poll_ev;
54 poll_ev = talloc_zero(ev, struct poll_event_context);
55 if (poll_ev == NULL) {
56 return -1;
58 poll_ev->ev = ev;
59 ev->additional_data = poll_ev;
60 return 0;
64 destroy an fd_event
66 static int poll_event_fd_destructor(struct tevent_fd *fde)
68 struct tevent_context *ev = fde->event_ctx;
69 struct poll_event_context *poll_ev = NULL;
70 struct tevent_fd *moved_fde;
71 uint64_t del_idx = fde->additional_flags;
73 if (ev == NULL) {
74 goto done;
77 poll_ev = talloc_get_type_abort(
78 ev->additional_data, struct poll_event_context);
80 moved_fde = poll_ev->fd_events[poll_ev->num_fds-1];
81 poll_ev->fd_events[del_idx] = moved_fde;
82 poll_ev->fds[del_idx] = poll_ev->fds[poll_ev->num_fds-1];
83 moved_fde->additional_flags = del_idx;
85 poll_ev->num_fds -= 1;
86 done:
87 return tevent_common_fd_destructor(fde);
91 add a fd based event
92 return NULL on failure (memory allocation error)
94 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
95 TALLOC_CTX *mem_ctx,
96 int fd, uint16_t flags,
97 tevent_fd_handler_t handler,
98 void *private_data,
99 const char *handler_name,
100 const char *location)
102 struct poll_event_context *poll_ev = talloc_get_type_abort(
103 ev->additional_data, struct poll_event_context);
104 struct pollfd *pfd;
105 struct tevent_fd *fde;
107 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
108 handler, private_data,
109 handler_name, location);
110 if (fde == NULL) {
111 return NULL;
114 /* we allocate 16 slots to avoid a lot of reallocations */
115 if (talloc_array_length(poll_ev->fds) == poll_ev->num_fds) {
116 struct pollfd *tmp_fds;
117 struct tevent_fd **tmp_fd_events;
118 tmp_fds = talloc_realloc(
119 poll_ev, poll_ev->fds, struct pollfd,
120 poll_ev->num_fds + 16);
121 if (tmp_fds == NULL) {
122 TALLOC_FREE(fde);
123 return NULL;
125 poll_ev->fds = tmp_fds;
127 tmp_fd_events = talloc_realloc(
128 poll_ev, poll_ev->fd_events, struct tevent_fd *,
129 poll_ev->num_fds + 16);
130 if (tmp_fd_events == NULL) {
131 TALLOC_FREE(fde);
132 return NULL;
134 poll_ev->fd_events = tmp_fd_events;
137 pfd = &poll_ev->fds[poll_ev->num_fds];
139 pfd->fd = fd;
141 pfd->events = 0;
142 pfd->revents = 0;
144 if (flags & TEVENT_FD_READ) {
145 pfd->events |= (POLLIN|POLLHUP);
147 if (flags & TEVENT_FD_WRITE) {
148 pfd->events |= (POLLOUT);
151 fde->additional_flags = poll_ev->num_fds;
152 poll_ev->fd_events[poll_ev->num_fds] = fde;
154 poll_ev->num_fds += 1;
156 talloc_set_destructor(fde, poll_event_fd_destructor);
158 return fde;
162 set the fd event flags
164 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
166 struct poll_event_context *poll_ev = talloc_get_type_abort(
167 fde->event_ctx->additional_data, struct poll_event_context);
168 uint64_t idx = fde->additional_flags;
169 uint16_t pollflags = 0;
171 if (flags & TEVENT_FD_READ) {
172 pollflags |= (POLLIN|POLLHUP);
174 if (flags & TEVENT_FD_WRITE) {
175 pollflags |= (POLLOUT);
178 poll_ev->fds[idx].events = pollflags;
180 fde->flags = flags;
184 event loop handling using poll()
186 static int poll_event_loop_poll(struct tevent_context *ev,
187 struct timeval *tvalp)
189 struct poll_event_context *poll_ev = talloc_get_type_abort(
190 ev->additional_data, struct poll_event_context);
191 struct tevent_fd *fde;
192 int pollrtn;
193 int timeout = -1;
195 if (ev->signal_events && tevent_common_check_signal(ev)) {
196 return 0;
199 if (tvalp != NULL) {
200 timeout = tvalp->tv_sec * 1000;
201 timeout += (tvalp->tv_usec + 999) / 1000;
204 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
205 pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
206 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
208 if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
209 tevent_common_check_signal(ev);
210 return 0;
213 if (pollrtn == -1 && errno == EBADF) {
214 /* the socket is dead! this should never
215 happen as the socket should have first been
216 made readable and that should have removed
217 the event, so this must be a bug. This is a
218 fatal error. */
219 tevent_debug(ev, TEVENT_DEBUG_FATAL,
220 "ERROR: EBADF on poll_event_loop_once\n");
221 poll_ev->exit_code = EBADF;
222 return -1;
225 if (pollrtn == 0 && tvalp) {
226 /* we don't care about a possible delay here */
227 tevent_common_loop_timer_delay(ev);
228 return 0;
231 if (pollrtn <= 0) {
233 * No fd's ready
235 return 0;
238 /* at least one file descriptor is ready - check
239 which ones and call the handler, being careful to allow
240 the handler to remove itself when called */
242 for (fde = ev->fd_events; fde; fde = fde->next) {
243 struct pollfd *pfd;
244 uint64_t pfd_idx = fde->additional_flags;
245 uint16_t flags = 0;
247 pfd = &poll_ev->fds[pfd_idx];
249 if (pfd->revents & (POLLHUP|POLLERR)) {
250 /* If we only wait for TEVENT_FD_WRITE, we
251 should not tell the event handler about it,
252 and remove the writable flag, as we only
253 report errors when waiting for read events
254 to match the select behavior. */
255 if (!(fde->flags & TEVENT_FD_READ)) {
256 TEVENT_FD_NOT_WRITEABLE(fde);
257 continue;
259 flags |= TEVENT_FD_READ;
261 if (pfd->revents & POLLIN) {
262 flags |= TEVENT_FD_READ;
264 if (pfd->revents & POLLOUT) {
265 flags |= TEVENT_FD_WRITE;
267 if (flags != 0) {
268 fde->handler(ev, fde, flags, fde->private_data);
269 break;
273 return 0;
277 do a single event loop using the events defined in ev
279 static int poll_event_loop_once(struct tevent_context *ev,
280 const char *location)
282 struct timeval tval;
284 if (ev->signal_events &&
285 tevent_common_check_signal(ev)) {
286 return 0;
289 if (ev->immediate_events &&
290 tevent_common_loop_immediate(ev)) {
291 return 0;
294 tval = tevent_common_loop_timer_delay(ev);
295 if (tevent_timeval_is_zero(&tval)) {
296 return 0;
299 return poll_event_loop_poll(ev, &tval);
302 static const struct tevent_ops poll_event_ops = {
303 .context_init = poll_event_context_init,
304 .add_fd = poll_event_add_fd,
305 .set_fd_close_fn = tevent_common_fd_set_close_fn,
306 .get_fd_flags = tevent_common_fd_get_flags,
307 .set_fd_flags = poll_event_set_fd_flags,
308 .add_timer = tevent_common_add_timer,
309 .schedule_immediate = tevent_common_schedule_immediate,
310 .add_signal = tevent_common_add_signal,
311 .loop_once = poll_event_loop_once,
312 .loop_wait = tevent_common_loop_wait,
315 _PRIVATE_ bool tevent_poll_init(void)
317 return tevent_register_backend("poll", &poll_event_ops);