Annotation of prex-old/sys/kern/timer.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005-2007, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * timer.c - kernel timer services.
32: */
33:
34: #include <kernel.h>
35: #include <task.h>
36: #include <event.h>
37: #include <timer.h>
38: #include <irq.h>
39: #include <sched.h>
40: #include <thread.h>
41: #include <kmem.h>
42: #include <exception.h>
43:
44: static volatile u_long lbolt; /* ticks elapsed since bootup */
45: static struct event timer_event; /* event to wakeup timer thread */
46: static struct event delay_event; /* event for the delay thread */
47: static struct list timer_list; /* list of active timers */
48: static struct list expire_list; /* list of expired timers */
49: static void (*tick_hook)(int); /* hook routine for timer tick */
50:
51: /*
52: * Macro to get a timer element for the next timer expiration.
53: */
54: #define timer_next() \
55: (list_entry(list_first(&timer_list), struct timer, link))
56:
57: /*
58: * Helper routine to get remaining ticks for the expiration time.
59: * Return 0 if time already passed.
60: */
61: static u_long
62: time_remain(u_long expire)
63: {
64:
65: if (time_before(lbolt, expire))
66: return expire - lbolt;
67: return 0;
68: }
69:
70: /*
71: * Add a timer element to the timer list, in the proper place.
72: * Requires interrupts to be disabled by the caller.
73: */
74: static void
75: timer_add(struct timer *tmr, u_long ticks)
76: {
77: list_t head, n;
78: struct timer *t;
79:
80: tmr->expire = lbolt + ticks;
81:
82: /*
83: * We sort the timer list by time. So, we can quickly
84: * get the next expiration time from the head element
85: * of the timer list.
86: */
87: head = &timer_list;
88: for (n = list_first(head); n != head; n = list_next(n)) {
89: t = list_entry(n, struct timer, link);
90: if (time_before(tmr->expire, t->expire))
91: break;
92: }
93: list_insert(list_prev(n), &tmr->link);
94: }
95:
96: /*
97: * Execute a function after a specified length of time.
98: * A device driver can call timer_callout() or timer_stop()
99: * from ISR at interrupt level.
100: */
101: void
102: timer_callout(struct timer *tmr, void (*func)(void *),
103: void *arg, u_long msec)
104: {
105: u_long ticks;
106:
107: ASSERT(tmr);
108:
109: ticks = msec_to_tick(msec);
110: if (ticks == 0)
111: ticks = 1;
112:
113: irq_lock();
114:
115: /*
116: * Stop timer if running
117: */
118: if (tmr->active)
119: list_remove(&tmr->link);
120: /*
121: * Program timer
122: */
123: tmr->func = func;
124: tmr->arg = arg;
125: tmr->active = 1;
126: tmr->interval = 0;
127: timer_add(tmr, ticks);
128:
129: irq_unlock();
130: }
131:
132: void
133: timer_stop(struct timer *tmr)
134: {
135: ASSERT(tmr);
136:
137: irq_lock();
138: if (tmr->active) {
139: list_remove(&tmr->link);
140: tmr->active = 0;
141: }
142: irq_unlock();
143: }
144:
145: /*
146: * timer_delay - delay thread execution.
147: * The caller thread is blocked for the specified time.
148: * Returns 0 on success, or the remaining time (msec) on failure.
149: * This service is not available at interrupt level.
150: */
151: u_long
152: timer_delay(u_long msec)
153: {
154: struct timer *tmr;
155: u_long remain = 0;
156: int rc;
157:
158: ASSERT(irq_level == 0);
159:
160: rc = sched_tsleep(&delay_event, msec);
161: if (rc != SLP_TIMEOUT) {
162: tmr = &cur_thread->timeout;
163: remain = tick_to_msec(time_remain(tmr->expire));
164: }
165: return remain;
166: }
167:
168: /*
169: * timer_sleep - sleep system call.
170: * @delay: delay time in milli-second
171: * @remain: remaining time returned if the sleep is interrupted.
172: *
173: * Stop execution of current thread for the indicated amount of time.
174: * Returns EINTR if sleep is canceled by some reasons.
175: */
176: int
177: timer_sleep(u_long delay, u_long *remain)
178: {
179: u_long msec;
180: int err = 0;
181:
182: msec = timer_delay(delay);
183:
184: if (remain != NULL)
185: err = umem_copyout(&msec, remain, sizeof(u_long));
186: if (err == 0 && msec > 0)
187: err = EINTR;
188: return err;
189: }
190:
191: /*
192: * Alarm timer expired:
193: * Send an alarm exception to the target task.
194: */
195: static void
196: alarm_expire(void *task)
197: {
198:
199: exception_post((task_t)task, SIGALRM);
200: }
201:
202: /*
203: * timer_alarm - schedule an alarm exception.
204: * @delay: delay time in milli-second. If delay is 0, stop timer.
205: * @remain: remaining time of the previous alarm request.
206: *
207: * SIGALRM is sent to the caller task when specified delay time
208: * is passed.
209: */
210: int
211: timer_alarm(u_long delay, u_long *remain)
212: {
213: struct timer *tmr;
214: u_long msec = 0;
215: int err = 0;
216:
217: irq_lock();
218: tmr = &cur_task()->alarm;
219: if (tmr->active) {
220: /*
221: * Save the remaining time before we update
222: * the timer value.
223: */
224: msec = tick_to_msec(time_remain(tmr->expire));
225: }
226: if (delay == 0) {
227: timer_stop(tmr);
228: } else {
229: timer_callout(tmr, alarm_expire, cur_task(), delay);
230: }
231: irq_unlock();
232:
233: if (remain != NULL)
234: err = umem_copyout(&msec, remain, sizeof(u_long));
235: return err;
236: }
237:
238: /*
239: * timer_periodic - set periodic timer for the specified thread.
240: * @th: thread to set timer.
241: * @start: first time to wakeup. set 0 to stop timer.
242: * @period: time interval to wakeup. This must be non-zero.
243: * (The unit of start/period is milli-seconds.)
244: *
245: * The periodic thread will wait the timer period by calling
246: * timer_waitperiod().
247: */
248: int
249: timer_periodic(thread_t th, u_long start, u_long period)
250: {
251: struct timer *tmr;
252: int err = 0;
253:
254: ASSERT(irq_level == 0);
255:
256: if (start != 0 && period == 0)
257: return EINVAL;
258:
259: sched_lock();
260: if (!thread_valid(th)) {
261: sched_unlock();
262: return ESRCH;
263: }
264: if (th->task != cur_task()) {
265: sched_unlock();
266: return EPERM;
267: }
268: tmr = th->periodic;
269: if (start == 0) {
270: if (tmr != NULL && tmr->active)
271: timer_stop(tmr);
272: else
273: err = EINVAL;
274: } else {
275: if (tmr == NULL) {
276: /*
277: * Allocate a timer element at first call. We
278: * don't put this data in the thread structure
279: * because only a few threads will use the
280: * periodic timer function.
281: */
282: tmr = kmem_alloc(sizeof(struct timer));
283: if (tmr == NULL) {
284: sched_unlock();
285: return ENOMEM;
286: }
287: event_init(&tmr->event, "periodic");
288: tmr->active = 1;
289: th->periodic = tmr;
290: }
291: /*
292: * Program an interval timer.
293: */
294: irq_lock();
295: tmr->interval = msec_to_tick(period);
296: if (tmr->interval == 0)
297: tmr->interval = 1;
298: timer_add(tmr, msec_to_tick(start));
299: irq_unlock();
300: }
301: sched_unlock();
302: return err;
303: }
304:
305:
306: /*
307: * timer_waitperiod - wait next period of the periodic timer.
308: *
309: * Since this routine can exit by any exceptions, the control may
310: * return at non-period time. So, the caller must retry immediately
311: * if the error status is EINTR. This will be automatically done
312: * by the library stub routine.
313: */
314: int
315: timer_waitperiod(void)
316: {
317: struct timer *tmr;
318: int rc, err = 0;
319:
320: ASSERT(irq_level == 0);
321:
322: if ((tmr = cur_thread->periodic) == NULL)
323: return EINVAL;
324:
325: if (time_before(lbolt, tmr->expire)) {
326: /*
327: * Sleep until timer_tick() routine wakes us up.
328: */
329: rc = sched_sleep(&tmr->event);
330: if (rc != SLP_SUCCESS)
331: err = EINTR;
332: }
333: return err;
334: }
335:
336: /*
337: * Clean up our resource for the thread termination.
338: */
339: void
340: timer_cleanup(thread_t th)
341: {
342: if (th->periodic != NULL) {
343: timer_stop(th->periodic);
344: kmem_free(th->periodic);
345: }
346: }
347:
348: int
349: timer_hook(void (*func)(int))
350: {
351:
352: if (tick_hook != NULL)
353: return -1;
354: irq_lock();
355: tick_hook = func;
356: irq_unlock();
357: return 0;
358: }
359:
360: /*
361: * Timer thread.
362: *
363: * Handle all expired timers. Each callout routine is called
364: * with scheduler locked and interrupts enabled.
365: */
366: static void
367: timer_thread(u_long unused)
368: {
369: struct timer *tmr;
370:
371: for (;;) {
372:
373: /* Wait until next timer expiration. */
374: sched_sleep(&timer_event);
375:
376: while (!list_empty(&expire_list)) {
377: /*
378: * Callout
379: */
380: tmr = list_entry(list_first(&expire_list),
381: struct timer, link);
382: list_remove(&tmr->link);
383: tmr->active = 0;
384: sched_lock();
385: interrupt_enable();
386: (*tmr->func)(tmr->arg);
387:
388: /*
389: * Unlock scheduler here in order to give
390: * chance to higher priority threads to run.
391: */
392: sched_unlock();
393: interrupt_disable();
394: }
395: }
396: /* NOTREACHED */
397: }
398:
399: /*
400: * Timer tick handler
401: *
402: * timer_tick() is called straight from the real time clock interrupt.
403: * All interrupts are still disabled at the entry of this routine.
404: */
405: void
406: timer_tick(void)
407: {
408: struct timer *tmr;
409: u_long ticks;
410: int idle, wakeup = 0;
411:
412: /* Bump time in ticks. */
413: lbolt++;
414:
415: /*
416: * Handle all of the timer elements that have expired.
417: */
418: while (!list_empty(&timer_list) &&
419: time_after_eq(lbolt, timer_next()->expire)) {
420: /*
421: * Remove an expired timer from the list and wakup
422: * the appropriate thread. If it is periodic timer,
423: * reprogram the next expiration time. Otherwize,
424: * it is moved to the expired list.
425: */
426: tmr = timer_next();
427: list_remove(&tmr->link);
428: if (tmr->interval != 0) {
429: /*
430: * Periodic timer
431: */
432: ticks = time_remain(tmr->expire + tmr->interval);
433: if (ticks == 0)
434: ticks = 1;
435: timer_add(tmr, ticks);
436: sched_wakeup(&tmr->event);
437: } else {
438: /*
439: * One-shot timer
440: */
441: list_insert(&expire_list, &tmr->link);
442: wakeup = 1;
443: }
444: }
445: if (wakeup)
446: sched_wakeup(&timer_event);
447:
448: sched_tick();
449:
450: /*
451: * Call a hook routine for power management or profiling work.
452: */
453: if (tick_hook != NULL) {
454: idle = (cur_thread->prio == PRIO_IDLE) ? 1 : 0;
455: tick_hook(idle);
456: }
457: }
458:
459: u_long
460: timer_count(void)
461: {
462:
463: return lbolt;
464: }
465:
466: void
467: timer_info(struct info_timer *info)
468: {
469:
470: info->hz = HZ;
471: }
472:
473: #if defined(DEBUG) && defined(CONFIG_KDUMP)
474: void
475: timer_dump(void)
476: {
477: struct timer *tmr;
478: list_t head, n;
479:
480: printk("Timer dump:\n");
481: printk("lbolt=%d\n", lbolt);
482:
483: head = &timer_list;
484: for (n = list_first(head); n != head; n = list_next(n)) {
485: tmr = list_entry(n, struct timer, link);
486: printk("timer=%x func=%x arg=%x expire=%d\n", (int)tmr,
487: (int)tmr->func, (int)tmr->arg, (int)tmr->expire);
488: }
489: }
490: #endif
491:
492: /*
493: * Initialize the timer facility, called at system startup time.
494: */
495: void
496: timer_init(void)
497: {
498:
499: list_init(&timer_list);
500: list_init(&expire_list);
501: event_init(&timer_event, "timer");
502: event_init(&delay_event, "delay");
503:
504: /*
505: * Start timer thread
506: */
507: if (kernel_thread(PRIO_TIMER, timer_thread, 0) == NULL)
508: panic("timer_init");
509: }
CVSweb