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