Retro68/gcc/libgo/runtime/time.goc

327 lines
6.3 KiB
Plaintext
Raw Normal View History

2012-03-27 23:13:14 +00:00
// 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"
2014-09-21 17:33:12 +00:00
#include "race.h"
enum {
debug = 0,
};
2012-03-27 23:13:14 +00:00
static Timers timers;
static void addtimer(Timer*);
2014-09-21 17:33:12 +00:00
static void dumptimers(const char*);
2012-03-27 23:13:14 +00:00
// 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) {
2014-09-21 17:33:12 +00:00
runtime_tsleep(ns, "sleep");
2012-03-27 23:13:14 +00:00
}
// startTimer adds t to the timer heap.
func startTimer(t *Timer) {
2014-09-21 17:33:12 +00:00
if(raceenabled)
runtime_racerelease(t);
runtime_addtimer(t);
2012-03-27 23:13:14 +00:00
}
// 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) {
2014-09-21 17:33:12 +00:00
stopped = runtime_deltimer(t);
2012-03-27 23:13:14 +00:00
}
// 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);
}
2014-09-21 17:33:12 +00:00
static FuncVal readyv = {(void(*)(void))ready};
2012-03-27 23:13:14 +00:00
// Put the current goroutine to sleep for ns nanoseconds.
void
2014-09-21 17:33:12 +00:00
runtime_tsleep(int64 ns, const char *reason)
2012-03-27 23:13:14 +00:00
{
2014-09-21 17:33:12 +00:00
G* g;
2012-03-27 23:13:14 +00:00
Timer t;
2014-09-21 17:33:12 +00:00
g = runtime_g();
2012-03-27 23:13:14 +00:00
if(ns <= 0)
return;
t.when = runtime_nanotime() + ns;
t.period = 0;
2014-09-21 17:33:12 +00:00
t.fv = &readyv;
t.arg.__object = g;
runtime_lock(&timers);
2012-03-27 23:13:14 +00:00
addtimer(&t);
2014-09-21 17:33:12 +00:00
runtime_park(runtime_unlock, &timers, reason);
}
void
runtime_addtimer(Timer *t)
{
runtime_lock(&timers);
addtimer(t);
runtime_unlock(&timers);
2012-03-27 23:13:14 +00:00
}
// 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;
2014-09-21 17:33:12 +00:00
// 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);
2012-03-27 23:13:14 +00:00
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);
}
}
2014-09-21 17:33:12 +00:00
if(timers.timerproc == nil) {
2012-03-27 23:13:14 +00:00
timers.timerproc = __go_go(timerproc, nil);
2014-09-21 17:33:12 +00:00
timers.timerproc->issystem = true;
}
if(debug)
dumptimers("addtimer");
2012-03-27 23:13:14 +00:00
}
2014-09-21 17:33:12 +00:00
// Used to force a dereference before the lock is acquired.
static int32 gi;
2012-03-27 23:13:14 +00:00
// Delete timer t from the heap.
// Do not need to update the timerproc:
// if it wakes up early, no big deal.
2014-09-21 17:33:12 +00:00
bool
runtime_deltimer(Timer *t)
2012-03-27 23:13:14 +00:00
{
int32 i;
2014-09-21 17:33:12 +00:00
// 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;
2012-03-27 23:13:14 +00:00
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);
}
2014-09-21 17:33:12 +00:00
if(debug)
dumptimers("deltimer");
2012-03-27 23:13:14 +00:00
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);
2014-09-21 17:33:12 +00:00
timers.sleeping = false;
2012-03-27 23:13:14 +00:00
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
}
2014-09-21 17:33:12 +00:00
f = (void*)t->fv->fn;
2012-03-27 23:13:14 +00:00
arg = t->arg;
runtime_unlock(&timers);
2014-09-21 17:33:12 +00:00
if(raceenabled)
runtime_raceacquire(t);
__go_set_closure(t->fv);
2012-03-27 23:13:14 +00:00
f(now, arg);
runtime_lock(&timers);
}
if(delta < 0) {
// No timers left - put goroutine to sleep.
timers.rescheduling = true;
2014-09-21 17:33:12 +00:00
runtime_park(runtime_unlock, &timers, "timer goroutine (idle)");
2012-03-27 23:13:14 +00:00
continue;
}
// At least one timer pending. Sleep until then.
timers.sleeping = true;
runtime_noteclear(&timers.waitnote);
runtime_unlock(&timers);
2014-09-21 17:33:12 +00:00
runtime_notetsleepg(&timers.waitnote, delta);
2012-03-27 23:13:14 +00:00
}
}
// heap maintenance algorithms.
static void
siftup(int32 i)
{
int32 p;
2014-09-21 17:33:12 +00:00
int64 when;
2012-03-27 23:13:14 +00:00
Timer **t, *tmp;
t = timers.t;
2014-09-21 17:33:12 +00:00
when = t[i]->when;
tmp = t[i];
2012-03-27 23:13:14 +00:00
while(i > 0) {
2014-09-21 17:33:12 +00:00
p = (i-1)/4; // parent
if(when >= t[p]->when)
2012-03-27 23:13:14 +00:00
break;
t[i] = t[p];
t[i]->i = i;
2014-09-21 17:33:12 +00:00
t[p] = tmp;
tmp->i = p;
2012-03-27 23:13:14 +00:00
i = p;
}
}
static void
siftdown(int32 i)
{
2014-09-21 17:33:12 +00:00
int32 c, c3, len;
int64 when, w, w3;
2012-03-27 23:13:14 +00:00
Timer **t, *tmp;
t = timers.t;
len = timers.len;
2014-09-21 17:33:12 +00:00
when = t[i]->when;
tmp = t[i];
2012-03-27 23:13:14 +00:00
for(;;) {
2014-09-21 17:33:12 +00:00
c = i*4 + 1; // left child
c3 = c + 2; // mid child
2012-03-27 23:13:14 +00:00
if(c >= len) {
break;
}
2014-09-21 17:33:12 +00:00
w = t[c]->when;
if(c+1 < len && t[c+1]->when < w) {
w = t[c+1]->when;
2012-03-27 23:13:14 +00:00
c++;
2014-09-21 17:33:12 +00:00
}
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)
2012-03-27 23:13:14 +00:00
break;
t[i] = t[c];
t[i]->i = i;
2014-09-21 17:33:12 +00:00
t[c] = tmp;
tmp->i = c;
2012-03-27 23:13:14 +00:00
i = c;
}
}
2014-09-21 17:33:12 +00:00
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");
}
2012-03-27 23:13:14 +00:00
void
2014-09-21 17:33:12 +00:00
runtime_time_scan(void (*addroot)(Obj))
2012-03-27 23:13:14 +00:00
{
2014-09-21 17:33:12 +00:00
addroot((Obj){(byte*)&timers, sizeof timers, 0});
2012-03-27 23:13:14 +00:00
}