github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 enum { 17 debug = 0, 18 }; 19 20 static Timers timers; 21 static void addtimer(Timer*); 22 static void dumptimers(int8*); 23 24 // Package time APIs. 25 // Godoc uses the comments in package time, not these. 26 27 // time.now is implemented in assembly. 28 29 // Sleep puts the current goroutine to sleep for at least ns nanoseconds. 30 func Sleep(ns int64) { 31 runtime·tsleep(ns, "sleep"); 32 } 33 34 // startTimer adds t to the timer heap. 35 func startTimer(t *Timer) { 36 if(raceenabled) 37 runtime·racerelease(t); 38 runtime·addtimer(t); 39 } 40 41 // stopTimer removes t from the timer heap if it is there. 42 // It returns true if t was removed, false if t wasn't even there. 43 func stopTimer(t *Timer) (stopped bool) { 44 stopped = runtime·deltimer(t); 45 } 46 47 // C runtime. 48 49 static void timerproc(void); 50 static void siftup(int32); 51 static void siftdown(int32); 52 53 // Ready the goroutine e.data. 54 static void 55 ready(int64 now, Eface e) 56 { 57 USED(now); 58 59 runtime·ready(e.data); 60 } 61 62 static FuncVal readyv = {(void(*)(void))ready}; 63 64 // Put the current goroutine to sleep for ns nanoseconds. 65 void 66 runtime·tsleep(int64 ns, int8 *reason) 67 { 68 Timer t; 69 70 if(ns <= 0) 71 return; 72 73 t.when = runtime·nanotime() + ns; 74 t.period = 0; 75 t.fv = &readyv; 76 t.arg.data = g; 77 runtime·lock(&timers); 78 addtimer(&t); 79 runtime·park(runtime·unlock, &timers, reason); 80 } 81 82 static FuncVal timerprocv = {timerproc}; 83 84 void 85 runtime·addtimer(Timer *t) 86 { 87 runtime·lock(&timers); 88 addtimer(t); 89 runtime·unlock(&timers); 90 } 91 92 // Add a timer to the heap and start or kick the timer proc 93 // if the new timer is earlier than any of the others. 94 static void 95 addtimer(Timer *t) 96 { 97 int32 n; 98 Timer **nt; 99 100 // when must never be negative; otherwise timerproc will overflow 101 // during its delta calculation and never expire other timers. 102 if(t->when < 0) 103 t->when = (1LL<<63)-1; 104 105 if(timers.len >= timers.cap) { 106 // Grow slice. 107 n = 16; 108 if(n <= timers.cap) 109 n = timers.cap*3 / 2; 110 nt = runtime·malloc(n*sizeof nt[0]); 111 runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]); 112 runtime·free(timers.t); 113 timers.t = nt; 114 timers.cap = n; 115 } 116 t->i = timers.len++; 117 timers.t[t->i] = t; 118 siftup(t->i); 119 if(t->i == 0) { 120 // siftup moved to top: new earliest deadline. 121 if(timers.sleeping) { 122 timers.sleeping = false; 123 runtime·notewakeup(&timers.waitnote); 124 } 125 if(timers.rescheduling) { 126 timers.rescheduling = false; 127 runtime·ready(timers.timerproc); 128 } 129 } 130 if(timers.timerproc == nil) { 131 timers.timerproc = runtime·newproc1(&timerprocv, nil, 0, 0, addtimer); 132 timers.timerproc->issystem = true; 133 } 134 if(debug) 135 dumptimers("addtimer"); 136 } 137 138 // Delete timer t from the heap. 139 // Do not need to update the timerproc: 140 // if it wakes up early, no big deal. 141 bool 142 runtime·deltimer(Timer *t) 143 { 144 int32 i; 145 146 // Dereference t so that any panic happens before the lock is held. 147 // Discard result, because t might be moving in the heap. 148 i = t->i; 149 USED(i); 150 151 runtime·lock(&timers); 152 153 // t may not be registered anymore and may have 154 // a bogus i (typically 0, if generated by Go). 155 // Verify it before proceeding. 156 i = t->i; 157 if(i < 0 || i >= timers.len || timers.t[i] != t) { 158 runtime·unlock(&timers); 159 return false; 160 } 161 162 timers.len--; 163 if(i == timers.len) { 164 timers.t[i] = nil; 165 } else { 166 timers.t[i] = timers.t[timers.len]; 167 timers.t[timers.len] = nil; 168 timers.t[i]->i = i; 169 siftup(i); 170 siftdown(i); 171 } 172 if(debug) 173 dumptimers("deltimer"); 174 runtime·unlock(&timers); 175 return true; 176 } 177 178 // Timerproc runs the time-driven events. 179 // It sleeps until the next event in the timers heap. 180 // If addtimer inserts a new earlier event, addtimer 181 // wakes timerproc early. 182 static void 183 timerproc(void) 184 { 185 int64 delta, now; 186 Timer *t; 187 void (*f)(int64, Eface); 188 Eface arg; 189 190 for(;;) { 191 runtime·lock(&timers); 192 timers.sleeping = false; 193 now = runtime·nanotime(); 194 for(;;) { 195 if(timers.len == 0) { 196 delta = -1; 197 break; 198 } 199 t = timers.t[0]; 200 delta = t->when - now; 201 if(delta > 0) 202 break; 203 if(t->period > 0) { 204 // leave in heap but adjust next time to fire 205 t->when += t->period * (1 + -delta/t->period); 206 siftdown(0); 207 } else { 208 // remove from heap 209 timers.t[0] = timers.t[--timers.len]; 210 timers.t[0]->i = 0; 211 siftdown(0); 212 t->i = -1; // mark as removed 213 } 214 f = (void*)t->fv->fn; 215 arg = t->arg; 216 runtime·unlock(&timers); 217 if(raceenabled) 218 runtime·raceacquire(t); 219 f(now, arg); 220 runtime·lock(&timers); 221 } 222 if(delta < 0) { 223 // No timers left - put goroutine to sleep. 224 timers.rescheduling = true; 225 runtime·park(runtime·unlock, &timers, "timer goroutine (idle)"); 226 continue; 227 } 228 // At least one timer pending. Sleep until then. 229 timers.sleeping = true; 230 runtime·noteclear(&timers.waitnote); 231 runtime·unlock(&timers); 232 runtime·notetsleepg(&timers.waitnote, delta); 233 } 234 } 235 236 // heap maintenance algorithms. 237 238 static void 239 siftup(int32 i) 240 { 241 int32 p; 242 int64 when; 243 Timer **t, *tmp; 244 245 t = timers.t; 246 when = t[i]->when; 247 tmp = t[i]; 248 while(i > 0) { 249 p = (i-1)/4; // parent 250 if(when >= t[p]->when) 251 break; 252 t[i] = t[p]; 253 t[i]->i = i; 254 t[p] = tmp; 255 tmp->i = p; 256 i = p; 257 } 258 } 259 260 static void 261 siftdown(int32 i) 262 { 263 int32 c, c3, len; 264 int64 when, w, w3; 265 Timer **t, *tmp; 266 267 t = timers.t; 268 len = timers.len; 269 when = t[i]->when; 270 tmp = t[i]; 271 for(;;) { 272 c = i*4 + 1; // left child 273 c3 = c + 2; // mid child 274 if(c >= len) { 275 break; 276 } 277 w = t[c]->when; 278 if(c+1 < len && t[c+1]->when < w) { 279 w = t[c+1]->when; 280 c++; 281 } 282 if(c3 < len) { 283 w3 = t[c3]->when; 284 if(c3+1 < len && t[c3+1]->when < w3) { 285 w3 = t[c3+1]->when; 286 c3++; 287 } 288 if(w3 < w) { 289 w = w3; 290 c = c3; 291 } 292 } 293 if(w >= when) 294 break; 295 t[i] = t[c]; 296 t[i]->i = i; 297 t[c] = tmp; 298 tmp->i = c; 299 i = c; 300 } 301 } 302 303 static void 304 dumptimers(int8 *msg) 305 { 306 Timer *t; 307 int32 i; 308 309 runtime·printf("timers: %s\n", msg); 310 for(i = 0; i < timers.len; i++) { 311 t = timers.t[i]; 312 runtime·printf("\t%d\t%p:\ti %d when %D period %D fn %p\n", 313 i, t, t->i, t->when, t->period, t->fv->fn); 314 } 315 runtime·printf("\n"); 316 }