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