00001 /* 00002 * Copyright (C) 2001-2004 Jakub Jermar 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 00009 * - Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * - Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * - The name of the author may not be used to endorse or promote products 00015 * derived from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00019 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00020 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00042 #include <time/clock.h> 00043 #include <time/timeout.h> 00044 #include <arch/types.h> 00045 #include <config.h> 00046 #include <synch/spinlock.h> 00047 #include <synch/waitq.h> 00048 #include <func.h> 00049 #include <proc/scheduler.h> 00050 #include <cpu.h> 00051 #include <arch.h> 00052 #include <adt/list.h> 00053 #include <atomic.h> 00054 #include <proc/thread.h> 00055 #include <sysinfo/sysinfo.h> 00056 #include <arch/barrier.h> 00057 00058 /* Pointers to public variables with time */ 00059 struct ptime { 00060 __native seconds1; 00061 __native useconds; 00062 __native seconds2; 00063 }; 00064 struct ptime *public_time; 00065 /* Variable holding fragment of second, so that we would update 00066 * seconds correctly 00067 */ 00068 static __native secfrag = 0; 00069 00078 void clock_counter_init(void) 00079 { 00080 void *faddr; 00081 00082 faddr = (void *)PFN2ADDR(frame_alloc(0, FRAME_ATOMIC)); 00083 if (!faddr) 00084 panic("Cannot allocate page for clock"); 00085 00086 public_time = (struct ptime *)PA2KA(faddr); 00087 00088 /* TODO: We would need some arch dependent settings here */ 00089 public_time->seconds1 = 0; 00090 public_time->seconds2 = 0; 00091 public_time->useconds = 0; 00092 00093 sysinfo_set_item_val("clock.faddr", NULL, (__native)faddr); 00094 } 00095 00096 00102 static void clock_update_counters(void) 00103 { 00104 if (CPU->id == 0) { 00105 secfrag += 1000000/HZ; 00106 if (secfrag >= 1000000) { 00107 secfrag -= 1000000; 00108 public_time->seconds1++; 00109 write_barrier(); 00110 public_time->useconds = secfrag; 00111 write_barrier(); 00112 public_time->seconds2 = public_time->seconds1; 00113 } else 00114 public_time->useconds += 1000000/HZ; 00115 } 00116 } 00117 00125 void clock(void) 00126 { 00127 link_t *l; 00128 timeout_t *h; 00129 timeout_handler_t f; 00130 void *arg; 00131 count_t missed_clock_ticks = CPU->missed_clock_ticks; 00132 int i; 00133 00134 /* 00135 * To avoid lock ordering problems, 00136 * run all expired timeouts as you visit them. 00137 */ 00138 for (i = 0; i <= missed_clock_ticks; i++) { 00139 clock_update_counters(); 00140 spinlock_lock(&CPU->timeoutlock); 00141 while ((l = CPU->timeout_active_head.next) != &CPU->timeout_active_head) { 00142 h = list_get_instance(l, timeout_t, link); 00143 spinlock_lock(&h->lock); 00144 if (h->ticks-- != 0) { 00145 spinlock_unlock(&h->lock); 00146 break; 00147 } 00148 list_remove(l); 00149 f = h->handler; 00150 arg = h->arg; 00151 timeout_reinitialize(h); 00152 spinlock_unlock(&h->lock); 00153 spinlock_unlock(&CPU->timeoutlock); 00154 00155 f(arg); 00156 00157 spinlock_lock(&CPU->timeoutlock); 00158 } 00159 spinlock_unlock(&CPU->timeoutlock); 00160 } 00161 CPU->missed_clock_ticks = 0; 00162 00163 /* 00164 * Do CPU usage accounting and find out whether to preempt THREAD. 00165 */ 00166 00167 if (THREAD) { 00168 __u64 ticks; 00169 00170 spinlock_lock(&CPU->lock); 00171 CPU->needs_relink += 1 + missed_clock_ticks; 00172 spinlock_unlock(&CPU->lock); 00173 00174 spinlock_lock(&THREAD->lock); 00175 if ((ticks = THREAD->ticks)) { 00176 if (ticks >= 1 + missed_clock_ticks) 00177 THREAD->ticks -= 1 + missed_clock_ticks; 00178 else 00179 THREAD->ticks = 0; 00180 } 00181 spinlock_unlock(&THREAD->lock); 00182 00183 if (!ticks && !PREEMPTION_DISABLED) { 00184 scheduler(); 00185 } 00186 } 00187 00188 } 00189