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
{
33 /* a pointer back to the generic event_context */
34 struct tevent_context
*ev
;
37 * These two arrays are maintained together.
40 struct tevent_fd
**fd_events
;
43 /* information for exiting from the event loop */
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
) {
59 ev
->additional_data
= poll_ev
;
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
;
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;
87 return tevent_common_fd_destructor(fde
);
92 return NULL on failure (memory allocation error)
94 static struct tevent_fd
*poll_event_add_fd(struct tevent_context
*ev
,
96 int fd
, uint16_t flags
,
97 tevent_fd_handler_t handler
,
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
);
105 struct tevent_fd
*fde
;
107 fde
= tevent_common_add_fd(ev
, mem_ctx
, fd
, flags
,
108 handler
, private_data
,
109 handler_name
, location
);
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
) {
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
) {
134 poll_ev
->fd_events
= tmp_fd_events
;
137 pfd
= &poll_ev
->fds
[poll_ev
->num_fds
];
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
);
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
;
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
;
195 if (ev
->signal_events
&& tevent_common_check_signal(ev
)) {
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
);
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
219 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
220 "ERROR: EBADF on poll_event_loop_once\n");
221 poll_ev
->exit_code
= EBADF
;
225 if (pollrtn
== 0 && tvalp
) {
226 /* we don't care about a possible delay here */
227 tevent_common_loop_timer_delay(ev
);
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
) {
244 uint64_t pfd_idx
= fde
->additional_flags
;
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
);
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
;
268 fde
->handler(ev
, fde
, flags
, fde
->private_data
);
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
)
284 if (ev
->signal_events
&&
285 tevent_common_check_signal(ev
)) {
289 if (ev
->immediate_events
&&
290 tevent_common_loop_immediate(ev
)) {
294 tval
= tevent_common_loop_timer_delay(ev
);
295 if (tevent_timeval_is_zero(&tval
)) {
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
);