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
{
34 * These two arrays are maintained together.
37 struct tevent_fd
**fd_events
;
40 /* information for exiting from the event loop */
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
) {
55 ev
->additional_data
= poll_ev
;
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
;
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;
88 return tevent_common_fd_destructor(fde
);
93 return NULL on failure (memory allocation error)
95 static struct tevent_fd
*poll_event_add_fd(struct tevent_context
*ev
,
97 int fd
, uint16_t flags
,
98 tevent_fd_handler_t handler
,
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
);
106 struct tevent_fd
*fde
;
108 fde
= tevent_common_add_fd(ev
, mem_ctx
, fd
, flags
,
109 handler
, private_data
,
110 handler_name
, location
);
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
) {
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
) {
135 poll_ev
->fd_events
= tmp_fd_events
;
138 pfd
= &poll_ev
->fds
[poll_ev
->num_fds
];
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
);
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
);
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
;
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
;
200 if (ev
->signal_events
&& tevent_common_check_signal(ev
)) {
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
);
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
222 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
223 "ERROR: EBADF on poll_event_loop_once\n");
224 poll_ev
->exit_code
= EBADF
;
228 if (pollrtn
== 0 && tvalp
) {
229 /* we don't care about a possible delay here */
230 tevent_common_loop_timer_delay(ev
);
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
) {
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
;
254 fde
->handler(ev
, fde
, flags
,
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
)
272 if (ev
->signal_events
&&
273 tevent_common_check_signal(ev
)) {
277 if (ev
->immediate_events
&&
278 tevent_common_loop_immediate(ev
)) {
282 tval
= tevent_common_loop_timer_delay(ev
);
283 if (tevent_timeval_is_zero(&tval
)) {
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
);