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