tests: Fix intermittent error in PSO test
[kai/samba-autobuild/.git] / lib / tevent / tevent_timed.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    common events code for timed events
5
6    Copyright (C) Andrew Tridgell        2003-2006
7    Copyright (C) Stefan Metzmacher      2005-2009
8
9      ** NOTE! The following LGPL license applies to the tevent
10      ** library. This does NOT imply that all of Samba is released
11      ** under the LGPL
12
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 3 of the License, or (at your option) any later version.
17
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include "replace.h"
28 #include "system/time.h"
29 #include "tevent.h"
30 #include "tevent_internal.h"
31 #include "tevent_util.h"
32
33 /**
34   compare two timeval structures. 
35   Return -1 if tv1 < tv2
36   Return 0 if tv1 == tv2
37   Return 1 if tv1 > tv2
38 */
39 int tevent_timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
40 {
41         if (tv1->tv_sec  > tv2->tv_sec)  return 1;
42         if (tv1->tv_sec  < tv2->tv_sec)  return -1;
43         if (tv1->tv_usec > tv2->tv_usec) return 1;
44         if (tv1->tv_usec < tv2->tv_usec) return -1;
45         return 0;
46 }
47
48 /**
49   return a zero timeval
50 */
51 struct timeval tevent_timeval_zero(void)
52 {
53         struct timeval tv;
54         tv.tv_sec = 0;
55         tv.tv_usec = 0;
56         return tv;
57 }
58
59 /**
60   return a timeval for the current time
61 */
62 struct timeval tevent_timeval_current(void)
63 {
64         struct timeval tv;
65         gettimeofday(&tv, NULL);
66         return tv;
67 }
68
69 /**
70   return a timeval struct with the given elements
71 */
72 struct timeval tevent_timeval_set(uint32_t secs, uint32_t usecs)
73 {
74         struct timeval tv;
75         tv.tv_sec = secs;
76         tv.tv_usec = usecs;
77         return tv;
78 }
79
80 /**
81   return the difference between two timevals as a timeval
82   if tv1 comes after tv2, then return a zero timeval
83   (this is *tv2 - *tv1)
84 */
85 struct timeval tevent_timeval_until(const struct timeval *tv1,
86                                     const struct timeval *tv2)
87 {
88         struct timeval t;
89         if (tevent_timeval_compare(tv1, tv2) >= 0) {
90                 return tevent_timeval_zero();
91         }
92         t.tv_sec = tv2->tv_sec - tv1->tv_sec;
93         if (tv1->tv_usec > tv2->tv_usec) {
94                 t.tv_sec--;
95                 t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
96         } else {
97                 t.tv_usec = tv2->tv_usec - tv1->tv_usec;
98         }
99         return t;
100 }
101
102 /**
103   return true if a timeval is zero
104 */
105 bool tevent_timeval_is_zero(const struct timeval *tv)
106 {
107         return tv->tv_sec == 0 && tv->tv_usec == 0;
108 }
109
110 struct timeval tevent_timeval_add(const struct timeval *tv, uint32_t secs,
111                                   uint32_t usecs)
112 {
113         struct timeval tv2 = *tv;
114         tv2.tv_sec += secs;
115         tv2.tv_usec += usecs;
116         tv2.tv_sec += tv2.tv_usec / 1000000;
117         tv2.tv_usec = tv2.tv_usec % 1000000;
118
119         return tv2;
120 }
121
122 /**
123   return a timeval in the future with a specified offset
124 */
125 struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
126 {
127         struct timeval tv = tevent_timeval_current();
128         return tevent_timeval_add(&tv, secs, usecs);
129 }
130
131 /*
132   destroy a timed event
133 */
134 static int tevent_common_timed_destructor(struct tevent_timer *te)
135 {
136         if (te->event_ctx == NULL) {
137                 return 0;
138         }
139
140         tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
141                      "Destroying timer event %p \"%s\"\n",
142                      te, te->handler_name);
143
144         if (te->event_ctx->last_zero_timer == te) {
145                 te->event_ctx->last_zero_timer = DLIST_PREV(te);
146         }
147         DLIST_REMOVE(te->event_ctx->timer_events, te);
148
149         return 0;
150 }
151
152 static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
153 {
154         return -1;
155 }
156
157 static void tevent_common_insert_timer(struct tevent_context *ev,
158                                        struct tevent_timer *te,
159                                        bool optimize_zero)
160 {
161         struct tevent_timer *prev_te = NULL;
162
163         /* keep the list ordered */
164         if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) {
165                 /*
166                  * Some callers use zero tevent_timer
167                  * instead of tevent_immediate events.
168                  *
169                  * As these can happen very often,
170                  * we remember the last zero timer
171                  * in the list.
172                  */
173                 prev_te = ev->last_zero_timer;
174                 ev->last_zero_timer = te;
175         } else {
176                 struct tevent_timer *cur_te;
177
178                 /*
179                  * we traverse the list from the tail
180                  * because it's much more likely that
181                  * timers are added at the end of the list
182                  */
183                 for (cur_te = DLIST_TAIL(ev->timer_events);
184                      cur_te != NULL;
185                      cur_te = DLIST_PREV(cur_te))
186                 {
187                         int ret;
188
189                         /*
190                          * if the new event comes before the current
191                          * we continue searching
192                          */
193                         ret = tevent_timeval_compare(&te->next_event,
194                                                      &cur_te->next_event);
195                         if (ret < 0) {
196                                 continue;
197                         }
198
199                         break;
200                 }
201
202                 prev_te = cur_te;
203         }
204
205         DLIST_ADD_AFTER(ev->timer_events, te, prev_te);
206 }
207
208 /*
209   add a timed event
210   return NULL on failure (memory allocation error)
211 */
212 static struct tevent_timer *tevent_common_add_timer_internal(
213                                         struct tevent_context *ev,
214                                         TALLOC_CTX *mem_ctx,
215                                         struct timeval next_event,
216                                         tevent_timer_handler_t handler,
217                                         void *private_data,
218                                         const char *handler_name,
219                                         const char *location,
220                                         bool optimize_zero)
221 {
222         struct tevent_timer *te;
223
224         te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
225         if (te == NULL) return NULL;
226
227         te->event_ctx           = ev;
228         te->next_event          = next_event;
229         te->handler             = handler;
230         te->private_data        = private_data;
231         te->handler_name        = handler_name;
232         te->location            = location;
233         te->additional_data     = NULL;
234
235         if (ev->timer_events == NULL) {
236                 ev->last_zero_timer = NULL;
237         }
238
239         tevent_common_insert_timer(ev, te, optimize_zero);
240
241         talloc_set_destructor(te, tevent_common_timed_destructor);
242
243         tevent_debug(ev, TEVENT_DEBUG_TRACE,
244                      "Added timed event \"%s\": %p\n",
245                      handler_name, te);
246         return te;
247 }
248
249 struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
250                                              TALLOC_CTX *mem_ctx,
251                                              struct timeval next_event,
252                                              tevent_timer_handler_t handler,
253                                              void *private_data,
254                                              const char *handler_name,
255                                              const char *location)
256 {
257         /*
258          * do not use optimization, there are broken Samba
259          * versions which use tevent_common_add_timer()
260          * without using tevent_common_loop_timer_delay(),
261          * it just uses DLIST_REMOVE(ev->timer_events, te)
262          * and would leave ev->last_zero_timer behind.
263          */
264         return tevent_common_add_timer_internal(ev, mem_ctx, next_event,
265                                                 handler, private_data,
266                                                 handler_name, location,
267                                                 false);
268 }
269
270 struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
271                                                 TALLOC_CTX *mem_ctx,
272                                                 struct timeval next_event,
273                                                 tevent_timer_handler_t handler,
274                                                 void *private_data,
275                                                 const char *handler_name,
276                                                 const char *location)
277 {
278         /*
279          * Here we turn on last_zero_timer optimization
280          */
281         return tevent_common_add_timer_internal(ev, mem_ctx, next_event,
282                                                 handler, private_data,
283                                                 handler_name, location,
284                                                 true);
285 }
286
287 void tevent_update_timer(struct tevent_timer *te, struct timeval next_event)
288 {
289         struct tevent_context *ev = te->event_ctx;
290
291         if (ev->last_zero_timer == te) {
292                 te->event_ctx->last_zero_timer = DLIST_PREV(te);
293         }
294         DLIST_REMOVE(ev->timer_events, te);
295
296         te->next_event = next_event;
297
298         /*
299          * Not doing the zero_timer optimization. This is for new code
300          * that should know about immediates.
301          */
302         tevent_common_insert_timer(ev, te, false);
303 }
304
305 /*
306   do a single event loop using the events defined in ev
307
308   return the delay until the next timed event,
309   or zero if a timed event was triggered
310 */
311 struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
312 {
313         struct timeval current_time = tevent_timeval_zero();
314         struct tevent_timer *te = ev->timer_events;
315
316         if (!te) {
317                 /* have a default tick time of 30 seconds. This guarantees
318                    that code that uses its own timeout checking will be
319                    able to proceed eventually */
320                 return tevent_timeval_set(30, 0);
321         }
322
323         /*
324          * work out the right timeout for the next timed event
325          *
326          * avoid the syscall to gettimeofday() if the timed event should
327          * be triggered directly
328          *
329          * if there's a delay till the next timed event, we're done
330          * with just returning the delay
331          */
332         if (!tevent_timeval_is_zero(&te->next_event)) {
333                 struct timeval delay;
334
335                 current_time = tevent_timeval_current();
336
337                 delay = tevent_timeval_until(&current_time, &te->next_event);
338                 if (!tevent_timeval_is_zero(&delay)) {
339                         return delay;
340                 }
341         }
342
343         /*
344          * ok, we have a timed event that we'll process ...
345          */
346
347         /* deny the handler to free the event */
348         talloc_set_destructor(te, tevent_common_timed_deny_destructor);
349
350         /* We need to remove the timer from the list before calling the
351          * handler because in a semi-async inner event loop called from the
352          * handler we don't want to come across this event again -- vl */
353         if (ev->last_zero_timer == te) {
354                 ev->last_zero_timer = DLIST_PREV(te);
355         }
356         DLIST_REMOVE(ev->timer_events, te);
357
358         tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
359                      "Running timer event %p \"%s\"\n",
360                      te, te->handler_name);
361
362         /*
363          * If the timed event was registered for a zero current_time,
364          * then we pass a zero timeval here too! To avoid the
365          * overhead of gettimeofday() calls.
366          *
367          * otherwise we pass the current time
368          */
369         te->handler(ev, te, current_time, te->private_data);
370
371         /* The destructor isn't necessary anymore, we've already removed the
372          * event from the list. */
373         talloc_set_destructor(te, NULL);
374
375         tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
376                      "Ending timer event %p \"%s\"\n",
377                      te, te->handler_name);
378
379         talloc_free(te);
380
381         return tevent_timeval_zero();
382 }
383