xref: /minix/minix/kernel/clock.c (revision e1cdaee1)
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(
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 {
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.
238  */
239   tmrs_settimer(&clock_timers, tp, exp_time, watchdog, NULL);
240   next_timeout = clock_timers->tmr_exp_time;
241 }
242 
243 /*===========================================================================*
244  *				reset_kernel_timer			     *
245  *===========================================================================*/
246 void reset_kernel_timer(
247   minix_timer_t *tp			/* pointer to timer structure */
248 )
249 {
250 /* The timer pointed to by 'tp' is no longer needed. Remove it from both the
251  * active and expired lists. Always update the next timeout time by setting
252  * it to the front of the active list.
253  */
254   tmrs_clrtimer(&clock_timers, tp, NULL);
255   next_timeout = (clock_timers == NULL) ?
256 	TMR_NEVER : clock_timers->tmr_exp_time;
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