xref: /minix3/minix/lib/libddekit/src/timer.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 #include "common.h"
2 
3 #include <ddekit/memory.h>
4 #include <ddekit/semaphore.h>
5 #include <ddekit/thread.h>
6 #include <ddekit/timer.h>
7 
8 #ifdef DDEBUG_LEVEL_TIMER
9 #undef DDEBUG
10 #define DDEBUG DDEBUG_LEVEL_TIMER
11 #endif
12 
13 #include "debug.h"
14 #include "thread.h"
15 
16 #define DDEBUG_MSG_TIMER(t) \
17 	DDEBUG_MSG_VERBOSE("id: %d, exp: %d, fn: %d, now %d", \
18 	                    (t)->id, (t)->exp, (t)->fn, jiffies)
19 
20 typedef clock_t myclock_t;
21 
22 struct ddekit_timer_s {
23 	void (*fn)(void *);
24 	void *args;
25 	int id;
26 	myclock_t exp;
27 	struct ddekit_timer_s * next;
28 };
29 
30 
31 static ddekit_sem_t *pending_timer_ints;
32 
33 /* are we currently expecting a alarm notify? */
34 int _ddekit_timer_pending = 0;
35 
36 unsigned long long jiffies;
37 unsigned long HZ;
38 
39 static struct ddekit_timer_s list =  {0,0,-1,1,0};
40 static int _id = 0 ;
41 static ddekit_thread_t *th;
42 static  ddekit_lock_t lock;
43 
44 static void lock_timer(void);
45 static void unlock_timer(void);
46 static clock_t get_current_clock(void);
47 static void remove_timer(int id);
48 static int insert_timer(struct ddekit_timer_s *t);
49 static struct ddekit_timer_s * get_next( myclock_t exp );
50 static void ddekit_timer_thread(void *data);
51 
52  /****************************************************************************
53  *    Private funtions                                                       *
54  ****************************************************************************/
55 
56 /*****************************************************************************
57  *    lock_timer                                                             *
58  ****************************************************************************/
59 static void lock_timer()
60 {
61 	ddekit_lock_lock(&lock);
62 }
63 
64 /*****************************************************************************
65  *    unlock_timer                                                           *
66  ****************************************************************************/
67 static void unlock_timer()
68 {
69 	ddekit_lock_unlock(&lock);
70 }
71 
72 /*****************************************************************************
73  *    get_current_clock                                                      *
74  ****************************************************************************/
75 static myclock_t get_current_clock()
76 {
77 	/* returns the current clock tick */
78 	myclock_t ret;
79 	getticks(&ret);
80 	return ret;
81 }
82 
83 /*****************************************************************************
84  *    remove_timer                                                           *
85  ****************************************************************************/
86 static void remove_timer(int id)
87 {
88 	/* removes a timer from the timer list */
89 	struct ddekit_timer_s *l,*m;
90 
91 	lock_timer();
92 
93 	for (l = &list; l &&  l->next && l->next->id!=id; l = l->next )
94 		;
95 
96 	if (l && l->next) {
97 		m = l->next;
98 
99 		DDEBUG_MSG_VERBOSE(
100 		    "deleting  timer at for tick: %d fn: %p, (now: %d)\n",
101 			m->exp, m->fn, jiffies);
102 
103 		l->next = m->next;
104 		DDEBUG_MSG_TIMER(m);
105 
106 		ddekit_simple_free(m);
107 	}
108 
109 	unlock_timer();
110 }
111 
112 /*****************************************************************************
113  *    insert_timer                                                           *
114  ****************************************************************************/
115 static int insert_timer(struct ddekit_timer_s *t)
116 {
117 	/* inserts a timer to the timer list */
118 	int ret;
119 
120 	lock_timer();
121 
122 	struct ddekit_timer_s *l;
123 
124 	for (l = &list; l->next && l->next->exp <= t->exp; l = l->next) {
125 
126 	}
127 
128 	t->next = l->next;
129 	l->next = t;
130 
131 	t->id   = ret = _id;
132 
133 	_id++;
134 
135 	if (_id==0) {
136 		DDEBUG_MSG_WARN("Timer ID overflow...");
137 	}
138 
139 	DDEBUG_MSG_TIMER(t);
140 
141 	unlock_timer();
142 
143 	return ret;
144 }
145 
146 /*****************************************************************************
147  *    get_next                                                               *
148  ****************************************************************************/
149 static struct ddekit_timer_s * get_next( myclock_t exp )
150 {
151 	/*
152 	 * this one get the next timer, which's timeout expired,
153 	 * returns NULL if no timer is pending
154 	 */
155 	struct ddekit_timer_s * ret = 0;
156 	lock_timer();
157 	if (list.next)
158 	{
159 		if (list.next->exp <= exp)
160 		{
161 			ret  = list.next;
162 			list.next = ret->next;
163 		}
164 	}
165 	unlock_timer();
166 	return ret;
167 }
168 
169 /*****************************************************************************
170  *    ddekit_timer_thread                                                    *
171  ****************************************************************************/
172 static void ddekit_timer_thread(void * data)
173 {
174 	struct ddekit_timer_s * l;
175 
176 	/* rock around the clock! */
177 	for ( ; ; )
178 	{
179 		/* wait for timer interrupts */
180 		ddekit_sem_down(pending_timer_ints);
181 		DDEBUG_MSG_VERBOSE("handling timer interrupt");
182 
183 		/* execute all expired timers */
184 		while( (l = get_next(jiffies)) != 0 ) {
185 			DDEBUG_MSG_TIMER(l);
186 			if (l->fn) {
187 				l->fn(l->args);
188 			}
189 			ddekit_simple_free(l);
190 		}
191 	}
192 }
193 
194 
195  /****************************************************************************
196  *    Public functions (ddekit/timer.h)                                      *
197  ****************************************************************************/
198 
199 /*****************************************************************************
200  *    ddekit_add_timer                                                       *
201  ****************************************************************************/
202 int ddekit_add_timer
203 (void (*fn)(void *), void *args, unsigned long timeout)
204 {
205 	struct ddekit_timer_s *t;
206 
207 	t = (struct ddekit_timer_s *)
208 	    ddekit_simple_malloc(sizeof(struct ddekit_timer_s ));
209 
210 	t->fn   = fn;
211 	t->args = args;
212 	t->exp = (myclock_t) timeout;
213 
214 	return insert_timer(t);
215 }
216 
217 /*****************************************************************************
218  *    ddekit_del_timer                                                       *
219  ****************************************************************************/
220 int ddekit_del_timer(int timer)
221 {
222 	remove_timer(timer);
223 	return 0;
224 }
225 
226 /*****************************************************************************
227  *    ddekit_timer_pending                                                   *
228  ****************************************************************************/
229 int ddekit_timer_pending(int timer)
230 {
231 	int ret=0;
232 	struct ddekit_timer_s *t;
233 	lock_timer();
234 	for (t=list.next; t; t = t->next) {
235 		if (t->id==timer) {
236 			ret = 1;
237 		}
238 
239 	}
240 	unlock_timer();
241 	return ret;
242 }
243 
244 /*****************************************************************************
245  *    ddekit_init_timers                                                     *
246  ****************************************************************************/
247 void ddekit_init_timers(void)
248 {
249 	static int first_time=0;
250 
251 	if (!first_time)
252 	{
253 		ddekit_lock_init(&lock);
254 		jiffies = get_current_clock();
255 		HZ = sys_hz();
256 		pending_timer_ints = ddekit_sem_init(0);
257 		th = ddekit_thread_create(ddekit_timer_thread, 0, "timer");
258 		first_time=1;
259 		DDEBUG_MSG_INFO("DDEkit timer subsustem initialized");
260 	}
261 }
262 
263 /*****************************************************************************
264  *    ddekit_get_timer_thread                                                *
265  ****************************************************************************/
266 ddekit_thread_t *ddekit_get_timer_thread(void)
267 {
268 	return th;
269 }
270 
271 /****************************************************************************
272  *    ddekit_internal (src/timer.h)                                         *
273  ****************************************************************************/
274 
275 /*****************************************************************************
276  *   _ddekit_timer_interrupt                                                 *
277  ****************************************************************************/
278 void _ddekit_timer_interrupt(void)
279 {
280 	jiffies = get_current_clock();
281 	DDEBUG_MSG_VERBOSE("now: %d", jiffies);
282 	ddekit_sem_up(pending_timer_ints);
283 }
284 
285 /*****************************************************************************
286  *    _ddekit_timer_update                                                   *
287  ****************************************************************************/
288 void _ddekit_timer_update()
289 {
290 	lock_timer();
291 
292 	static myclock_t next_timout;
293 	if(list.next)
294 	{
295 		if(!_ddekit_timer_pending || list.next->exp < next_timout) {
296 
297 			unsigned to = list.next->exp - jiffies;
298 
299 			_ddekit_timer_pending = 1;
300 
301 			if (list.next->exp <= jiffies) {
302 				DDEBUG_MSG_WARN("Timeout lies in past to %d, now: %d",
303 					list.next->exp, jiffies);
304 				to = 1;
305 			}
306 
307 			sys_setalarm(to, 0 /* REL */);
308 
309 			DDEBUG_MSG_VERBOSE("requesting alarm for clock tick %d , now %d",
310 				list.next->exp, jiffies);
311 		}
312 		next_timout = list.next->exp;
313 	}
314 	unlock_timer();
315 }
316