xref: /minix/minix/kernel/clock.c (revision 9f81acbc)
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 <minix/endpoint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 
20 #include "clock.h"
21 
22 #ifdef USE_WATCHDOG
23 #include "watchdog.h"
24 #endif
25 
26 /* Function prototype for PRIVATE functions.
27  */
28 static void load_update(void);
29 
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.
36  */
37 static minix_timer_t *clock_timers;	/* queue of CLOCK timers */
38 
39 /* Number of ticks to adjust realtime by. A negative value implies slowing
40  * down realtime, a positive value implies speeding it up.
41  */
42 static int32_t adjtime_delta = 0;
43 
44 /*
45  * Initialize the clock variables.
46  */
47 void
48 init_clock(void)
49 {
50 	char *value;
51 
52 	/* Initialize clock information structure. */
53 	memset(&kclockinfo, 0, sizeof(kclockinfo));
54 
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;
61 
62 	/* Load average data initialization. */
63 	memset(&kloadinfo, 0, sizeof(kloadinfo));
64 }
65 
66 /*
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.
69  */
70 int timer_int_handler(void)
71 {
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.
77 	 */
78 
79 	struct proc * p, * billp;
80 
81 	/* FIXME watchdog for slave cpus! */
82 #ifdef USE_WATCHDOG
83 	/*
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
87 	 */
88 	watchdog_local_timer_ticks++;
89 #endif
90 
91 	if (cpu_is_bsp(cpuid)) {
92 		kclockinfo.uptime++;
93 
94 		/* if adjtime_delta has ticks remaining, apply one to realtime.
95 		 * limit changes to every other interrupt.
96 		 */
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++;
103 		}
104 	}
105 
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.
111 	 */
112 
113 	p = get_cpulocal_var(proc_ptr);
114 	billp = get_cpulocal_var(bill_ptr);
115 
116 	p->p_user_time++;
117 
118 	if (! (priv(p)->s_flags & BILLABLE)) {
119 		billp->p_sys_time++;
120 	}
121 
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.
127 	 */
128 	if ((p->p_misc_flags & MF_VIRT_TIMER) && (p->p_virt_left > 0)) {
129 		p->p_virt_left--;
130 	}
131 	if ((p->p_misc_flags & MF_PROF_TIMER) && (p->p_prof_left > 0)) {
132 		p->p_prof_left--;
133 	}
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--;
138 	}
139 
140 	/*
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!
144 	 */
145 	vtimer_check(p);
146 
147 	if (p != billp)
148 		vtimer_check(billp);
149 
150 	/* Update load average. */
151 	load_update();
152 
153 	if (cpu_is_bsp(cpuid)) {
154 		/*
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.
158 		 */
159 		if (clock_timers != NULL &&
160 		    tmr_has_expired(clock_timers, kclockinfo.uptime))
161 			tmrs_exptimers(&clock_timers, kclockinfo.uptime, NULL);
162 
163 #ifdef DEBUG_SERIAL
164 		if (kinfo.do_serial_debug)
165 			do_ser_debug();
166 #endif
167 
168 	}
169 
170 	arch_timer_int_handler();
171 
172 	return(1);					/* reenable interrupts */
173 }
174 
175 /*===========================================================================*
176  *				get_realtime				     *
177  *===========================================================================*/
178 clock_t get_realtime(void)
179 {
180   /* Get and return the current wall time in ticks since boot. */
181   return(kclockinfo.realtime);
182 }
183 
184 /*===========================================================================*
185  *				set_realtime				     *
186  *===========================================================================*/
187 void set_realtime(clock_t newrealtime)
188 {
189   kclockinfo.realtime = newrealtime;
190 }
191 
192 /*===========================================================================*
193  *				set_adjtime_delta			     *
194  *===========================================================================*/
195 void set_adjtime_delta(int32_t ticks)
196 {
197   adjtime_delta = ticks;
198 }
199 
200 /*===========================================================================*
201  *				get_monotonic				     *
202  *===========================================================================*/
203 clock_t get_monotonic(void)
204 {
205   /* Get and return the number of ticks since boot. */
206   return(kclockinfo.uptime);
207 }
208 
209 /*===========================================================================*
210  *				set_boottime				     *
211  *===========================================================================*/
212 void set_boottime(time_t newboottime)
213 {
214   kclockinfo.boottime = newboottime;
215 }
216 
217 /*===========================================================================*
218  *				get_boottime				     *
219  *===========================================================================*/
220 time_t get_boottime(void)
221 {
222   /* Get and return the number of seconds since the UNIX epoch. */
223   return(kclockinfo.boottime);
224 }
225 
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 */
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   (void)tmrs_settimer(&clock_timers, tp, exp_time, watchdog, arg, NULL, NULL);
240 }
241 
242 /*===========================================================================*
243  *				reset_kernel_timer			     *
244  *===========================================================================*/
245 void reset_kernel_timer(
246   minix_timer_t *tp			/* pointer to timer structure */
247 )
248 {
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.
252  */
253   if (tmr_is_set(tp))
254 	(void)tmrs_clrtimer(&clock_timers, tp, NULL, NULL);
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