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