github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/time.goc (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Time-related runtime and pieces of package time. 6 7 package time 8 9 #include "runtime.h" 10 #include "defs_GOOS_GOARCH.h" 11 #include "os_GOOS.h" 12 #include "arch_GOARCH.h" 13 #include "malloc.h" 14 #include "race.h" 15 16 static Timers timers; 17 static void addtimer(Timer*); 18 19 // Package time APIs. 20 // Godoc uses the comments in package time, not these. 21 22 // time.now is implemented in assembly. 23 24 // Sleep puts the current goroutine to sleep for at least ns nanoseconds. 25 func Sleep(ns int64) { 26 runtime·tsleep(ns, "sleep"); 27 } 28 29 // startTimer adds t to the timer heap. 30 func startTimer(t *Timer) { 31 if(raceenabled) 32 runtime·racerelease(t); 33 runtime·addtimer(t); 34 } 35 36 // stopTimer removes t from the timer heap if it is there. 37 // It returns true if t was removed, false if t wasn't even there. 38 func stopTimer(t *Timer) (stopped bool) { 39 stopped = runtime·deltimer(t); 40 } 41 42 // C runtime. 43 44 static void timerproc(void); 45 static void siftup(int32); 46 static void siftdown(int32); 47 48 // Ready the goroutine e.data. 49 static void 50 ready(int64 now, Eface e) 51 { 52 USED(now); 53 54 runtime·ready(e.data); 55 } 56 57 static FuncVal readyv = {(void(*)(void))ready}; 58 59 // Put the current goroutine to sleep for ns nanoseconds. 60 void 61 runtime·tsleep(int64 ns, int8 *reason) 62 { 63 Timer t; 64 65 if(ns <= 0) 66 return; 67 68 t.when = runtime·nanotime() + ns; 69 t.period = 0; 70 t.fv = &readyv; 71 t.arg.data = g; 72 runtime·lock(&timers); 73 addtimer(&t); 74 runtime·park(runtime·unlock, &timers, reason); 75 } 76 77 static FuncVal timerprocv = {timerproc}; 78 79 void 80 runtime·addtimer(Timer *t) 81 { 82 runtime·lock(&timers); 83 addtimer(t); 84 runtime·unlock(&timers); 85 } 86 87 // Add a timer to the heap and start or kick the timer proc 88 // if the new timer is earlier than any of the others. 89 static void 90 addtimer(Timer *t) 91 { 92 int32 n; 93 Timer **nt; 94 95 if(timers.len >= timers.cap) { 96 // Grow slice. 97 n = 16; 98 if(n <= timers.cap) 99 n = timers.cap*3 / 2; 100 nt = runtime·malloc(n*sizeof nt[0]); 101 runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]); 102 runtime·free(timers.t); 103 timers.t = nt; 104 timers.cap = n; 105 } 106 t->i = timers.len++; 107 timers.t[t->i] = t; 108 siftup(t->i); 109 if(t->i == 0) { 110 // siftup moved to top: new earliest deadline. 111 if(timers.sleeping) { 112 timers.sleeping = false; 113 runtime·notewakeup(&timers.waitnote); 114 } 115 if(timers.rescheduling) { 116 timers.rescheduling = false; 117 runtime·ready(timers.timerproc); 118 } 119 } 120 if(timers.timerproc == nil) { 121 timers.timerproc = runtime·newproc1(&timerprocv, nil, 0, 0, addtimer); 122 timers.timerproc->issystem = true; 123 } 124 } 125 126 // Delete timer t from the heap. 127 // Do not need to update the timerproc: 128 // if it wakes up early, no big deal. 129 bool 130 runtime·deltimer(Timer *t) 131 { 132 int32 i; 133 134 runtime·lock(&timers); 135 136 // t may not be registered anymore and may have 137 // a bogus i (typically 0, if generated by Go). 138 // Verify it before proceeding. 139 i = t->i; 140 if(i < 0 || i >= timers.len || timers.t[i] != t) { 141 runtime·unlock(&timers); 142 return false; 143 } 144 145 timers.len--; 146 if(i == timers.len) { 147 timers.t[i] = nil; 148 } else { 149 timers.t[i] = timers.t[timers.len]; 150 timers.t[timers.len] = nil; 151 timers.t[i]->i = i; 152 siftup(i); 153 siftdown(i); 154 } 155 runtime·unlock(&timers); 156 return true; 157 } 158 159 // Timerproc runs the time-driven events. 160 // It sleeps until the next event in the timers heap. 161 // If addtimer inserts a new earlier event, addtimer 162 // wakes timerproc early. 163 static void 164 timerproc(void) 165 { 166 int64 delta, now; 167 Timer *t; 168 void (*f)(int64, Eface); 169 Eface arg; 170 171 for(;;) { 172 runtime·lock(&timers); 173 now = runtime·nanotime(); 174 for(;;) { 175 if(timers.len == 0) { 176 delta = -1; 177 break; 178 } 179 t = timers.t[0]; 180 delta = t->when - now; 181 if(delta > 0) 182 break; 183 if(t->period > 0) { 184 // leave in heap but adjust next time to fire 185 t->when += t->period * (1 + -delta/t->period); 186 siftdown(0); 187 } else { 188 // remove from heap 189 timers.t[0] = timers.t[--timers.len]; 190 timers.t[0]->i = 0; 191 siftdown(0); 192 t->i = -1; // mark as removed 193 } 194 f = (void*)t->fv->fn; 195 arg = t->arg; 196 runtime·unlock(&timers); 197 if(raceenabled) 198 runtime·raceacquire(t); 199 f(now, arg); 200 runtime·lock(&timers); 201 } 202 if(delta < 0) { 203 // No timers left - put goroutine to sleep. 204 timers.rescheduling = true; 205 runtime·park(runtime·unlock, &timers, "timer goroutine (idle)"); 206 continue; 207 } 208 // At least one timer pending. Sleep until then. 209 timers.sleeping = true; 210 runtime·noteclear(&timers.waitnote); 211 runtime·unlock(&timers); 212 runtime·entersyscallblock(); 213 runtime·notetsleep(&timers.waitnote, delta); 214 runtime·exitsyscall(); 215 } 216 } 217 218 // heap maintenance algorithms. 219 220 static void 221 siftup(int32 i) 222 { 223 int32 p; 224 Timer **t, *tmp; 225 226 t = timers.t; 227 while(i > 0) { 228 p = (i-1)/2; // parent 229 if(t[i]->when >= t[p]->when) 230 break; 231 tmp = t[i]; 232 t[i] = t[p]; 233 t[p] = tmp; 234 t[i]->i = i; 235 t[p]->i = p; 236 i = p; 237 } 238 } 239 240 static void 241 siftdown(int32 i) 242 { 243 int32 c, len; 244 Timer **t, *tmp; 245 246 t = timers.t; 247 len = timers.len; 248 for(;;) { 249 c = i*2 + 1; // left child 250 if(c >= len) { 251 break; 252 } 253 if(c+1 < len && t[c+1]->when < t[c]->when) 254 c++; 255 if(t[c]->when >= t[i]->when) 256 break; 257 tmp = t[i]; 258 t[i] = t[c]; 259 t[c] = tmp; 260 t[i]->i = i; 261 t[c]->i = c; 262 i = c; 263 } 264 }