Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / bind-9.3 / lib / bind / isc / ev_timers.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1995-1999 by Internet Software Consortium
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* ev_timers.c - implement timers for the eventlib
19  * vix 09sep95 [initial]
20  */
21
22 #if !defined(LINT) && !defined(CODECENTER)
23 static const char rcsid[] = "$Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka Exp $";
24 #endif
25
26 /* Import. */
27
28 #include "port_before.h"
29 #include "fd_setsize.h"
30
31 #include <errno.h>
32
33 #include <isc/assertions.h>
34 #include <isc/eventlib.h>
35 #include "eventlib_p.h"
36
37 #include "port_after.h"
38
39 /* Constants. */
40
41 #define MILLION 1000000
42 #define BILLION 1000000000
43
44 /* Forward. */
45
46 static int due_sooner(void *, void *);
47 static void set_index(void *, int);
48 static void free_timer(void *, void *);
49 static void print_timer(void *, void *);
50 static void idle_timeout(evContext, void *, struct timespec, struct timespec);
51
52 /* Private type. */
53
54 typedef struct {
55         evTimerFunc     func;
56         void *          uap;
57         struct timespec lastTouched;
58         struct timespec max_idle;
59         evTimer *       timer;
60 } idle_timer;
61
62 /* Public. */
63
64 struct timespec
65 evConsTime(time_t sec, long nsec) {
66         struct timespec x;
67
68         x.tv_sec = sec;
69         x.tv_nsec = nsec;
70         return (x);
71 }
72
73 struct timespec
74 evAddTime(struct timespec addend1, struct timespec addend2) {
75         struct timespec x;
76
77         x.tv_sec = addend1.tv_sec + addend2.tv_sec;
78         x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
79         if (x.tv_nsec >= BILLION) {
80                 x.tv_sec++;
81                 x.tv_nsec -= BILLION;
82         }
83         return (x);
84 }
85
86 struct timespec
87 evSubTime(struct timespec minuend, struct timespec subtrahend) {
88         struct timespec x;
89
90         x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
91         if (minuend.tv_nsec >= subtrahend.tv_nsec)
92                 x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
93         else {
94                 x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
95                 x.tv_sec--;
96         }
97         return (x);
98 }
99
100 int
101 evCmpTime(struct timespec a, struct timespec b) {
102         long x = a.tv_sec - b.tv_sec;
103
104         if (x == 0L)
105                 x = a.tv_nsec - b.tv_nsec;
106         return (x < 0L ? (-1) : x > 0L ? (1) : (0));
107 }
108
109 struct timespec
110 evNowTime() {
111         struct timeval now;
112 #ifdef CLOCK_REALTIME
113         struct timespec tsnow;
114         int m = CLOCK_REALTIME;
115
116 #ifdef CLOCK_MONOTONIC
117         if (__evOptMonoTime)
118                 m = CLOCK_MONOTONIC;
119 #endif
120         if (clock_gettime(m, &tsnow) == 0)
121                 return (tsnow);
122 #endif
123         if (gettimeofday(&now, NULL) < 0)
124                 return (evConsTime(0, 0));
125         return (evTimeSpec(now));
126 }
127
128 struct timespec
129 evUTCTime() {
130         struct timeval now;
131 #ifdef CLOCK_REALTIME
132         struct timespec tsnow;
133         if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
134                 return (tsnow);
135 #endif
136         if (gettimeofday(&now, NULL) < 0)
137                 return (evConsTime(0, 0));
138         return (evTimeSpec(now));
139 }
140
141 struct timespec
142 evLastEventTime(evContext opaqueCtx) {
143         evContext_p *ctx = opaqueCtx.opaque;
144
145         return (ctx->lastEventTime);
146 }
147
148 struct timespec
149 evTimeSpec(struct timeval tv) {
150         struct timespec ts;
151
152         ts.tv_sec = tv.tv_sec;
153         ts.tv_nsec = tv.tv_usec * 1000;
154         return (ts);
155 }
156
157 struct timeval
158 evTimeVal(struct timespec ts) {
159         struct timeval tv;
160
161         tv.tv_sec = ts.tv_sec;
162         tv.tv_usec = ts.tv_nsec / 1000;
163         return (tv);
164 }
165
166 int
167 evSetTimer(evContext opaqueCtx,
168            evTimerFunc func,
169            void *uap,
170            struct timespec due,
171            struct timespec inter,
172            evTimerID *opaqueID
173 ) {
174         evContext_p *ctx = opaqueCtx.opaque;
175         evTimer *id;
176
177         evPrintf(ctx, 1,
178 "evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
179                  ctx, func, uap,
180                  (long)due.tv_sec, due.tv_nsec,
181                  (long)inter.tv_sec, inter.tv_nsec);
182
183 #ifdef __hpux
184         /*
185          * tv_sec and tv_nsec are unsigned.
186          */
187         if (due.tv_nsec >= BILLION)
188                 EV_ERR(EINVAL);
189
190         if (inter.tv_nsec >= BILLION)
191                 EV_ERR(EINVAL);
192 #else
193         if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
194                 EV_ERR(EINVAL);
195
196         if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
197                 EV_ERR(EINVAL);
198 #endif
199
200         /* due={0,0} is a magic cookie meaning "now." */
201         if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
202                 due = evNowTime();
203
204         /* Allocate and fill. */
205         OKNEW(id);
206         id->func = func;
207         id->uap = uap;
208         id->due = due;
209         id->inter = inter;
210
211         if (heap_insert(ctx->timers, id) < 0)
212                 return (-1);
213
214         /* Remember the ID if the caller provided us a place for it. */
215         if (opaqueID)
216                 opaqueID->opaque = id;
217
218         if (ctx->debug > 7) {
219                 evPrintf(ctx, 7, "timers after evSetTimer:\n");
220                 (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
221         }
222
223         return (0);
224 }
225
226 int
227 evClearTimer(evContext opaqueCtx, evTimerID id) {
228         evContext_p *ctx = opaqueCtx.opaque;
229         evTimer *del = id.opaque;
230
231         if (ctx->cur != NULL &&
232             ctx->cur->type == Timer &&
233             ctx->cur->u.timer.this == del) {
234                 evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
235                 /*
236                  * Setting the interval to zero ensures that evDrop() will
237                  * clean up the timer.
238                  */
239                 del->inter = evConsTime(0, 0);
240                 return (0);
241         }
242
243         if (heap_element(ctx->timers, del->index) != del)
244                 EV_ERR(ENOENT);
245
246         if (heap_delete(ctx->timers, del->index) < 0)
247                 return (-1);
248         FREE(del);
249
250         if (ctx->debug > 7) {
251                 evPrintf(ctx, 7, "timers after evClearTimer:\n");
252                 (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
253         }
254
255         return (0);
256 }
257
258 int
259 evConfigTimer(evContext opaqueCtx,
260              evTimerID id,
261              const char *param,
262              int value
263 ) {
264         evContext_p *ctx = opaqueCtx.opaque;
265         evTimer *timer = id.opaque;
266         int result=0;
267
268         UNUSED(value);
269
270         if (heap_element(ctx->timers, timer->index) != timer)
271                 EV_ERR(ENOENT);
272
273         if (strcmp(param, "rate") == 0)
274                 timer->mode |= EV_TMR_RATE;
275         else if (strcmp(param, "interval") == 0)
276                 timer->mode &= ~EV_TMR_RATE;
277         else
278                 EV_ERR(EINVAL);
279
280         return (result);
281 }
282
283 int
284 evResetTimer(evContext opaqueCtx,
285              evTimerID id,
286              evTimerFunc func,
287              void *uap,
288              struct timespec due,
289              struct timespec inter
290 ) {
291         evContext_p *ctx = opaqueCtx.opaque;
292         evTimer *timer = id.opaque;
293         struct timespec old_due;
294         int result=0;
295
296         if (heap_element(ctx->timers, timer->index) != timer)
297                 EV_ERR(ENOENT);
298
299 #ifdef __hpux
300         /*
301          * tv_sec and tv_nsec are unsigned.
302          */
303         if (due.tv_nsec >= BILLION)
304                 EV_ERR(EINVAL);
305
306         if (inter.tv_nsec >= BILLION)
307                 EV_ERR(EINVAL);
308 #else
309         if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
310                 EV_ERR(EINVAL);
311
312         if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
313                 EV_ERR(EINVAL);
314 #endif
315
316         old_due = timer->due;
317
318         timer->func = func;
319         timer->uap = uap;
320         timer->due = due;
321         timer->inter = inter;
322
323         switch (evCmpTime(due, old_due)) {
324         case -1:
325                 result = heap_increased(ctx->timers, timer->index);
326                 break;
327         case 0:
328                 result = 0;
329                 break;
330         case 1:
331                 result = heap_decreased(ctx->timers, timer->index);
332                 break;
333         }
334
335         if (ctx->debug > 7) {
336                 evPrintf(ctx, 7, "timers after evResetTimer:\n");
337                 (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
338         }
339
340         return (result);
341 }
342
343 int
344 evSetIdleTimer(evContext opaqueCtx,
345                 evTimerFunc func,
346                 void *uap,
347                 struct timespec max_idle,
348                 evTimerID *opaqueID
349 ) {
350         evContext_p *ctx = opaqueCtx.opaque;
351         idle_timer *tt;
352
353         /* Allocate and fill. */
354         OKNEW(tt);
355         tt->func = func;
356         tt->uap = uap;
357         tt->lastTouched = ctx->lastEventTime;
358         tt->max_idle = max_idle;
359
360         if (evSetTimer(opaqueCtx, idle_timeout, tt,
361                        evAddTime(ctx->lastEventTime, max_idle),
362                        max_idle, opaqueID) < 0) {
363                 FREE(tt);
364                 return (-1);
365         }
366
367         tt->timer = opaqueID->opaque;
368
369         return (0);
370 }
371
372 int
373 evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
374         evTimer *del = id.opaque;
375         idle_timer *tt = del->uap;
376
377         FREE(tt);
378         return (evClearTimer(opaqueCtx, id));
379 }
380
381 int
382 evResetIdleTimer(evContext opaqueCtx,
383                  evTimerID opaqueID,
384                  evTimerFunc func,
385                  void *uap,
386                  struct timespec max_idle
387 ) {
388         evContext_p *ctx = opaqueCtx.opaque;
389         evTimer *timer = opaqueID.opaque;
390         idle_timer *tt = timer->uap;
391
392         tt->func = func;
393         tt->uap = uap;
394         tt->lastTouched = ctx->lastEventTime;
395         tt->max_idle = max_idle;
396
397         return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
398                              evAddTime(ctx->lastEventTime, max_idle),
399                              max_idle));
400 }
401
402 int
403 evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
404         evContext_p *ctx = opaqueCtx.opaque;
405         evTimer *t = id.opaque;
406         idle_timer *tt = t->uap;
407
408         tt->lastTouched = ctx->lastEventTime;
409
410         return (0);
411 }
412
413 /* Public to the rest of eventlib. */
414
415 heap_context
416 evCreateTimers(const evContext_p *ctx) {
417
418         UNUSED(ctx);
419
420         return (heap_new(due_sooner, set_index, 2048));
421 }
422
423 void
424 evDestroyTimers(const evContext_p *ctx) {
425         (void) heap_for_each(ctx->timers, free_timer, NULL);
426         (void) heap_free(ctx->timers);
427 }
428
429 /* Private. */
430
431 static int
432 due_sooner(void *a, void *b) {
433         evTimer *a_timer, *b_timer;
434
435         a_timer = a;
436         b_timer = b;
437         return (evCmpTime(a_timer->due, b_timer->due) < 0);
438 }
439
440 static void
441 set_index(void *what, int index) {
442         evTimer *timer;
443
444         timer = what;
445         timer->index = index;
446 }
447
448 static void
449 free_timer(void *what, void *uap) {
450         evTimer *t = what;
451
452         UNUSED(uap);
453
454         FREE(t);
455 }
456
457 static void
458 print_timer(void *what, void *uap) {
459         evTimer *cur = what;
460         evContext_p *ctx = uap;
461
462         cur = what;
463         evPrintf(ctx, 7,
464             "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
465                  cur->func, cur->uap,
466                  (long)cur->due.tv_sec, cur->due.tv_nsec,
467                  (long)cur->inter.tv_sec, cur->inter.tv_nsec);
468 }
469
470 static void
471 idle_timeout(evContext opaqueCtx,
472              void *uap,
473              struct timespec due,
474              struct timespec inter
475 ) {
476         evContext_p *ctx = opaqueCtx.opaque;
477         idle_timer *this = uap;
478         struct timespec idle;
479
480         UNUSED(due);
481         UNUSED(inter);
482         
483         idle = evSubTime(ctx->lastEventTime, this->lastTouched);
484         if (evCmpTime(idle, this->max_idle) >= 0) {
485                 (this->func)(opaqueCtx, this->uap, this->timer->due,
486                              this->max_idle);
487                 /*
488                  * Setting the interval to zero will cause the timer to
489                  * be cleaned up in evDrop().
490                  */
491                 this->timer->inter = evConsTime(0, 0);
492                 FREE(this);
493         } else {
494                 /* evDrop() will reschedule the timer. */
495                 this->timer->inter = evSubTime(this->max_idle, idle);
496         }
497 }