URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [runtime/] [time.goc] - Rev 747
Compare with Previous | Blame | View Log
// 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"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) {G *g;g = runtime_g();g->status = Gwaiting;g->waitreason = "sleep";runtime_tsleep(ns);}// startTimer adds t to the timer heap.func startTimer(t *Timer) {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 = deltimer(t);}// C runtime.static void timerproc(void*);static void siftup(int32);static void siftdown(int32);// Ready the goroutine e.data.static voidready(int64 now, Eface e){USED(now);runtime_ready(e.__object);}// Put the current goroutine to sleep for ns nanoseconds.// The caller must have set g->status and g->waitreason.voidruntime_tsleep(int64 ns){Timer t;if(ns <= 0)return;t.when = runtime_nanotime() + ns;t.period = 0;t.f = ready;t.arg.__object = runtime_g();addtimer(&t);runtime_gosched();}// 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 voidaddtimer(Timer *t){int32 n;Timer **nt;runtime_lock(&timers);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);runtime_unlock(&timers);}// Delete timer t from the heap.// Do not need to update the timerproc:// if it wakes up early, no big deal.static booldeltimer(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 voidtimerproc(void* dummy __attribute__ ((unused))){G *g;int64 delta, now;Timer *t;void (*f)(int64, Eface);Eface arg;g = runtime_g();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 firet->when += t->period * (1 + -delta/t->period);siftdown(0);} else {// remove from heaptimers.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);f(now, arg);runtime_lock(&timers);}if(delta < 0) {// No timers left - put goroutine to sleep.timers.rescheduling = true;g->status = Gwaiting;g->waitreason = "timer goroutine (idle)";runtime_unlock(&timers);runtime_gosched();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 voidsiftup(int32 i){int32 p;Timer **t, *tmp;t = timers.t;while(i > 0) {p = (i-1)/2; // parentif(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 voidsiftdown(int32 i){int32 c, len;Timer **t, *tmp;t = timers.t;len = timers.len;for(;;) {c = i*2 + 1; // left childif(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;}}voidruntime_time_scan(void (*scan)(byte*, int64)){scan((byte*)&timers, sizeof timers);}
