github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libgo/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 <sys/time.h> 10 11 #include "runtime.h" 12 #include "defs.h" 13 #include "arch.h" 14 #include "malloc.h" 15 16 enum { 17 debug = 0, 18 }; 19 20 static Timers timers; 21 static void addtimer(Timer*); 22 static void dumptimers(const char*); 23 24 // nacl fake time support. 25 int64 runtime_timens; 26 27 // Package time APIs. 28 // Godoc uses the comments in package time, not these. 29 30 // time.now is implemented in assembly. 31 32 // runtimeNano returns the current value of the runtime clock in nanoseconds. 33 func runtimeNano() (ns int64) { 34 ns = runtime_nanotime(); 35 } 36 37 // Sleep puts the current goroutine to sleep for at least ns nanoseconds. 38 func Sleep(ns int64) { 39 runtime_tsleep(ns, "sleep"); 40 } 41 42 // startTimer adds t to the timer heap. 43 func startTimer(t *Timer) { 44 runtime_addtimer(t); 45 } 46 47 // stopTimer removes t from the timer heap if it is there. 48 // It returns true if t was removed, false if t wasn't even there. 49 func stopTimer(t *Timer) (stopped bool) { 50 stopped = runtime_deltimer(t); 51 } 52 53 // C runtime. 54 55 int64 runtime_unixnanotime(void) 56 { 57 struct time_now_ret r; 58 59 r = now(); 60 return r.sec*1000000000 + r.nsec; 61 } 62 63 static void timerproc(void*); 64 static void siftup(int32); 65 static void siftdown(int32); 66 67 // Ready the goroutine e.data. 68 static void 69 ready(Eface e, uintptr seq) 70 { 71 USED(seq); 72 73 runtime_ready(e.__object); 74 } 75 76 static FuncVal readyv = {(void(*)(void))ready}; 77 78 // Put the current goroutine to sleep for ns nanoseconds. 79 void 80 runtime_tsleep(int64 ns, const char *reason) 81 { 82 G* g; 83 Timer t; 84 85 g = runtime_g(); 86 87 if(ns <= 0) 88 return; 89 90 t.when = runtime_nanotime() + ns; 91 t.period = 0; 92 t.fv = &readyv; 93 t.arg.__object = g; 94 t.seq = 0; 95 runtime_lock(&timers.lock); 96 addtimer(&t); 97 runtime_parkunlock(&timers.lock, reason); 98 } 99 100 void 101 runtime_addtimer(Timer *t) 102 { 103 runtime_lock(&timers.lock); 104 addtimer(t); 105 runtime_unlock(&timers.lock); 106 } 107 108 // Add a timer to the heap and start or kick the timer proc 109 // if the new timer is earlier than any of the others. 110 static void 111 addtimer(Timer *t) 112 { 113 int32 n; 114 Timer **nt; 115 116 // when must never be negative; otherwise timerproc will overflow 117 // during its delta calculation and never expire other timers. 118 if(t->when < 0) 119 t->when = (int64)((1ULL<<63)-1); 120 121 if(timers.len >= timers.cap) { 122 // Grow slice. 123 n = 16; 124 if(n <= timers.cap) 125 n = timers.cap*3 / 2; 126 nt = runtime_malloc(n*sizeof nt[0]); 127 runtime_memmove(nt, timers.t, timers.len*sizeof nt[0]); 128 runtime_free(timers.t); 129 timers.t = nt; 130 timers.cap = n; 131 } 132 t->i = timers.len++; 133 timers.t[t->i] = t; 134 siftup(t->i); 135 if(t->i == 0) { 136 // siftup moved to top: new earliest deadline. 137 if(timers.sleeping) { 138 timers.sleeping = false; 139 runtime_notewakeup(&timers.waitnote); 140 } 141 if(timers.rescheduling) { 142 timers.rescheduling = false; 143 runtime_ready(timers.timerproc); 144 } 145 } 146 if(timers.timerproc == nil) { 147 timers.timerproc = __go_go(timerproc, nil); 148 timers.timerproc->issystem = true; 149 } 150 if(debug) 151 dumptimers("addtimer"); 152 } 153 154 // Used to force a dereference before the lock is acquired. 155 static int32 gi; 156 157 // Delete timer t from the heap. 158 // Do not need to update the timerproc: 159 // if it wakes up early, no big deal. 160 bool 161 runtime_deltimer(Timer *t) 162 { 163 int32 i; 164 165 // Dereference t so that any panic happens before the lock is held. 166 // Discard result, because t might be moving in the heap. 167 i = t->i; 168 gi = i; 169 170 runtime_lock(&timers.lock); 171 172 // t may not be registered anymore and may have 173 // a bogus i (typically 0, if generated by Go). 174 // Verify it before proceeding. 175 i = t->i; 176 if(i < 0 || i >= timers.len || timers.t[i] != t) { 177 runtime_unlock(&timers.lock); 178 return false; 179 } 180 181 timers.len--; 182 if(i == timers.len) { 183 timers.t[i] = nil; 184 } else { 185 timers.t[i] = timers.t[timers.len]; 186 timers.t[timers.len] = nil; 187 timers.t[i]->i = i; 188 siftup(i); 189 siftdown(i); 190 } 191 if(debug) 192 dumptimers("deltimer"); 193 runtime_unlock(&timers.lock); 194 return true; 195 } 196 197 // Timerproc runs the time-driven events. 198 // It sleeps until the next event in the timers heap. 199 // If addtimer inserts a new earlier event, addtimer 200 // wakes timerproc early. 201 static void 202 timerproc(void* dummy __attribute__ ((unused))) 203 { 204 int64 delta, now; 205 Timer *t; 206 FuncVal *fv; 207 void (*f)(Eface, uintptr); 208 Eface arg; 209 uintptr seq; 210 211 for(;;) { 212 runtime_lock(&timers.lock); 213 timers.sleeping = false; 214 now = runtime_nanotime(); 215 for(;;) { 216 if(timers.len == 0) { 217 delta = -1; 218 break; 219 } 220 t = timers.t[0]; 221 delta = t->when - now; 222 if(delta > 0) 223 break; 224 if(t->period > 0) { 225 // leave in heap but adjust next time to fire 226 t->when += t->period * (1 + -delta/t->period); 227 siftdown(0); 228 } else { 229 // remove from heap 230 timers.t[0] = timers.t[--timers.len]; 231 timers.t[0]->i = 0; 232 siftdown(0); 233 t->i = -1; // mark as removed 234 } 235 fv = t->fv; 236 f = (void*)t->fv->fn; 237 arg = t->arg; 238 seq = t->seq; 239 runtime_unlock(&timers.lock); 240 __builtin_call_with_static_chain(f(arg, seq), fv); 241 242 // clear f and arg to avoid leak while sleeping for next timer 243 f = nil; 244 USED(f); 245 arg.__type_descriptor = nil; 246 arg.__object = nil; 247 USED(&arg); 248 249 runtime_lock(&timers.lock); 250 } 251 if(delta < 0) { 252 // No timers left - put goroutine to sleep. 253 timers.rescheduling = true; 254 runtime_g()->isbackground = true; 255 runtime_parkunlock(&timers.lock, "timer goroutine (idle)"); 256 runtime_g()->isbackground = false; 257 continue; 258 } 259 // At least one timer pending. Sleep until then. 260 timers.sleeping = true; 261 runtime_noteclear(&timers.waitnote); 262 runtime_unlock(&timers.lock); 263 runtime_notetsleepg(&timers.waitnote, delta); 264 } 265 } 266 267 // heap maintenance algorithms. 268 269 static void 270 siftup(int32 i) 271 { 272 int32 p; 273 int64 when; 274 Timer **t, *tmp; 275 276 t = timers.t; 277 when = t[i]->when; 278 tmp = t[i]; 279 while(i > 0) { 280 p = (i-1)/4; // parent 281 if(when >= t[p]->when) 282 break; 283 t[i] = t[p]; 284 t[i]->i = i; 285 t[p] = tmp; 286 tmp->i = p; 287 i = p; 288 } 289 } 290 291 static void 292 siftdown(int32 i) 293 { 294 int32 c, c3, len; 295 int64 when, w, w3; 296 Timer **t, *tmp; 297 298 t = timers.t; 299 len = timers.len; 300 when = t[i]->when; 301 tmp = t[i]; 302 for(;;) { 303 c = i*4 + 1; // left child 304 c3 = c + 2; // mid child 305 if(c >= len) { 306 break; 307 } 308 w = t[c]->when; 309 if(c+1 < len && t[c+1]->when < w) { 310 w = t[c+1]->when; 311 c++; 312 } 313 if(c3 < len) { 314 w3 = t[c3]->when; 315 if(c3+1 < len && t[c3+1]->when < w3) { 316 w3 = t[c3+1]->when; 317 c3++; 318 } 319 if(w3 < w) { 320 w = w3; 321 c = c3; 322 } 323 } 324 if(w >= when) 325 break; 326 t[i] = t[c]; 327 t[i]->i = i; 328 t[c] = tmp; 329 tmp->i = c; 330 i = c; 331 } 332 } 333 334 static void 335 dumptimers(const char *msg) 336 { 337 Timer *t; 338 int32 i; 339 340 runtime_printf("timers: %s\n", msg); 341 for(i = 0; i < timers.len; i++) { 342 t = timers.t[i]; 343 runtime_printf("\t%d\t%p:\ti %d when %D period %D fn %p\n", 344 i, t, t->i, t->when, t->period, t->fv->fn); 345 } 346 runtime_printf("\n"); 347 } 348 349 void 350 runtime_time_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj)) 351 { 352 enqueue1(wbufp, (Obj){(byte*)&timers, sizeof timers, 0}); 353 }