s4:ldb:python/api: use only one ldb file in test_contains()
[Samba/gebeck_regimport.git] / source3 / lib / events.c
blobd987072884d361aed67b150582c2ea29fbbaa60e
1 /*
2 Unix SMB/CIFS implementation.
3 Timed event library.
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/>.
21 #include "includes.h"
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)
33 struct timeval now;
34 struct tevent_fd *fde;
35 struct timeval diff;
36 bool ret = false;
38 for (fde = ev->fd_events; fde; fde = fde->next) {
39 if (fde->flags & EVENT_FD_READ) {
40 FD_SET(fde->fd, read_fds);
41 ret = true;
43 if (fde->flags & EVENT_FD_WRITE) {
44 FD_SET(fde->fd, write_fds);
45 ret = true;
48 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
49 && (fde->fd > *maxfd)) {
50 *maxfd = fde->fd;
54 if (ev->immediate_events != NULL) {
55 *timeout = timeval_zero();
56 return true;
59 if (ev->timer_events == NULL) {
60 return ret;
63 now = timeval_current();
64 diff = timeval_until(&now, &ev->timer_events->next_event);
65 *timeout = timeval_min(timeout, &diff);
67 return true;
70 bool run_events(struct tevent_context *ev,
71 int *selrtn, fd_set *read_fds, fd_set *write_fds)
73 struct tevent_fd *fde;
74 struct timeval now;
76 if (ev->signal_events &&
77 tevent_common_check_signal(ev)) {
78 return true;
81 if (ev->immediate_events &&
82 tevent_common_loop_immediate(ev)) {
83 return true;
86 GetTimeOfDay(&now);
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);
113 return true;
116 if (*selrtn <= 0) {
118 * No fd ready
120 return false;
123 for (fde = ev->fd_events; fde; fde = fde->next) {
124 uint16 flags = 0;
126 if (FD_ISSET(fde->fd, read_fds)) {
127 flags |= EVENT_FD_READ;
128 FD_CLR(fde->fd, read_fds);
129 (*selrtn)--;
131 if (FD_ISSET(fde->fd, write_fds)) {
132 flags |= EVENT_FD_WRITE;
133 FD_CLR(fde->fd, write_fds);
134 (*selrtn)--;
137 if (flags & fde->flags) {
138 fde->handler(ev, fde, flags, fde->private_data);
139 return true;
143 return false;
147 struct timeval *get_timed_events_timeout(struct tevent_context *ev,
148 struct timeval *to_ret)
150 struct timeval now;
152 if ((ev->timer_events == NULL) && (ev->immediate_events == NULL)) {
153 return NULL;
155 if (ev->immediate_events != NULL) {
156 *to_ret = timeval_zero();
157 return to_ret;
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));
166 return to_ret;
169 static int s3_event_loop_once(struct tevent_context *ev, const char *location)
171 struct timeval to;
172 fd_set r_fds, w_fds;
173 int maxfd = 0;
174 int ret = 0;
176 FD_ZERO(&r_fds);
177 FD_ZERO(&w_fds);
179 to.tv_sec = 9999; /* Max timeout */
180 to.tv_usec = 0;
182 if (run_events(ev, &ret, NULL, NULL)) {
183 return 0;
186 if (!event_add_to_select_args(ev, &r_fds, &w_fds, &to, &maxfd)) {
187 return -1;
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));
196 return -1;
199 run_events(ev, &ret, &r_fds, &w_fds);
200 return 0;
203 static int s3_event_context_init(struct tevent_context *ev)
205 return 0;
208 void dump_event_list(struct tevent_context *ev)
210 struct tevent_timer *te;
211 struct tevent_fd *fe;
212 struct timeval evt, now;
214 if (!ev) {
215 return;
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",
227 te->handler_name,
229 (int)evt.tv_sec,
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",
236 fe->fd,
238 fe->flags));
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;
258 if (initialized) {
259 return true;
261 initialized = tevent_register_backend("s3", &s3_event_ops);
262 tevent_set_default_backend("s3");
263 return initialized;
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;
276 char *s = NULL;
277 switch (level) {
278 case TEVENT_DEBUG_FATAL:
279 samba_level = 0;
280 break;
281 case TEVENT_DEBUG_ERROR:
282 samba_level = 1;
283 break;
284 case TEVENT_DEBUG_WARNING:
285 samba_level = 2;
286 break;
287 case TEVENT_DEBUG_TRACE:
288 samba_level = 11;
289 break;
292 if (vasprintf(&s, fmt, ap) == -1) {
293 return;
295 DEBUG(samba_level, ("s3_event: %s", s));
296 free(s);
299 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
301 struct tevent_context *ev;
303 s3_tevent_init();
305 ev = tevent_context_init_byname(mem_ctx, "s3");
306 if (ev) {
307 tevent_set_debug(ev, s3_event_debug, NULL);
310 return ev;