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