1 /*
2 * Copyright (c) 2016-2021 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/queue.h>
20
21 #include "kore.h"
22
23 TAILQ_HEAD(timerlist, kore_timer) kore_timers;
24
25 void
kore_timer_init(void)26 kore_timer_init(void)
27 {
28 TAILQ_INIT(&kore_timers);
29 }
30
31 struct kore_timer *
kore_timer_add(void (* cb)(void *,u_int64_t),u_int64_t interval,void * arg,int flags)32 kore_timer_add(void (*cb)(void *, u_int64_t), u_int64_t interval,
33 void *arg, int flags)
34 {
35 struct kore_timer *timer, *t;
36
37 timer = kore_malloc(sizeof(*timer));
38
39 timer->cb = cb;
40 timer->arg = arg;
41 timer->flags = flags;
42 timer->interval = interval;
43 timer->nextrun = kore_time_ms() + timer->interval;
44
45 TAILQ_FOREACH(t, &kore_timers, list) {
46 if (t->nextrun > timer->nextrun) {
47 TAILQ_INSERT_BEFORE(t, timer, list);
48 return (timer);
49 }
50 }
51
52 TAILQ_INSERT_TAIL(&kore_timers, timer, list);
53 return (timer);
54 }
55
56 void
kore_timer_remove(struct kore_timer * timer)57 kore_timer_remove(struct kore_timer *timer)
58 {
59 TAILQ_REMOVE(&kore_timers, timer, list);
60 kore_free(timer);
61 }
62
63 u_int64_t
kore_timer_next_run(u_int64_t now)64 kore_timer_next_run(u_int64_t now)
65 {
66 struct kore_timer *timer;
67
68 if ((timer = TAILQ_FIRST(&kore_timers)) != NULL) {
69 if (timer->nextrun > now)
70 return (timer->nextrun - now);
71 return (0);
72 }
73
74 return (KORE_WAIT_INFINITE);
75 }
76
77 void
kore_timer_run(u_int64_t now)78 kore_timer_run(u_int64_t now)
79 {
80 struct kore_timer *timer, *t, *prev;
81
82 prev = NULL;
83
84 while ((timer = TAILQ_FIRST(&kore_timers)) != NULL) {
85 if (timer == prev)
86 break;
87
88 if (timer->nextrun > now)
89 break;
90
91 TAILQ_REMOVE(&kore_timers, timer, list);
92 timer->cb(timer->arg, now);
93
94 if (timer->flags & KORE_TIMER_ONESHOT) {
95 kore_free(timer);
96 } else {
97 prev = timer;
98 timer->nextrun = now + timer->interval;
99 TAILQ_FOREACH(t, &kore_timers, list) {
100 if (t->nextrun > timer->nextrun) {
101 TAILQ_INSERT_BEFORE(t, timer, list);
102 break;
103 }
104 }
105
106 if (t == NULL)
107 TAILQ_INSERT_TAIL(&kore_timers, timer, list);
108 }
109 }
110 }
111