OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [runtime/] [time.goc] - Rev 761

Go to most recent revision | 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 void
ready(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.
void
runtime_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 void
addtimer(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 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)))
{
        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 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);
                        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 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 (*scan)(byte*, int64))
{
        scan((byte*)&timers, sizeof timers);
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.