1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2006-2019 Kim Woelders
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include "E.h"
25 #include "list.h"
26 #include "timers.h"
27
28 struct _timer {
29 unsigned int in_time;
30 unsigned int at_time;
31 struct _timer *next;
32 int (*func)(void *data);
33 void *data;
34 char again;
35 };
36
37 static int
tdiff(unsigned int t1,unsigned int t2)38 tdiff(unsigned int t1, unsigned int t2)
39 {
40 return (int)(t1 - t2);
41 }
42
43 static Timer *q_first = NULL;
44
45 static void
_TimerSet(Timer * timer)46 _TimerSet(Timer * timer)
47 {
48 Timer *ptr, *pptr;
49
50 if (EDebug(EDBUG_TYPE_TIMERS) > 1)
51 Eprintf("%s %p: func=%p data=%p\n", __func__, timer, timer->func,
52 timer->data);
53
54 /* if there is no queue it becomes the queue */
55 if (!q_first)
56 {
57 q_first = timer;
58 timer->next = NULL;
59 }
60 else
61 {
62 pptr = NULL;
63 for (ptr = q_first; ptr; pptr = ptr, ptr = ptr->next)
64 {
65 if (tdiff(ptr->at_time, timer->at_time) > 0)
66 break;
67 }
68 if (pptr)
69 pptr->next = timer;
70 else
71 q_first = timer;
72 timer->next = ptr;
73 }
74 }
75
76 static void
_TimerDel(Timer * timer)77 _TimerDel(Timer * timer)
78 {
79 if (EDebug(EDBUG_TYPE_TIMERS))
80 Eprintf("%s %p: func=%p data=%p\n", __func__, timer, timer->func,
81 timer->data);
82 Efree(timer);
83 }
84
85 Timer *
TimerAdd(int dt_ms,int (* func)(void * data),void * data)86 TimerAdd(int dt_ms, int (*func)(void *data), void *data)
87 {
88 Timer *timer;
89
90 timer = EMALLOC(Timer, 1);
91 if (!timer)
92 return NULL;
93
94 timer->in_time = (unsigned int)dt_ms;
95 timer->at_time = GetTimeMs() + dt_ms;
96 timer->func = func;
97 timer->data = data;
98 timer->again = 1;
99
100 if (EDebug(EDBUG_TYPE_TIMERS))
101 Eprintf("%s %p: func=%p data=%p: %8d\n", __func__, timer,
102 timer->func, timer->data, dt_ms);
103
104 _TimerSet(timer); /* Add to timer queue */
105
106 return timer;
107 }
108
109 void
TimersRun(unsigned int t_ms)110 TimersRun(unsigned int t_ms)
111 {
112 Timer *timer, *q_old, *q_run;
113
114 timer = q_first;
115 if (!timer)
116 return; /* No timers pending */
117
118 q_run = q_old = timer;
119 for (; timer; timer = q_first)
120 {
121 if (tdiff(timer->at_time, t_ms) > 0)
122 break;
123
124 if (EDebug(EDBUG_TYPE_TIMERS))
125 Eprintf("%s - run %p: func=%p data=%p: %8d\n", __func__, timer,
126 timer->func, timer->data, timer->at_time - t_ms);
127
128 q_first = timer->next;
129
130 /* Run this callback */
131 timer->again = timer->func(timer->data);
132 q_run = timer;
133 }
134
135 if (q_old != q_first)
136 {
137 /* At least one timer has run */
138 q_run->next = NULL; /* Terminate expired timer list */
139
140 /* Re-schedule/remove timers that have run */
141 for (timer = q_old; timer; timer = q_old)
142 {
143 q_old = timer->next;
144 if (timer->again)
145 {
146 timer->at_time += timer->in_time;
147 _TimerSet(timer); /* Add to timer queue */
148 }
149 else
150 {
151 _TimerDel(timer);
152 }
153 }
154 }
155
156 if (EDebug(EDBUG_TYPE_TIMERS) > 1)
157 {
158 for (timer = q_first; timer; timer = timer->next)
159 Eprintf("%s - pend %p: func=%p data=%p: %8d (%d)\n", __func__,
160 timer, timer->func, timer->data, timer->at_time - t_ms,
161 timer->in_time);
162 }
163 }
164
165 int
TimersRunNextIn(unsigned int t_ms)166 TimersRunNextIn(unsigned int t_ms)
167 {
168 Timer *timer;
169 int dt;
170
171 timer = q_first;
172
173 /* If the next (rescheduled) timer is already expired, set timeout time
174 * to 1 ms. This avoids starving the fd's and should maintain the intended
175 * (mean) timer rate.
176 * The (mean) amount of work done in a timer function should of course not
177 * exceed the timeout time. */
178 if (timer)
179 dt = (int)(timer->at_time - t_ms) > 0 ? (int)(timer->at_time - t_ms) : 1;
180 else
181 dt = 0;
182
183 if (EDebug(EDBUG_TYPE_TIMERS))
184 Eprintf("%s - next in %8d\n", __func__, dt);
185
186 return dt;
187 }
188
189 void
TimerDel(Timer * timer)190 TimerDel(Timer * timer)
191 {
192 Timer *qe, *ptr, *pptr;
193
194 pptr = NULL;
195 for (ptr = q_first; ptr; pptr = ptr, ptr = ptr->next)
196 {
197 qe = ptr;
198 if (qe != timer)
199 continue;
200
201 /* Match - remove it from the queue */
202 if (pptr)
203 pptr->next = qe->next;
204 else
205 q_first = qe->next;
206
207 /* free it */
208 _TimerDel(timer);
209 break;
210 }
211 }
212
213 void
TimerSetInterval(Timer * timer,int dt_ms)214 TimerSetInterval(Timer * timer, int dt_ms)
215 {
216 timer->in_time = (unsigned int)dt_ms;
217 }
218
219 /*
220 * Idlers
221 */
222 static LIST_HEAD(idler_list);
223
224 typedef void (IdlerFunc) (void *data);
225
226 struct _idler {
227 dlist_t list;
228 IdlerFunc *func;
229 void *data;
230 };
231
232 Idler *
IdlerAdd(IdlerFunc * func,void * data)233 IdlerAdd(IdlerFunc * func, void *data)
234 {
235 Idler *id;
236
237 id = EMALLOC(Idler, 1);
238 if (!id)
239 return NULL;
240
241 id->func = func;
242 id->data = data;
243
244 LIST_APPEND(Idler, &idler_list, id);
245
246 return id;
247 }
248
249 void
IdlerDel(Idler * id)250 IdlerDel(Idler * id)
251 {
252 LIST_REMOVE(Idler, &idler_list, id);
253 Efree(id);
254 }
255
256 static void
_IdlerRun(void * _id,void * prm __UNUSED__)257 _IdlerRun(void *_id, void *prm __UNUSED__)
258 {
259 Idler *id = (Idler *) _id;
260
261 if (EDebug(EDBUG_TYPE_IDLERS) > 1)
262 Eprintf("%s: func=%p\n", __func__, id->func);
263 id->func(id->data);
264 }
265
266 void
IdlersRun(void)267 IdlersRun(void)
268 {
269 Idler *id;
270
271 if (EDebug(EDBUG_TYPE_IDLERS))
272 Eprintf("%s B\n", __func__);
273 LIST_FOR_EACH(Idler, &idler_list, id) _IdlerRun(id, NULL);
274 if (EDebug(EDBUG_TYPE_IDLERS))
275 Eprintf("%s E\n", __func__);
276 }
277