1 /*
2 * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
3 * Copyright (c) 2005-2007 Atheme Project (http://www.atheme.org)
4 *
5 * Permission to use, copy, modify, and/or 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 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
10 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
12 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
13 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
14 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
17 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
18 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
19 * POSSIBILITY OF SUCH DAMAGE.
20 */
21
22 #include "mowgli.h"
23
24 static mowgli_heap_t *timer_heap = NULL;
25
26 static mowgli_eventloop_timer_t *
mowgli_timer_add_real(mowgli_eventloop_t * eventloop,const char * name,mowgli_event_dispatch_func_t * func,void * arg,time_t when,time_t frequency)27 mowgli_timer_add_real(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when, time_t frequency)
28 {
29 mowgli_eventloop_timer_t *timer;
30
31 return_val_if_fail(eventloop != NULL, NULL);
32 return_val_if_fail(func != NULL, NULL);
33
34 if (timer_heap == NULL)
35 timer_heap = mowgli_heap_create(sizeof(mowgli_eventloop_timer_t), 16, BH_NOW);
36
37 timer = mowgli_heap_alloc(timer_heap);
38
39 timer->func = func;
40 timer->name = name;
41 timer->arg = arg;
42 timer->deadline = mowgli_eventloop_get_time(eventloop) + when;
43 timer->frequency = frequency;
44 timer->active = true;
45
46 if (eventloop->deadline != -1 && timer->deadline <= eventloop->deadline)
47 eventloop->deadline = timer->deadline;
48
49 mowgli_node_add(timer, &timer->node, &eventloop->timer_list);
50
51 #ifdef DEBUG
52 mowgli_log("[timer(%p) add when:%d active:%d] [eventloop deadline:%d]", timer, timer->deadline, timer->active, eventloop->deadline);
53 #endif
54
55 return timer;
56 }
57
58 /* add an event to the table to be continually ran */
59 mowgli_eventloop_timer_t *
mowgli_timer_add(mowgli_eventloop_t * eventloop,const char * name,mowgli_event_dispatch_func_t * func,void * arg,time_t when)60 mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when)
61 {
62 return mowgli_timer_add_real(eventloop, name, func, arg, when, when);
63 }
64
65 /* adds an event to the table to be ran only once */
66 mowgli_eventloop_timer_t *
mowgli_timer_add_once(mowgli_eventloop_t * eventloop,const char * name,mowgli_event_dispatch_func_t * func,void * arg,time_t when)67 mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when)
68 {
69 return mowgli_timer_add_real(eventloop, name, func, arg, when, 0);
70 }
71
72 /* delete an event from the table */
73 void
mowgli_timer_destroy(mowgli_eventloop_t * eventloop,mowgli_eventloop_timer_t * timer)74 mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer)
75 {
76 return_if_fail(eventloop != NULL);
77 return_if_fail(timer != NULL);
78
79 if (eventloop->last_ran == timer->name)
80 eventloop->last_ran = "<removed>";
81
82 mowgli_node_delete(&timer->node, &eventloop->timer_list);
83 mowgli_heap_free(timer_heap, timer);
84 }
85
86 /* checks all pending events */
87 void
mowgli_eventloop_run_timers(mowgli_eventloop_t * eventloop)88 mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop)
89 {
90 mowgli_node_t *n, *tn;
91 time_t currtime;
92
93 return_if_fail(eventloop != NULL);
94
95 currtime = mowgli_eventloop_get_time(eventloop);
96
97 MOWGLI_ITER_FOREACH_SAFE(n, tn, eventloop->timer_list.head)
98 {
99 mowgli_eventloop_timer_t *timer = n->data;
100
101 if (timer->active && (timer->deadline <= currtime))
102 {
103 /* now we call it */
104 eventloop->last_ran = timer->name;
105 timer->func(timer->arg);
106
107 /* invalidate eventloop sleep-until time */
108 eventloop->deadline = -1;
109
110 /* event is scheduled more than once */
111 if (timer->frequency)
112 {
113 timer->deadline = currtime + timer->frequency;
114 }
115 else
116 {
117 /* XXX: yuck. find a better way to handle this. */
118 eventloop->last_ran = "<onceonly>";
119
120 mowgli_timer_destroy(eventloop, timer);
121 }
122 }
123 }
124 }
125
126 /* returns the time the next mowgli_timer_run() should happen */
127 time_t
mowgli_eventloop_next_timer(mowgli_eventloop_t * eventloop)128 mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop)
129 {
130 mowgli_node_t *n;
131
132 return_val_if_fail(eventloop != NULL, 0);
133
134 if (eventloop->deadline == -1)
135 MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head)
136 {
137 mowgli_eventloop_timer_t *timer = n->data;
138
139 if (timer->active && ((timer->deadline < eventloop->deadline) || (eventloop->deadline == -1)))
140 eventloop->deadline = timer->deadline;
141
142 #ifdef DEBUG
143 mowgli_log("timer %p active:%d when:%ld deadline:%ld", timer, timer->active, timer->deadline, eventloop->deadline);
144 #endif
145 }
146
147 #ifdef DEBUG
148 mowgli_log("eventloop deadline:%ld", eventloop->deadline);
149
150 #endif
151
152 return eventloop->deadline;
153 }
154
155 /* finds an event in the table */
156 mowgli_eventloop_timer_t *
mowgli_timer_find(mowgli_eventloop_t * eventloop,mowgli_event_dispatch_func_t * func,void * arg)157 mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg)
158 {
159 mowgli_node_t *n;
160
161 return_val_if_fail(eventloop != NULL, NULL);
162 return_val_if_fail(func != NULL, NULL);
163
164 MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head)
165 {
166 mowgli_eventloop_timer_t *timer = n->data;
167
168 if ((timer->func == func) && (timer->arg == arg))
169 return timer;
170 }
171
172 return NULL;
173 }
174
175 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
176 * vim:ts=8
177 * vim:sw=8
178 * vim:noexpandtab
179 */
180