2011-11-03 15:35:28 -06: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.
|
|
|
|
|
runtime: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07:00
|
|
|
// Time-related runtime and pieces of package time.
|
2011-11-03 15:35:28 -06:00
|
|
|
|
|
|
|
package time
|
|
|
|
|
|
|
|
#include "runtime.h"
|
runtime: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07:00
|
|
|
#include "defs.h"
|
|
|
|
#include "os.h"
|
|
|
|
#include "arch.h"
|
|
|
|
#include "malloc.h"
|
2011-11-03 15:35:28 -06:00
|
|
|
|
runtime: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07:00
|
|
|
static Timers timers;
|
|
|
|
static void addtimer(Timer*);
|
|
|
|
static bool deltimer(Timer*);
|
|
|
|
|
|
|
|
// Package time APIs.
|
|
|
|
// Godoc uses the comments in package time, not these.
|
|
|
|
|
2011-11-30 09:59:44 -07:00
|
|
|
// time.now is implemented in assembly.
|
runtime: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07:00
|
|
|
|
|
|
|
// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
|
|
|
|
func Sleep(ns int64) {
|
|
|
|
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.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.data = 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 = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-11-25 04:13:10 -07:00
|
|
|
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: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07: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)
|
|
|
|
{
|
|
|
|
int64 delta, now;
|
|
|
|
Timer *t;
|
2011-11-14 11:59:48 -07:00
|
|
|
void (*f)(int64, Eface);
|
|
|
|
Eface arg;
|
runtime: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2011-11-14 11:59:48 -07:00
|
|
|
f = t->f;
|
|
|
|
arg = t->arg;
|
|
|
|
runtime·unlock(&timers);
|
|
|
|
f(now, arg);
|
|
|
|
runtime·lock(&timers);
|
runtime: add timer support, use for package time
This looks like it is just moving some code from
time to runtime (and translating it to C), but the
runtime can do a better job managing the goroutines,
and it needs this functionality for its own maintenance
(for example, for the garbage collector to hand back
unused memory to the OS on a time delay).
Might as well have just one copy of the timer logic,
and runtime can't depend on time, so vice versa.
It also unifies Sleep, NewTicker, and NewTimer behind
one mechanism, so that there are no claims that one
is more efficient than another. (For example, today
people recommend using time.After instead of time.Sleep
to avoid blocking an OS thread.)
Fixes #1644.
Fixes #1731.
Fixes #2190.
R=golang-dev, r, hectorchu, iant, iant, jsing, alex.brainman, dvyukov
CC=golang-dev
https://golang.org/cl/5334051
2011-11-09 13:17:05 -07:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|