xref: /minix/minix/kernel/clock.c (revision 9f988b79)
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().
6  *
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)
13  */
14 
15 #include "kernel/kernel.h"
16 #include <minix/endpoint.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <assert.h>
20 
21 #include "clock.h"
22 
23 #ifdef USE_WATCHDOG
24 #include "watchdog.h"
25 #endif
26 
27 /* Function prototype for PRIVATE functions.
28  */
29 static void load_update(void);
30 
31 /* The CLOCK's timers queue. The functions in <minix/timers.h> operate on this.
32  * Each system process possesses a single synchronous alarm timer. If other
33  * kernel parts want to use additional timers, they must declare their own
34  * persistent (static) timer structure, which can be passed to the clock
35  * via (re)set_kernel_timer().
36  * When a timer expires its watchdog function is run by the CLOCK task.
37  */
38 static minix_timer_t *clock_timers;	/* queue of CLOCK timers */
39 static clock_t next_timeout;	/* monotonic time that next timer expires */
40 
41 /* Number of ticks to adjust realtime by. A negative value implies slowing
42  * down realtime, a positive value implies speeding it up.
43  */
44 static int32_t adjtime_delta = 0;
45 
46 /*
47  * Initialize the clock variables.
48  */
49 void
50 init_clock(void)
51 {
52 	char *value;
53 	int i;
54 
55 	/* Initialize clock information structure. */
56 	memset(&kclockinfo, 0, sizeof(kclockinfo));
57 
58 	/* Get clock tick frequency. */
59 	value = env_get("hz");
60 	if (value != NULL)
61 		kclockinfo.hz = atoi(value);
62 	if (value == NULL || kclockinfo.hz < 2 || kclockinfo.hz > 50000)
63 		kclockinfo.hz = DEFAULT_HZ;
64 
65 	/* Load average data initialization. */
66 	memset(&kloadinfo, 0, sizeof(kloadinfo));
67 }
68 
69 /*
70  * The boot processor's timer interrupt handler. In addition to non-boot cpus
71  * it keeps real time and notifies the clock task if need be.
72  */
73 int timer_int_handler(void)
74 {
75 	/* Update user and system accounting times. Charge the current process
76 	 * for user time. If the current process is not billable, that is, if a
77 	 * non-user process is running, charge the billable process for system
78 	 * time as well.  Thus the unbillable process' user time is the billable
79 	 * user's system time.
80 	 */
81 
82 	struct proc * p, * billp;
83 
84 	/* FIXME watchdog for slave cpus! */
85 #ifdef USE_WATCHDOG
86 	/*
87 	 * we need to know whether local timer ticks are happening or whether
88 	 * the kernel is locked up. We don't care about overflows as we only
89 	 * need to know that it's still ticking or not
90 	 */
91 	watchdog_local_timer_ticks++;
92 #endif
93 
94 	if (cpu_is_bsp(cpuid)) {
95 		kclockinfo.uptime++;
96 
97 		/* if adjtime_delta has ticks remaining, apply one to realtime.
98 		 * limit changes to every other interrupt.
99 		 */
100 		if (adjtime_delta != 0 && kclockinfo.uptime & 0x1) {
101 			/* go forward or stay behind */
102 			kclockinfo.realtime += (adjtime_delta > 0) ? 2 : 0;
103 			adjtime_delta += (adjtime_delta > 0) ? -1 : +1;
104 		} else {
105 			kclockinfo.realtime++;
106 		}
107 	}
108 
109 	/* Update user and system accounting times. Charge the current process
110 	 * for user time. If the current process is not billable, that is, if a
111 	 * non-user process is running, charge the billable process for system
112 	 * time as well.  Thus the unbillable process' user time is the billable
113 	 * user's system time.
114 	 */
115 
116 	p = get_cpulocal_var(proc_ptr);
117 	billp = get_cpulocal_var(bill_ptr);
118 
119 	p->p_user_time++;
120 
121 	if (! (priv(p)->s_flags & BILLABLE)) {
122 		billp->p_sys_time++;
123 	}
124 
125 	/* Decrement virtual timers, if applicable. We decrement both the
126 	 * virtual and the profile timer of the current process, and if the
127 	 * current process is not billable, the timer of the billed process as
128 	 * well.  If any of the timers expire, do_clocktick() will send out
129 	 * signals.
130 	 */
131 	if ((p->p_misc_flags & MF_VIRT_TIMER) && (p->p_virt_left > 0)) {
132 		p->p_virt_left--;
133 	}
134 	if ((p->p_misc_flags & MF_PROF_TIMER) && (p->p_prof_left > 0)) {
135 		p->p_prof_left--;
136 	}
137 	if (! (priv(p)->s_flags & BILLABLE) &&
138 			(billp->p_misc_flags & MF_PROF_TIMER) &&
139 			(billp->p_prof_left > 0)) {
140 		billp->p_prof_left--;
141 	}
142 
143 	/*
144 	 * Check if a process-virtual timer expired. Check current process, but
145 	 * also bill_ptr - one process's user time is another's system time, and
146 	 * the profile timer decreases for both!
147 	 */
148 	vtimer_check(p);
149 
150 	if (p != billp)
151 		vtimer_check(billp);
152 
153 	/* Update load average. */
154 	load_update();
155 
156 	if (cpu_is_bsp(cpuid)) {
157 		/* if a timer expired, notify the clock task */
158 		if ((next_timeout <= kclockinfo.uptime)) {
159 			tmrs_exptimers(&clock_timers, kclockinfo.uptime, NULL);
160 			next_timeout = (clock_timers == NULL) ?
161 				TMR_NEVER : clock_timers->tmr_exp_time;
162 		}
163 
164 #ifdef DEBUG_SERIAL
165 		if (kinfo.do_serial_debug)
166 			do_ser_debug();
167 #endif
168 
169 	}
170 
171 	arch_timer_int_handler();
172 
173 	return(1);					/* reenable interrupts */
174 }
175 
176 /*===========================================================================*
177  *				get_realtime				     *
178  *===========================================================================*/
179 clock_t get_realtime(void)
180 {
181   /* Get and return the current wall time in ticks since boot. */
182   return(kclockinfo.realtime);
183 }
184 
185 /*===========================================================================*
186  *				set_realtime				     *
187  *===========================================================================*/
188 void set_realtime(clock_t newrealtime)
189 {
190   kclockinfo.realtime = newrealtime;
191 }
192 
193 /*===========================================================================*
194  *				set_adjtime_delta			     *
195  *===========================================================================*/
196 void set_adjtime_delta(int32_t ticks)
197 {
198   adjtime_delta = ticks;
199 }
200 
201 /*===========================================================================*
202  *				get_monotonic				     *
203  *===========================================================================*/
204 clock_t get_monotonic(void)
205 {
206   /* Get and return the number of ticks since boot. */
207   return(kclockinfo.uptime);
208 }
209 
210 /*===========================================================================*
211  *				set_boottime				     *
212  *===========================================================================*/
213 void set_boottime(time_t newboottime)
214 {
215   kclockinfo.boottime = newboottime;
216 }
217 
218 /*===========================================================================*
219  *				get_boottime				     *
220  *===========================================================================*/
221 time_t get_boottime(void)
222 {
223   /* Get and return the number of seconds since the UNIX epoch. */
224   return(kclockinfo.boottime);
225 }
226 
227 /*===========================================================================*
228  *				set_kernel_timer			     *
229  *===========================================================================*/
230 void set_kernel_timer(tp, exp_time, watchdog)
231 minix_timer_t *tp;		/* pointer to timer structure */
232 clock_t exp_time;		/* expiration monotonic time */
233 tmr_func_t watchdog;		/* watchdog to be called */
234 {
235 /* Insert the new timer in the active timers list. Always update the
236  * next timeout time by setting it to the front of the active list.
237  */
238   tmrs_settimer(&clock_timers, tp, exp_time, watchdog, NULL);
239   next_timeout = clock_timers->tmr_exp_time;
240 }
241 
242 /*===========================================================================*
243  *				reset_kernel_timer			     *
244  *===========================================================================*/
245 void reset_kernel_timer(tp)
246 minix_timer_t *tp;		/* pointer to timer structure */
247 {
248 /* The timer pointed to by 'tp' is no longer needed. Remove it from both the
249  * active and expired lists. Always update the next timeout time by setting
250  * it to the front of the active list.
251  */
252   tmrs_clrtimer(&clock_timers, tp, NULL);
253   next_timeout = (clock_timers == NULL) ?
254 	TMR_NEVER : clock_timers->tmr_exp_time;
255 }
256 
257 /*===========================================================================*
258  *				load_update				     *
259  *===========================================================================*/
260 static void load_update(void)
261 {
262 	u16_t slot;
263 	int enqueued = 0, q;
264 	struct proc *p;
265 	struct proc **rdy_head;
266 
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)).
272 	 */
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;
278 	}
279 
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++;
285 		}
286 	}
287 
288 	kloadinfo.proc_load_history[slot] += enqueued;
289 
290 	/* Up-to-dateness. */
291 	kloadinfo.last_clock = kclockinfo.uptime;
292 }
293 
294 int boot_cpu_init_timer(unsigned freq)
295 {
296 	if (init_local_timer(freq))
297 		return -1;
298 
299 	if (register_local_timer_handler(
300 				(irq_handler_t) timer_int_handler))
301 		return -1;
302 
303 	return 0;
304 }
305 
306 int app_cpu_init_timer(unsigned freq)
307 {
308 	if (init_local_timer(freq))
309 		return -1;
310 
311 	return 0;
312 }
313