2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Volker Lendecke 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <tevent_internal.h>
23 #include "../lib/util/select.h"
26 * Return if there's something in the queue
29 bool event_add_to_select_args(struct tevent_context
*ev
,
30 fd_set
*read_fds
, fd_set
*write_fds
,
31 struct timeval
*timeout
, int *maxfd
)
34 struct tevent_fd
*fde
;
38 for (fde
= ev
->fd_events
; fde
; fde
= fde
->next
) {
39 if (fde
->flags
& EVENT_FD_READ
) {
40 FD_SET(fde
->fd
, read_fds
);
43 if (fde
->flags
& EVENT_FD_WRITE
) {
44 FD_SET(fde
->fd
, write_fds
);
48 if ((fde
->flags
& (EVENT_FD_READ
|EVENT_FD_WRITE
))
49 && (fde
->fd
> *maxfd
)) {
54 if (ev
->immediate_events
!= NULL
) {
55 *timeout
= timeval_zero();
59 if (ev
->timer_events
== NULL
) {
63 now
= timeval_current();
64 diff
= timeval_until(&now
, &ev
->timer_events
->next_event
);
65 *timeout
= timeval_min(timeout
, &diff
);
70 bool run_events(struct tevent_context
*ev
,
71 int *selrtn
, fd_set
*read_fds
, fd_set
*write_fds
)
73 struct tevent_fd
*fde
;
76 if (ev
->signal_events
&&
77 tevent_common_check_signal(ev
)) {
81 if (ev
->immediate_events
&&
82 tevent_common_loop_immediate(ev
)) {
88 if ((ev
->timer_events
!= NULL
)
89 && (timeval_compare(&now
, &ev
->timer_events
->next_event
) >= 0)) {
90 /* this older events system did not auto-free timed
91 events on running them, and had a race condition
92 where the event could be called twice if the
93 talloc_free of the te happened after the callback
94 made a call which invoked the event loop. To avoid
95 this while still allowing old code which frees the
96 te, we need to create a temporary context which
97 will be used to ensure the te is freed. We also
98 remove the te from the timed event list before we
99 call the handler, to ensure we can't loop */
101 struct tevent_timer
*te
= ev
->timer_events
;
102 TALLOC_CTX
*tmp_ctx
= talloc_new(ev
);
104 DEBUG(10, ("Running timed event \"%s\" %p\n",
105 ev
->timer_events
->handler_name
, ev
->timer_events
));
107 DLIST_REMOVE(ev
->timer_events
, te
);
108 talloc_steal(tmp_ctx
, te
);
110 te
->handler(ev
, te
, now
, te
->private_data
);
112 talloc_free(tmp_ctx
);
123 for (fde
= ev
->fd_events
; fde
; fde
= fde
->next
) {
126 if (FD_ISSET(fde
->fd
, read_fds
)) {
127 flags
|= EVENT_FD_READ
;
128 FD_CLR(fde
->fd
, read_fds
);
131 if (FD_ISSET(fde
->fd
, write_fds
)) {
132 flags
|= EVENT_FD_WRITE
;
133 FD_CLR(fde
->fd
, write_fds
);
137 if (flags
& fde
->flags
) {
138 fde
->handler(ev
, fde
, flags
, fde
->private_data
);
147 struct timeval
*get_timed_events_timeout(struct tevent_context
*ev
,
148 struct timeval
*to_ret
)
152 if ((ev
->timer_events
== NULL
) && (ev
->immediate_events
== NULL
)) {
155 if (ev
->immediate_events
!= NULL
) {
156 *to_ret
= timeval_zero();
160 now
= timeval_current();
161 *to_ret
= timeval_until(&now
, &ev
->timer_events
->next_event
);
163 DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret
->tv_sec
,
164 (int)to_ret
->tv_usec
));
169 static int s3_event_loop_once(struct tevent_context
*ev
, const char *location
)
179 to
.tv_sec
= 9999; /* Max timeout */
182 if (run_events(ev
, &ret
, NULL
, NULL
)) {
186 if (!event_add_to_select_args(ev
, &r_fds
, &w_fds
, &to
, &maxfd
)) {
190 ret
= sys_select(maxfd
+1, &r_fds
, &w_fds
, NULL
, &to
);
192 if (ret
== -1 && errno
!= EINTR
) {
193 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
194 "sys_select() failed: %d:%s\n",
195 errno
, strerror(errno
));
199 run_events(ev
, &ret
, &r_fds
, &w_fds
);
203 static int s3_event_context_init(struct tevent_context
*ev
)
208 void dump_event_list(struct tevent_context
*ev
)
210 struct tevent_timer
*te
;
211 struct tevent_fd
*fe
;
212 struct timeval evt
, now
;
218 now
= timeval_current();
220 DEBUG(10,("dump_event_list:\n"));
222 for (te
= ev
->timer_events
; te
; te
= te
->next
) {
224 evt
= timeval_until(&now
, &te
->next_event
);
226 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
230 http_timestring(talloc_tos(), te
->next_event
.tv_sec
)));
233 for (fe
= ev
->fd_events
; fe
; fe
= fe
->next
) {
235 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
242 static const struct tevent_ops s3_event_ops
= {
243 .context_init
= s3_event_context_init
,
244 .add_fd
= tevent_common_add_fd
,
245 .set_fd_close_fn
= tevent_common_fd_set_close_fn
,
246 .get_fd_flags
= tevent_common_fd_get_flags
,
247 .set_fd_flags
= tevent_common_fd_set_flags
,
248 .add_timer
= tevent_common_add_timer
,
249 .schedule_immediate
= tevent_common_schedule_immediate
,
250 .add_signal
= tevent_common_add_signal
,
251 .loop_once
= s3_event_loop_once
,
252 .loop_wait
= tevent_common_loop_wait
,
255 static bool s3_tevent_init(void)
257 static bool initialized
;
261 initialized
= tevent_register_backend("s3", &s3_event_ops
);
262 tevent_set_default_backend("s3");
267 this is used to catch debug messages from events
269 static void s3_event_debug(void *context
, enum tevent_debug_level level
,
270 const char *fmt
, va_list ap
) PRINTF_ATTRIBUTE(3,0);
272 static void s3_event_debug(void *context
, enum tevent_debug_level level
,
273 const char *fmt
, va_list ap
)
275 int samba_level
= -1;
278 case TEVENT_DEBUG_FATAL
:
281 case TEVENT_DEBUG_ERROR
:
284 case TEVENT_DEBUG_WARNING
:
287 case TEVENT_DEBUG_TRACE
:
292 if (vasprintf(&s
, fmt
, ap
) == -1) {
295 DEBUG(samba_level
, ("s3_event: %s", s
));
299 struct tevent_context
*s3_tevent_context_init(TALLOC_CTX
*mem_ctx
)
301 struct tevent_context
*ev
;
305 ev
= tevent_context_init_byname(mem_ctx
, "s3");
307 tevent_set_debug(ev
, s3_event_debug
, NULL
);