Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / kernel / clock.c
blob3260e60a1a300774837b8c14b912b1c1cd723e39
1 /* This file contains the architecture-independent clock functionality, which
2 * handles time related functions. Important events that are handled here
3 * include setting and monitoring alarm timers and deciding when to
4 * (re)schedule processes. System services can access its services through
5 * system calls, such as sys_setalarm().
7 * Changes:
8 * Aug 18, 2006 removed direct hardware access etc, MinixPPC (Ingmar Alting)
9 * Oct 08, 2005 reordering and comment editing (A. S. Woodhull)
10 * Mar 18, 2004 clock interface moved to SYSTEM task (Jorrit N. Herder)
11 * Sep 30, 2004 source code documentation updated (Jorrit N. Herder)
12 * Sep 24, 2004 redesigned alarm timers (Jorrit N. Herder)
15 #include <minix/endpoint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
20 #include "clock.h"
22 #ifdef USE_WATCHDOG
23 #include "watchdog.h"
24 #endif
26 /* Function prototype for PRIVATE functions.
28 static void load_update(void);
30 /* The CLOCK's timers queue. The functions in <minix/timers.h> operate on this.
31 * Each system process possesses a single synchronous alarm timer. If other
32 * kernel parts want to use additional timers, they must declare their own
33 * persistent (static) timer structure, which can be passed to the clock
34 * via (re)set_kernel_timer().
35 * When a timer expires its watchdog function is run by the CLOCK task.
37 static minix_timer_t *clock_timers; /* queue of CLOCK timers */
39 /* Number of ticks to adjust realtime by. A negative value implies slowing
40 * down realtime, a positive value implies speeding it up.
42 static int32_t adjtime_delta = 0;
45 * Initialize the clock variables.
47 void
48 init_clock(void)
50 char *value;
52 /* Initialize clock information structure. */
53 memset(&kclockinfo, 0, sizeof(kclockinfo));
55 /* Get clock tick frequency. */
56 value = env_get("hz");
57 if (value != NULL)
58 kclockinfo.hz = atoi(value);
59 if (value == NULL || kclockinfo.hz < 2 || kclockinfo.hz > 50000)
60 kclockinfo.hz = DEFAULT_HZ;
62 /* Load average data initialization. */
63 memset(&kloadinfo, 0, sizeof(kloadinfo));
67 * The boot processor's timer interrupt handler. In addition to non-boot cpus
68 * it keeps real time and notifies the clock task if need be.
70 int timer_int_handler(void)
72 /* Update user and system accounting times. Charge the current process
73 * for user time. If the current process is not billable, that is, if a
74 * non-user process is running, charge the billable process for system
75 * time as well. Thus the unbillable process' user time is the billable
76 * user's system time.
79 struct proc * p, * billp;
81 /* FIXME watchdog for slave cpus! */
82 #ifdef USE_WATCHDOG
84 * we need to know whether local timer ticks are happening or whether
85 * the kernel is locked up. We don't care about overflows as we only
86 * need to know that it's still ticking or not
88 watchdog_local_timer_ticks++;
89 #endif
91 if (cpu_is_bsp(cpuid)) {
92 kclockinfo.uptime++;
94 /* if adjtime_delta has ticks remaining, apply one to realtime.
95 * limit changes to every other interrupt.
97 if (adjtime_delta != 0 && kclockinfo.uptime & 0x1) {
98 /* go forward or stay behind */
99 kclockinfo.realtime += (adjtime_delta > 0) ? 2 : 0;
100 adjtime_delta += (adjtime_delta > 0) ? -1 : +1;
101 } else {
102 kclockinfo.realtime++;
106 /* Update user and system accounting times. Charge the current process
107 * for user time. If the current process is not billable, that is, if a
108 * non-user process is running, charge the billable process for system
109 * time as well. Thus the unbillable process' user time is the billable
110 * user's system time.
113 p = get_cpulocal_var(proc_ptr);
114 billp = get_cpulocal_var(bill_ptr);
116 p->p_user_time++;
118 if (! (priv(p)->s_flags & BILLABLE)) {
119 billp->p_sys_time++;
122 /* Decrement virtual timers, if applicable. We decrement both the
123 * virtual and the profile timer of the current process, and if the
124 * current process is not billable, the timer of the billed process as
125 * well. If any of the timers expire, do_clocktick() will send out
126 * signals.
128 if ((p->p_misc_flags & MF_VIRT_TIMER) && (p->p_virt_left > 0)) {
129 p->p_virt_left--;
131 if ((p->p_misc_flags & MF_PROF_TIMER) && (p->p_prof_left > 0)) {
132 p->p_prof_left--;
134 if (! (priv(p)->s_flags & BILLABLE) &&
135 (billp->p_misc_flags & MF_PROF_TIMER) &&
136 (billp->p_prof_left > 0)) {
137 billp->p_prof_left--;
141 * Check if a process-virtual timer expired. Check current process, but
142 * also bill_ptr - one process's user time is another's system time, and
143 * the profile timer decreases for both!
145 vtimer_check(p);
147 if (p != billp)
148 vtimer_check(billp);
150 /* Update load average. */
151 load_update();
153 if (cpu_is_bsp(cpuid)) {
155 * If a timer expired, notify the clock task. Keep in mind
156 * that clock tick values may overflow, so we must only look at
157 * relative differences, and only if there are timers at all.
159 if (clock_timers != NULL &&
160 tmr_has_expired(clock_timers, kclockinfo.uptime))
161 tmrs_exptimers(&clock_timers, kclockinfo.uptime, NULL);
163 #ifdef DEBUG_SERIAL
164 if (kinfo.do_serial_debug)
165 do_ser_debug();
166 #endif
170 arch_timer_int_handler();
172 return(1); /* reenable interrupts */
175 /*===========================================================================*
176 * get_realtime *
177 *===========================================================================*/
178 clock_t get_realtime(void)
180 /* Get and return the current wall time in ticks since boot. */
181 return(kclockinfo.realtime);
184 /*===========================================================================*
185 * set_realtime *
186 *===========================================================================*/
187 void set_realtime(clock_t newrealtime)
189 kclockinfo.realtime = newrealtime;
192 /*===========================================================================*
193 * set_adjtime_delta *
194 *===========================================================================*/
195 void set_adjtime_delta(int32_t ticks)
197 adjtime_delta = ticks;
200 /*===========================================================================*
201 * get_monotonic *
202 *===========================================================================*/
203 clock_t get_monotonic(void)
205 /* Get and return the number of ticks since boot. */
206 return(kclockinfo.uptime);
209 /*===========================================================================*
210 * set_boottime *
211 *===========================================================================*/
212 void set_boottime(time_t newboottime)
214 kclockinfo.boottime = newboottime;
217 /*===========================================================================*
218 * get_boottime *
219 *===========================================================================*/
220 time_t get_boottime(void)
222 /* Get and return the number of seconds since the UNIX epoch. */
223 return(kclockinfo.boottime);
226 /*===========================================================================*
227 * set_kernel_timer *
228 *===========================================================================*/
229 void set_kernel_timer(
230 minix_timer_t *tp, /* pointer to timer structure */
231 clock_t exp_time, /* expiration monotonic time */
232 tmr_func_t watchdog, /* watchdog to be called */
233 int arg /* argument for watchdog function */
236 /* Insert the new timer in the active timers list. Always update the
237 * next timeout time by setting it to the front of the active list.
239 (void)tmrs_settimer(&clock_timers, tp, exp_time, watchdog, arg, NULL, NULL);
242 /*===========================================================================*
243 * reset_kernel_timer *
244 *===========================================================================*/
245 void reset_kernel_timer(
246 minix_timer_t *tp /* pointer to timer structure */
249 /* The timer pointed to by 'tp' is no longer needed. Remove it from both the
250 * active and expired lists. Always update the next timeout time by setting
251 * it to the front of the active list.
253 if (tmr_is_set(tp))
254 (void)tmrs_clrtimer(&clock_timers, tp, NULL, NULL);
257 /*===========================================================================*
258 * load_update *
259 *===========================================================================*/
260 static void load_update(void)
262 u16_t slot;
263 int enqueued = 0, q;
264 struct proc *p;
265 struct proc **rdy_head;
267 /* Load average data is stored as a list of numbers in a circular
268 * buffer. Each slot accumulates _LOAD_UNIT_SECS of samples of
269 * the number of runnable processes. Computations can then
270 * be made of the load average over variable periods, in the
271 * user library (see getloadavg(3)).
273 slot = (kclockinfo.uptime / system_hz / _LOAD_UNIT_SECS) %
274 _LOAD_HISTORY;
275 if(slot != kloadinfo.proc_last_slot) {
276 kloadinfo.proc_load_history[slot] = 0;
277 kloadinfo.proc_last_slot = slot;
280 rdy_head = get_cpulocal_var(run_q_head);
281 /* Cumulation. How many processes are ready now? */
282 for(q = 0; q < NR_SCHED_QUEUES; q++) {
283 for(p = rdy_head[q]; p != NULL; p = p->p_nextready) {
284 enqueued++;
288 kloadinfo.proc_load_history[slot] += enqueued;
290 /* Up-to-dateness. */
291 kloadinfo.last_clock = kclockinfo.uptime;
294 int boot_cpu_init_timer(unsigned freq)
296 if (init_local_timer(freq))
297 return -1;
299 if (register_local_timer_handler(
300 (irq_handler_t) timer_int_handler))
301 return -1;
303 return 0;
306 int app_cpu_init_timer(unsigned freq)
308 if (init_local_timer(freq))
309 return -1;
311 return 0;