diff options
author | Ben Cheng <bccheng@google.com> | 2013-03-28 11:14:20 -0700 |
---|---|---|
committer | Ben Cheng <bccheng@google.com> | 2013-03-28 12:40:33 -0700 |
commit | af0c51ac87ab2a87caa03fa108f0d164987a2764 (patch) | |
tree | 4b8b470f7c5b69642fdab8d0aa1fbc148d02196b /gcc-4.8/libgo/runtime/time.goc | |
parent | d87cae247d39ebf4f5a6bf25c932a14d2fdb9384 (diff) | |
download | toolchain_gcc-af0c51ac87ab2a87caa03fa108f0d164987a2764.tar.gz toolchain_gcc-af0c51ac87ab2a87caa03fa108f0d164987a2764.tar.bz2 toolchain_gcc-af0c51ac87ab2a87caa03fa108f0d164987a2764.zip |
[GCC 4.8] Initial check-in of GCC 4.8.0
Change-Id: I0719d8a6d0f69b367a6ab6f10eb75622dbf12771
Diffstat (limited to 'gcc-4.8/libgo/runtime/time.goc')
-rw-r--r-- | gcc-4.8/libgo/runtime/time.goc | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/gcc-4.8/libgo/runtime/time.goc b/gcc-4.8/libgo/runtime/time.goc new file mode 100644 index 000000000..9a5cbdfed --- /dev/null +++ b/gcc-4.8/libgo/runtime/time.goc @@ -0,0 +1,263 @@ +// 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 "runtime.h" +#include "defs.h" +#include "arch.h" +#include "malloc.h" +#include "race.h" + +static Timers timers; +static void addtimer(Timer*); +static bool deltimer(Timer*); + +// Package time APIs. +// Godoc uses the comments in package time, not these. + +// time.now is implemented in assembly. + +// 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) { + if(raceenabled) + runtime_racerelease(t); + runtime_lock(&timers); + addtimer(t); + runtime_unlock(&timers); +} + +// 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 = deltimer(t); +} + +// C runtime. + +static void timerproc(void*); +static void siftup(int32); +static void siftdown(int32); + +// Ready the goroutine e.data. +static void +ready(int64 now, Eface e) +{ + USED(now); + + runtime_ready(e.__object); +} + +// 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.f = ready; + t.arg.__object = g; + runtime_lock(&timers); + addtimer(&t); + runtime_park(runtime_unlock, &timers, reason); +} + +// 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; + + 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; + } +} + +// Delete timer t from the heap. +// Do not need to update the timerproc: +// if it wakes up early, no big deal. +static bool +deltimer(Timer *t) +{ + int32 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); + } + 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; + void (*f)(int64, Eface); + Eface arg; + + for(;;) { + runtime_lock(&timers); + 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 + } + f = t->f; + arg = t->arg; + runtime_unlock(&timers); + if(raceenabled) + runtime_raceacquire(t); + f(now, arg); + runtime_lock(&timers); + } + if(delta < 0) { + // No timers left - put goroutine to sleep. + timers.rescheduling = true; + runtime_park(runtime_unlock, &timers, "timer goroutine (idle)"); + continue; + } + // At least one timer pending. Sleep until then. + timers.sleeping = true; + runtime_noteclear(&timers.waitnote); + runtime_unlock(&timers); + runtime_entersyscall(); + runtime_notetsleep(&timers.waitnote, delta); + runtime_exitsyscall(); + } +} + +// heap maintenance algorithms. + +static void +siftup(int32 i) +{ + int32 p; + Timer **t, *tmp; + + t = timers.t; + while(i > 0) { + p = (i-1)/2; // parent + if(t[i]->when >= t[p]->when) + break; + tmp = t[i]; + t[i] = t[p]; + t[p] = tmp; + t[i]->i = i; + t[p]->i = p; + i = p; + } +} + +static void +siftdown(int32 i) +{ + int32 c, len; + Timer **t, *tmp; + + t = timers.t; + len = timers.len; + for(;;) { + c = i*2 + 1; // left child + if(c >= len) { + break; + } + if(c+1 < len && t[c+1]->when < t[c]->when) + c++; + if(t[c]->when >= t[i]->when) + break; + tmp = t[i]; + t[i] = t[c]; + t[c] = tmp; + t[i]->i = i; + t[c]->i = c; + i = c; + } +} + +void +runtime_time_scan(void (*addroot)(Obj)) +{ + addroot((Obj){(byte*)&timers, sizeof timers, 0}); +} |