aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/libgo/runtime/time.goc
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2013-03-28 11:14:20 -0700
committerBen Cheng <bccheng@google.com>2013-03-28 12:40:33 -0700
commitaf0c51ac87ab2a87caa03fa108f0d164987a2764 (patch)
tree4b8b470f7c5b69642fdab8d0aa1fbc148d02196b /gcc-4.8/libgo/runtime/time.goc
parentd87cae247d39ebf4f5a6bf25c932a14d2fdb9384 (diff)
downloadtoolchain_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.goc263
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});
+}