xref: /minix3/minix/lib/libddekit/src/timer.c (revision d91f738bd8d93aa6befa2a8d07581040607a512a)
1433d6423SLionel Sambuc #include "common.h"
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include <ddekit/memory.h>
4433d6423SLionel Sambuc #include <ddekit/semaphore.h>
5433d6423SLionel Sambuc #include <ddekit/thread.h>
6433d6423SLionel Sambuc #include <ddekit/timer.h>
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #ifdef DDEBUG_LEVEL_TIMER
9433d6423SLionel Sambuc #undef DDEBUG
10433d6423SLionel Sambuc #define DDEBUG DDEBUG_LEVEL_TIMER
11433d6423SLionel Sambuc #endif
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "debug.h"
14433d6423SLionel Sambuc #include "thread.h"
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #define DDEBUG_MSG_TIMER(t) \
17433d6423SLionel Sambuc 	DDEBUG_MSG_VERBOSE("id: %d, exp: %d, fn: %d, now %d", \
18433d6423SLionel Sambuc 	                    (t)->id, (t)->exp, (t)->fn, jiffies)
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc typedef clock_t myclock_t;
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc struct ddekit_timer_s {
23433d6423SLionel Sambuc 	void (*fn)(void *);
24433d6423SLionel Sambuc 	void *args;
25433d6423SLionel Sambuc 	int id;
26433d6423SLionel Sambuc 	myclock_t exp;
27433d6423SLionel Sambuc 	struct ddekit_timer_s * next;
28433d6423SLionel Sambuc };
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc static ddekit_sem_t *pending_timer_ints;
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc /* are we currently expecting a alarm notify? */
34433d6423SLionel Sambuc int _ddekit_timer_pending = 0;
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc unsigned long long jiffies;
37433d6423SLionel Sambuc unsigned long HZ;
38433d6423SLionel Sambuc 
39433d6423SLionel Sambuc static struct ddekit_timer_s list =  {0,0,-1,1,0};
40433d6423SLionel Sambuc static int _id = 0 ;
41433d6423SLionel Sambuc static ddekit_thread_t *th;
42433d6423SLionel Sambuc static  ddekit_lock_t lock;
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc static void lock_timer(void);
45433d6423SLionel Sambuc static void unlock_timer(void);
46433d6423SLionel Sambuc static void remove_timer(int id);
47433d6423SLionel Sambuc static int insert_timer(struct ddekit_timer_s *t);
48433d6423SLionel Sambuc static struct ddekit_timer_s * get_next( myclock_t exp );
49433d6423SLionel Sambuc static void ddekit_timer_thread(void *data);
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc  /****************************************************************************
52433d6423SLionel Sambuc  *    Private funtions                                                       *
53433d6423SLionel Sambuc  ****************************************************************************/
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc /*****************************************************************************
56433d6423SLionel Sambuc  *    lock_timer                                                             *
57433d6423SLionel Sambuc  ****************************************************************************/
lock_timer()58433d6423SLionel Sambuc static void lock_timer()
59433d6423SLionel Sambuc {
60433d6423SLionel Sambuc 	ddekit_lock_lock(&lock);
61433d6423SLionel Sambuc }
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc /*****************************************************************************
64433d6423SLionel Sambuc  *    unlock_timer                                                           *
65433d6423SLionel Sambuc  ****************************************************************************/
unlock_timer()66433d6423SLionel Sambuc static void unlock_timer()
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc 	ddekit_lock_unlock(&lock);
69433d6423SLionel Sambuc }
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc /*****************************************************************************
72433d6423SLionel Sambuc  *    remove_timer                                                           *
73433d6423SLionel Sambuc  ****************************************************************************/
remove_timer(int id)74433d6423SLionel Sambuc static void remove_timer(int id)
75433d6423SLionel Sambuc {
76433d6423SLionel Sambuc 	/* removes a timer from the timer list */
77433d6423SLionel Sambuc 	struct ddekit_timer_s *l,*m;
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc 	lock_timer();
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc 	for (l = &list; l &&  l->next && l->next->id!=id; l = l->next )
82433d6423SLionel Sambuc 		;
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc 	if (l && l->next) {
85433d6423SLionel Sambuc 		m = l->next;
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc 		DDEBUG_MSG_VERBOSE(
88433d6423SLionel Sambuc 		    "deleting  timer at for tick: %d fn: %p, (now: %d)\n",
89433d6423SLionel Sambuc 			m->exp, m->fn, jiffies);
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc 		l->next = m->next;
92433d6423SLionel Sambuc 		DDEBUG_MSG_TIMER(m);
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc 		ddekit_simple_free(m);
95433d6423SLionel Sambuc 	}
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	unlock_timer();
98433d6423SLionel Sambuc }
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc /*****************************************************************************
101433d6423SLionel Sambuc  *    insert_timer                                                           *
102433d6423SLionel Sambuc  ****************************************************************************/
insert_timer(struct ddekit_timer_s * t)103433d6423SLionel Sambuc static int insert_timer(struct ddekit_timer_s *t)
104433d6423SLionel Sambuc {
105433d6423SLionel Sambuc 	/* inserts a timer to the timer list */
106433d6423SLionel Sambuc 	int ret;
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 	lock_timer();
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc 	struct ddekit_timer_s *l;
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc 	for (l = &list; l->next && l->next->exp <= t->exp; l = l->next) {
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc 	}
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc 	t->next = l->next;
117433d6423SLionel Sambuc 	l->next = t;
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc 	t->id   = ret = _id;
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc 	_id++;
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 	if (_id==0) {
124433d6423SLionel Sambuc 		DDEBUG_MSG_WARN("Timer ID overflow...");
125433d6423SLionel Sambuc 	}
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 	DDEBUG_MSG_TIMER(t);
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 	unlock_timer();
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 	return ret;
132433d6423SLionel Sambuc }
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc /*****************************************************************************
135433d6423SLionel Sambuc  *    get_next                                                               *
136433d6423SLionel Sambuc  ****************************************************************************/
get_next(myclock_t exp)137433d6423SLionel Sambuc static struct ddekit_timer_s * get_next( myclock_t exp )
138433d6423SLionel Sambuc {
139433d6423SLionel Sambuc 	/*
140433d6423SLionel Sambuc 	 * this one get the next timer, which's timeout expired,
141433d6423SLionel Sambuc 	 * returns NULL if no timer is pending
142433d6423SLionel Sambuc 	 */
143433d6423SLionel Sambuc 	struct ddekit_timer_s * ret = 0;
144433d6423SLionel Sambuc 	lock_timer();
145433d6423SLionel Sambuc 	if (list.next)
146433d6423SLionel Sambuc 	{
147433d6423SLionel Sambuc 		if (list.next->exp <= exp)
148433d6423SLionel Sambuc 		{
149433d6423SLionel Sambuc 			ret  = list.next;
150433d6423SLionel Sambuc 			list.next = ret->next;
151433d6423SLionel Sambuc 		}
152433d6423SLionel Sambuc 	}
153433d6423SLionel Sambuc 	unlock_timer();
154433d6423SLionel Sambuc 	return ret;
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc /*****************************************************************************
158433d6423SLionel Sambuc  *    ddekit_timer_thread                                                    *
159433d6423SLionel Sambuc  ****************************************************************************/
ddekit_timer_thread(void * data)160433d6423SLionel Sambuc static void ddekit_timer_thread(void * data)
161433d6423SLionel Sambuc {
162433d6423SLionel Sambuc 	struct ddekit_timer_s * l;
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc 	/* rock around the clock! */
165433d6423SLionel Sambuc 	for ( ; ; )
166433d6423SLionel Sambuc 	{
167433d6423SLionel Sambuc 		/* wait for timer interrupts */
168433d6423SLionel Sambuc 		ddekit_sem_down(pending_timer_ints);
169433d6423SLionel Sambuc 		DDEBUG_MSG_VERBOSE("handling timer interrupt");
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc 		/* execute all expired timers */
172433d6423SLionel Sambuc 		while( (l = get_next(jiffies)) != 0 ) {
173433d6423SLionel Sambuc 			DDEBUG_MSG_TIMER(l);
174433d6423SLionel Sambuc 			if (l->fn) {
175433d6423SLionel Sambuc 				l->fn(l->args);
176433d6423SLionel Sambuc 			}
177433d6423SLionel Sambuc 			ddekit_simple_free(l);
178433d6423SLionel Sambuc 		}
179433d6423SLionel Sambuc 	}
180433d6423SLionel Sambuc }
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc  /****************************************************************************
184433d6423SLionel Sambuc  *    Public functions (ddekit/timer.h)                                      *
185433d6423SLionel Sambuc  ****************************************************************************/
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc /*****************************************************************************
188433d6423SLionel Sambuc  *    ddekit_add_timer                                                       *
189433d6423SLionel Sambuc  ****************************************************************************/
ddekit_add_timer(void (* fn)(void *),void * args,unsigned long timeout)190433d6423SLionel Sambuc int ddekit_add_timer
191433d6423SLionel Sambuc (void (*fn)(void *), void *args, unsigned long timeout)
192433d6423SLionel Sambuc {
193433d6423SLionel Sambuc 	struct ddekit_timer_s *t;
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc 	t = (struct ddekit_timer_s *)
196433d6423SLionel Sambuc 	    ddekit_simple_malloc(sizeof(struct ddekit_timer_s ));
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc 	t->fn   = fn;
199433d6423SLionel Sambuc 	t->args = args;
200433d6423SLionel Sambuc 	t->exp = (myclock_t) timeout;
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc 	return insert_timer(t);
203433d6423SLionel Sambuc }
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc /*****************************************************************************
206433d6423SLionel Sambuc  *    ddekit_del_timer                                                       *
207433d6423SLionel Sambuc  ****************************************************************************/
ddekit_del_timer(int timer)208433d6423SLionel Sambuc int ddekit_del_timer(int timer)
209433d6423SLionel Sambuc {
210433d6423SLionel Sambuc 	remove_timer(timer);
211433d6423SLionel Sambuc 	return 0;
212433d6423SLionel Sambuc }
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc /*****************************************************************************
215433d6423SLionel Sambuc  *    ddekit_timer_pending                                                   *
216433d6423SLionel Sambuc  ****************************************************************************/
ddekit_timer_pending(int timer)217433d6423SLionel Sambuc int ddekit_timer_pending(int timer)
218433d6423SLionel Sambuc {
219433d6423SLionel Sambuc 	int ret=0;
220433d6423SLionel Sambuc 	struct ddekit_timer_s *t;
221433d6423SLionel Sambuc 	lock_timer();
222433d6423SLionel Sambuc 	for (t=list.next; t; t = t->next) {
223433d6423SLionel Sambuc 		if (t->id==timer) {
224433d6423SLionel Sambuc 			ret = 1;
225433d6423SLionel Sambuc 		}
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 	}
228433d6423SLionel Sambuc 	unlock_timer();
229433d6423SLionel Sambuc 	return ret;
230433d6423SLionel Sambuc }
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc /*****************************************************************************
233433d6423SLionel Sambuc  *    ddekit_init_timers                                                     *
234433d6423SLionel Sambuc  ****************************************************************************/
ddekit_init_timers(void)235433d6423SLionel Sambuc void ddekit_init_timers(void)
236433d6423SLionel Sambuc {
237433d6423SLionel Sambuc 	static int first_time=0;
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc 	if (!first_time)
240433d6423SLionel Sambuc 	{
241433d6423SLionel Sambuc 		ddekit_lock_init(&lock);
242*d91f738bSDavid van Moolenbroek 		jiffies = getticks();
243433d6423SLionel Sambuc 		HZ = sys_hz();
244433d6423SLionel Sambuc 		pending_timer_ints = ddekit_sem_init(0);
245433d6423SLionel Sambuc 		th = ddekit_thread_create(ddekit_timer_thread, 0, "timer");
246433d6423SLionel Sambuc 		first_time=1;
247433d6423SLionel Sambuc 		DDEBUG_MSG_INFO("DDEkit timer subsustem initialized");
248433d6423SLionel Sambuc 	}
249433d6423SLionel Sambuc }
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc /*****************************************************************************
252433d6423SLionel Sambuc  *    ddekit_get_timer_thread                                                *
253433d6423SLionel Sambuc  ****************************************************************************/
ddekit_get_timer_thread(void)254433d6423SLionel Sambuc ddekit_thread_t *ddekit_get_timer_thread(void)
255433d6423SLionel Sambuc {
256433d6423SLionel Sambuc 	return th;
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc /****************************************************************************
260433d6423SLionel Sambuc  *    ddekit_internal (src/timer.h)                                         *
261433d6423SLionel Sambuc  ****************************************************************************/
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc /*****************************************************************************
264433d6423SLionel Sambuc  *   _ddekit_timer_interrupt                                                 *
265433d6423SLionel Sambuc  ****************************************************************************/
_ddekit_timer_interrupt(void)266433d6423SLionel Sambuc void _ddekit_timer_interrupt(void)
267433d6423SLionel Sambuc {
268*d91f738bSDavid van Moolenbroek 	jiffies = getticks();
269433d6423SLionel Sambuc 	DDEBUG_MSG_VERBOSE("now: %d", jiffies);
270433d6423SLionel Sambuc 	ddekit_sem_up(pending_timer_ints);
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc /*****************************************************************************
274433d6423SLionel Sambuc  *    _ddekit_timer_update                                                   *
275433d6423SLionel Sambuc  ****************************************************************************/
_ddekit_timer_update()276433d6423SLionel Sambuc void _ddekit_timer_update()
277433d6423SLionel Sambuc {
278433d6423SLionel Sambuc 	lock_timer();
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	static myclock_t next_timout;
281433d6423SLionel Sambuc 	if(list.next)
282433d6423SLionel Sambuc 	{
283433d6423SLionel Sambuc 		if(!_ddekit_timer_pending || list.next->exp < next_timout) {
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc 			unsigned to = list.next->exp - jiffies;
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 			_ddekit_timer_pending = 1;
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc 			if (list.next->exp <= jiffies) {
290433d6423SLionel Sambuc 				DDEBUG_MSG_WARN("Timeout lies in past to %d, now: %d",
291433d6423SLionel Sambuc 					list.next->exp, jiffies);
292433d6423SLionel Sambuc 				to = 1;
293433d6423SLionel Sambuc 			}
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 			sys_setalarm(to, 0 /* REL */);
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc 			DDEBUG_MSG_VERBOSE("requesting alarm for clock tick %d , now %d",
298433d6423SLionel Sambuc 				list.next->exp, jiffies);
299433d6423SLionel Sambuc 		}
300433d6423SLionel Sambuc 		next_timout = list.next->exp;
301433d6423SLionel Sambuc 	}
302433d6423SLionel Sambuc 	unlock_timer();
303433d6423SLionel Sambuc }
304