1 /* This file contains the clock task, which handles time related functions.
2 * Important events that are handled by the CLOCK include setting and
3 * monitoring alarm timers and deciding when to (re)schedule processes.
4 * The CLOCK offers a direct interface to kernel processes. System services
5 * can access its services through system calls, such as sys_setalarm(). The
6 * CLOCK task thus is hidden from the outside world.
9 * Aug 18, 2006 removed direct hardware access etc, MinixPPC (Ingmar Alting)
10 * Oct 08, 2005 reordering and comment editing (A. S. Woodhull)
11 * Mar 18, 2004 clock interface moved to SYSTEM task (Jorrit N. Herder)
12 * Sep 30, 2004 source code documentation updated (Jorrit N. Herder)
13 * Sep 24, 2004 redesigned alarm timers (Jorrit N. Herder)
15 * Clock task is notified by the clock's interrupt handler when a timer
18 * In addition to the main clock_task() entry point, which starts the main
19 * loop, there are several other minor entry points:
20 * clock_stop: called just before MINIX shutdown
21 * get_uptime: get realtime since boot in clock ticks
22 * set_timer: set a watchdog timer (+)
23 * reset_timer: reset a watchdog timer (+)
24 * read_clock: read the counter of channel 0 of the 8253A timer
26 * (+) The CLOCK task keeps tracks of watchdog timers for the entire kernel.
27 * It is crucial that watchdog functions not block, or the CLOCK task may
28 * be blocked. Do not send() a message when the receiver is not expecting it.
29 * Instead, notify(), which always returns, should be used.
34 #include <minix/endpoint.h>
38 #ifdef CONFIG_WATCHDOG
42 /* Function prototype for PRIVATE functions.
44 FORWARD
_PROTOTYPE( void load_update
, (void));
46 /* The CLOCK's timers queue. The functions in <timers.h> operate on this.
47 * Each system process possesses a single synchronous alarm timer. If other
48 * kernel parts want to use additional timers, they must declare their own
49 * persistent (static) timer structure, which can be passed to the clock
50 * via (re)set_timer().
51 * When a timer expires its watchdog function is run by the CLOCK task.
53 PRIVATE timer_t
*clock_timers
; /* queue of CLOCK timers */
54 PRIVATE
clock_t next_timeout
; /* realtime that next timer expires */
56 /* The time is incremented by the interrupt handler on each clock tick.
58 PRIVATE
clock_t realtime
= 0; /* real time clock */
60 /*===========================================================================*
62 *===========================================================================*/
63 PUBLIC
void clock_init()
66 /* Set a watchdog timer to periodically balance the scheduling queues.
67 Side-effect sets new timer */
73 * The boot processor timer interrupt handler. In addition to non-boot cpus it
74 * keeps real time and notifies the clock task if need be
76 PUBLIC
int bsp_timer_int_handler(void)
83 /* Get number of ticks and update realtime. */
84 ticks
= lost_ticks
+ 1;
88 ap_timer_int_handler();
90 /* if a timer expired, notify the clock task */
91 if ((next_timeout
<= realtime
)) {
92 tmrs_exptimers(&clock_timers
, realtime
, NULL
);
93 next_timeout
= (clock_timers
== NULL
) ?
94 TMR_NEVER
: clock_timers
->tmr_exp_time
;
100 return(1); /* reenable interrupts */
103 /*===========================================================================*
105 *===========================================================================*/
106 PUBLIC
clock_t get_uptime(void)
108 /* Get and return the current clock uptime in ticks. */
112 /*===========================================================================*
114 *===========================================================================*/
115 PUBLIC
void set_timer(tp
, exp_time
, watchdog
)
116 struct timer
*tp
; /* pointer to timer structure */
117 clock_t exp_time
; /* expiration realtime */
118 tmr_func_t watchdog
; /* watchdog to be called */
120 /* Insert the new timer in the active timers list. Always update the
121 * next timeout time by setting it to the front of the active list.
123 tmrs_settimer(&clock_timers
, tp
, exp_time
, watchdog
, NULL
);
124 next_timeout
= clock_timers
->tmr_exp_time
;
127 /*===========================================================================*
129 *===========================================================================*/
130 PUBLIC
void reset_timer(tp
)
131 struct timer
*tp
; /* pointer to timer structure */
133 /* The timer pointed to by 'tp' is no longer needed. Remove it from both the
134 * active and expired lists. Always update the next timeout time by setting
135 * it to the front of the active list.
137 tmrs_clrtimer(&clock_timers
, tp
, NULL
);
138 next_timeout
= (clock_timers
== NULL
) ?
139 TMR_NEVER
: clock_timers
->tmr_exp_time
;
142 /*===========================================================================*
144 *===========================================================================*/
145 PRIVATE
void load_update(void)
151 /* Load average data is stored as a list of numbers in a circular
152 * buffer. Each slot accumulates _LOAD_UNIT_SECS of samples of
153 * the number of runnable processes. Computations can then
154 * be made of the load average over variable periods, in the
155 * user library (see getloadavg(3)).
157 slot
= (realtime
/ system_hz
/ _LOAD_UNIT_SECS
) % _LOAD_HISTORY
;
158 if(slot
!= kloadinfo
.proc_last_slot
) {
159 kloadinfo
.proc_load_history
[slot
] = 0;
160 kloadinfo
.proc_last_slot
= slot
;
163 /* Cumulation. How many processes are ready now? */
164 for(q
= 0; q
< NR_SCHED_QUEUES
; q
++)
165 for(p
= rdy_head
[q
]; p
!= NIL_PROC
; p
= p
->p_nextready
)
168 kloadinfo
.proc_load_history
[slot
] += enqueued
;
170 /* Up-to-dateness. */
171 kloadinfo
.last_clock
= realtime
;
175 * Timer interupt handler. This is the only thing executed on non boot
176 * processors. It is called by bsp_timer_int_handler() on the boot processor
178 PUBLIC
int ap_timer_int_handler(void)
181 /* Update user and system accounting times. Charge the current process
182 * for user time. If the current process is not billable, that is, if a
183 * non-user process is running, charge the billable process for system
184 * time as well. Thus the unbillable process' user time is the billable
185 * user's system time.
189 struct proc
* p
, * billp
;
191 #ifdef CONFIG_WATCHDOG
193 * we need to know whether local timer ticks are happening or whether
194 * the kernel is locked up. We don't care about overflows as we only
195 * need to know that it's still ticking or not
197 watchdog_local_timer_ticks
++;
200 /* Update user and system accounting times. Charge the current process
201 * for user time. If the current process is not billable, that is, if a
202 * non-user process is running, charge the billable process for system
203 * time as well. Thus the unbillable process' user time is the billable
204 * user's system time.
207 /* FIXME prepared for get_cpu_local_var() */
211 p
->p_user_time
+= ticks
;
212 if (priv(p
)->s_flags
& PREEMPTIBLE
) {
213 p
->p_ticks_left
-= ticks
;
215 if (! (priv(p
)->s_flags
& BILLABLE
)) {
216 billp
->p_sys_time
+= ticks
;
217 billp
->p_ticks_left
-= ticks
;
220 /* Decrement virtual timers, if applicable. We decrement both the
221 * virtual and the profile timer of the current process, and if the
222 * current process is not billable, the timer of the billed process as
223 * well. If any of the timers expire, do_clocktick() will send out
226 if ((p
->p_misc_flags
& MF_VIRT_TIMER
)){
227 p
->p_virt_left
-= ticks
;
229 if ((p
->p_misc_flags
& MF_PROF_TIMER
)){
230 p
->p_prof_left
-= ticks
;
232 if (! (priv(p
)->s_flags
& BILLABLE
) &&
233 (billp
->p_misc_flags
& MF_PROF_TIMER
)){
234 billp
->p_prof_left
-= ticks
;
238 * Check if a process-virtual timer expired. Check current process, but
239 * also bill_ptr - one process's user time is another's system time, and
240 * the profile timer decreases for both!
247 /* Update load average. */
250 /* check if the process is still runnable after checking the vtimer */
251 if (p
->p_rts_flags
== 0 && p
->p_ticks_left
<= 0 &&
252 priv(p
)->s_flags
& PREEMPTIBLE
) {
253 /* this dequeues the process */
254 RTS_SET(p
, RTS_NO_QUANTUM
);
260 PUBLIC
int boot_cpu_init_timer(unsigned freq
)
262 if (arch_init_local_timer(freq
))
265 if (arch_register_local_timer_handler(
266 (irq_handler_t
) bsp_timer_int_handler
))