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 select_event_context {
33
/* a pointer back to the generic event_context */
34
struct tevent_context *ev;
36
/* the maximum file descriptor number in fd_events */
39
/* information for exiting from the event loop */
44
create a select_event_context structure.
46
static int select_event_context_init(struct tevent_context *ev)
48
struct select_event_context *select_ev;
50
select_ev = talloc_zero(ev, struct select_event_context);
51
if (!select_ev) return -1;
54
ev->additional_data = select_ev;
61
static void calc_maxfd(struct select_event_context *select_ev)
63
struct tevent_fd *fde;
66
for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
67
if (fde->fd > select_ev->maxfd) {
68
select_ev->maxfd = fde->fd;
74
/* to mark the ev->maxfd invalid
75
* this means we need to recalculate it
77
#define EVENT_INVALID_MAXFD (-1)
82
static int select_event_fd_destructor(struct tevent_fd *fde)
84
struct tevent_context *ev = fde->event_ctx;
85
struct select_event_context *select_ev = NULL;
88
select_ev = talloc_get_type(ev->additional_data,
89
struct select_event_context);
91
if (select_ev->maxfd == fde->fd) {
92
select_ev->maxfd = EVENT_INVALID_MAXFD;
96
return tevent_common_fd_destructor(fde);
101
return NULL on failure (memory allocation error)
103
static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
104
int fd, uint16_t flags,
105
tevent_fd_handler_t handler,
107
const char *handler_name,
108
const char *location)
110
struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
111
struct select_event_context);
112
struct tevent_fd *fde;
114
fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
115
handler, private_data,
116
handler_name, location);
117
if (!fde) return NULL;
119
if (fde->fd > select_ev->maxfd) {
120
select_ev->maxfd = fde->fd;
122
talloc_set_destructor(fde, select_event_fd_destructor);
128
event loop handling using select()
130
static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
133
struct tevent_fd *fde;
136
/* we maybe need to recalculate the maxfd */
137
if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
138
calc_maxfd(select_ev);
144
/* setup any fd events */
145
for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
146
if (fde->flags & TEVENT_FD_READ) {
147
FD_SET(fde->fd, &r_fds);
149
if (fde->flags & TEVENT_FD_WRITE) {
150
FD_SET(fde->fd, &w_fds);
154
if (select_ev->ev->signal_events &&
155
tevent_common_check_signal(select_ev->ev)) {
159
selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
161
if (selrtn == -1 && errno == EINTR &&
162
select_ev->ev->signal_events) {
163
tevent_common_check_signal(select_ev->ev);
167
if (selrtn == -1 && errno == EBADF) {
168
/* the socket is dead! this should never
169
happen as the socket should have first been
170
made readable and that should have removed
171
the event, so this must be a bug. This is a
173
tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
174
"ERROR: EBADF on select_event_loop_once\n");
175
select_ev->exit_code = EBADF;
179
if (selrtn == 0 && tvalp) {
180
/* we don't care about a possible delay here */
181
tevent_common_loop_timer_delay(select_ev->ev);
186
/* at least one file descriptor is ready - check
187
which ones and call the handler, being careful to allow
188
the handler to remove itself when called */
189
for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
192
if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
193
if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
195
fde->handler(select_ev->ev, fde, flags, fde->private_data);
205
do a single event loop using the events defined in ev
207
static int select_event_loop_once(struct tevent_context *ev, const char *location)
209
struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
210
struct select_event_context);
213
if (ev->signal_events &&
214
tevent_common_check_signal(ev)) {
218
if (ev->immediate_events &&
219
tevent_common_loop_immediate(ev)) {
223
tval = tevent_common_loop_timer_delay(ev);
224
if (tevent_timeval_is_zero(&tval)) {
228
return select_event_loop_select(select_ev, &tval);
231
static const struct tevent_ops select_event_ops = {
232
.context_init = select_event_context_init,
233
.add_fd = select_event_add_fd,
234
.set_fd_close_fn = tevent_common_fd_set_close_fn,
235
.get_fd_flags = tevent_common_fd_get_flags,
236
.set_fd_flags = tevent_common_fd_set_flags,
237
.add_timer = tevent_common_add_timer,
238
.schedule_immediate = tevent_common_schedule_immediate,
239
.add_signal = tevent_common_add_signal,
240
.loop_once = select_event_loop_once,
241
.loop_wait = tevent_common_loop_wait,
244
bool tevent_select_init(void)
246
return tevent_register_backend("select", &select_event_ops);