123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Time-related runtime and pieces of package time.
- package time
- #include <sys/time.h>
- #include "runtime.h"
- #include "defs.h"
- #include "arch.h"
- #include "malloc.h"
- enum {
- debug = 0,
- };
- static Timers timers;
- static void addtimer(Timer*);
- static void dumptimers(const char*);
- // nacl fake time support.
- int64 runtime_timens;
- // Package time APIs.
- // Godoc uses the comments in package time, not these.
- // time.now is implemented in assembly.
- // runtimeNano returns the current value of the runtime clock in nanoseconds.
- func runtimeNano() (ns int64) {
- ns = runtime_nanotime();
- }
- // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
- func Sleep(ns int64) {
- runtime_tsleep(ns, "sleep");
- }
- // startTimer adds t to the timer heap.
- func startTimer(t *Timer) {
- runtime_addtimer(t);
- }
- // stopTimer removes t from the timer heap if it is there.
- // It returns true if t was removed, false if t wasn't even there.
- func stopTimer(t *Timer) (stopped bool) {
- stopped = runtime_deltimer(t);
- }
- // C runtime.
- int64 runtime_unixnanotime(void)
- {
- struct time_now_ret r;
- r = now();
- return r.sec*1000000000 + r.nsec;
- }
- static void timerproc(void*);
- static void siftup(int32);
- static void siftdown(int32);
- // Ready the goroutine e.data.
- static void
- ready(Eface e, uintptr seq)
- {
- USED(seq);
- runtime_ready(e.__object);
- }
- static FuncVal readyv = {(void(*)(void))ready};
- // Put the current goroutine to sleep for ns nanoseconds.
- void
- runtime_tsleep(int64 ns, const char *reason)
- {
- G* g;
- Timer t;
- g = runtime_g();
- if(ns <= 0)
- return;
- t.when = runtime_nanotime() + ns;
- t.period = 0;
- t.fv = &readyv;
- t.arg.__object = g;
- t.seq = 0;
- runtime_lock(&timers);
- addtimer(&t);
- runtime_parkunlock(&timers, reason);
- }
- void
- runtime_addtimer(Timer *t)
- {
- runtime_lock(&timers);
- addtimer(t);
- runtime_unlock(&timers);
- }
- // Add a timer to the heap and start or kick the timer proc
- // if the new timer is earlier than any of the others.
- static void
- addtimer(Timer *t)
- {
- int32 n;
- Timer **nt;
- // when must never be negative; otherwise timerproc will overflow
- // during its delta calculation and never expire other timers.
- if(t->when < 0)
- t->when = (int64)((1ULL<<63)-1);
- if(timers.len >= timers.cap) {
- // Grow slice.
- n = 16;
- if(n <= timers.cap)
- n = timers.cap*3 / 2;
- nt = runtime_malloc(n*sizeof nt[0]);
- runtime_memmove(nt, timers.t, timers.len*sizeof nt[0]);
- runtime_free(timers.t);
- timers.t = nt;
- timers.cap = n;
- }
- t->i = timers.len++;
- timers.t[t->i] = t;
- siftup(t->i);
- if(t->i == 0) {
- // siftup moved to top: new earliest deadline.
- if(timers.sleeping) {
- timers.sleeping = false;
- runtime_notewakeup(&timers.waitnote);
- }
- if(timers.rescheduling) {
- timers.rescheduling = false;
- runtime_ready(timers.timerproc);
- }
- }
- if(timers.timerproc == nil) {
- timers.timerproc = __go_go(timerproc, nil);
- timers.timerproc->issystem = true;
- }
- if(debug)
- dumptimers("addtimer");
- }
- // Used to force a dereference before the lock is acquired.
- static int32 gi;
- // Delete timer t from the heap.
- // Do not need to update the timerproc:
- // if it wakes up early, no big deal.
- bool
- runtime_deltimer(Timer *t)
- {
- int32 i;
- // Dereference t so that any panic happens before the lock is held.
- // Discard result, because t might be moving in the heap.
- i = t->i;
- gi = i;
- runtime_lock(&timers);
- // t may not be registered anymore and may have
- // a bogus i (typically 0, if generated by Go).
- // Verify it before proceeding.
- i = t->i;
- if(i < 0 || i >= timers.len || timers.t[i] != t) {
- runtime_unlock(&timers);
- return false;
- }
- timers.len--;
- if(i == timers.len) {
- timers.t[i] = nil;
- } else {
- timers.t[i] = timers.t[timers.len];
- timers.t[timers.len] = nil;
- timers.t[i]->i = i;
- siftup(i);
- siftdown(i);
- }
- if(debug)
- dumptimers("deltimer");
- runtime_unlock(&timers);
- return true;
- }
- // Timerproc runs the time-driven events.
- // It sleeps until the next event in the timers heap.
- // If addtimer inserts a new earlier event, addtimer
- // wakes timerproc early.
- static void
- timerproc(void* dummy __attribute__ ((unused)))
- {
- int64 delta, now;
- Timer *t;
- FuncVal *fv;
- void (*f)(Eface, uintptr);
- Eface arg;
- uintptr seq;
- for(;;) {
- runtime_lock(&timers);
- timers.sleeping = false;
- now = runtime_nanotime();
- for(;;) {
- if(timers.len == 0) {
- delta = -1;
- break;
- }
- t = timers.t[0];
- delta = t->when - now;
- if(delta > 0)
- break;
- if(t->period > 0) {
- // leave in heap but adjust next time to fire
- t->when += t->period * (1 + -delta/t->period);
- siftdown(0);
- } else {
- // remove from heap
- timers.t[0] = timers.t[--timers.len];
- timers.t[0]->i = 0;
- siftdown(0);
- t->i = -1; // mark as removed
- }
- fv = t->fv;
- f = (void*)t->fv->fn;
- arg = t->arg;
- seq = t->seq;
- runtime_unlock(&timers);
- __builtin_call_with_static_chain(f(arg, seq), fv);
- // clear f and arg to avoid leak while sleeping for next timer
- f = nil;
- USED(f);
- arg.__type_descriptor = nil;
- arg.__object = nil;
- USED(&arg);
- runtime_lock(&timers);
- }
- if(delta < 0) {
- // No timers left - put goroutine to sleep.
- timers.rescheduling = true;
- runtime_g()->isbackground = true;
- runtime_parkunlock(&timers, "timer goroutine (idle)");
- runtime_g()->isbackground = false;
- continue;
- }
- // At least one timer pending. Sleep until then.
- timers.sleeping = true;
- runtime_noteclear(&timers.waitnote);
- runtime_unlock(&timers);
- runtime_notetsleepg(&timers.waitnote, delta);
- }
- }
- // heap maintenance algorithms.
- static void
- siftup(int32 i)
- {
- int32 p;
- int64 when;
- Timer **t, *tmp;
- t = timers.t;
- when = t[i]->when;
- tmp = t[i];
- while(i > 0) {
- p = (i-1)/4; // parent
- if(when >= t[p]->when)
- break;
- t[i] = t[p];
- t[i]->i = i;
- t[p] = tmp;
- tmp->i = p;
- i = p;
- }
- }
- static void
- siftdown(int32 i)
- {
- int32 c, c3, len;
- int64 when, w, w3;
- Timer **t, *tmp;
- t = timers.t;
- len = timers.len;
- when = t[i]->when;
- tmp = t[i];
- for(;;) {
- c = i*4 + 1; // left child
- c3 = c + 2; // mid child
- if(c >= len) {
- break;
- }
- w = t[c]->when;
- if(c+1 < len && t[c+1]->when < w) {
- w = t[c+1]->when;
- c++;
- }
- if(c3 < len) {
- w3 = t[c3]->when;
- if(c3+1 < len && t[c3+1]->when < w3) {
- w3 = t[c3+1]->when;
- c3++;
- }
- if(w3 < w) {
- w = w3;
- c = c3;
- }
- }
- if(w >= when)
- break;
- t[i] = t[c];
- t[i]->i = i;
- t[c] = tmp;
- tmp->i = c;
- i = c;
- }
- }
- static void
- dumptimers(const char *msg)
- {
- Timer *t;
- int32 i;
- runtime_printf("timers: %s\n", msg);
- for(i = 0; i < timers.len; i++) {
- t = timers.t[i];
- runtime_printf("\t%d\t%p:\ti %d when %D period %D fn %p\n",
- i, t, t->i, t->when, t->period, t->fv->fn);
- }
- runtime_printf("\n");
- }
- void
- runtime_time_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
- {
- enqueue1(wbufp, (Obj){(byte*)&timers, sizeof timers, 0});
- }
|