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