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