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
This commit is contained in:
Russ Cox 2011-11-09 15:17:05 -05:00
parent fbfed49134
commit 3b860269ee
15 changed files with 662 additions and 390 deletions

View file

@ -62,21 +62,52 @@ runtime·semacreate(void)
return 1;
}
void
runtime·semasleep(void)
int32
runtime·semasleep(int64 ns)
{
retry:
Timespec ts;
// spin-mutex lock
while(runtime·xchg(&m->waitsemalock, 1))
runtime·osyield();
if(m->waitsemacount == 0) {
// the function unlocks the spinlock
runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock);
goto retry;
for(;;) {
// lock held
if(m->waitsemacount == 0) {
// sleep until semaphore != 0 or timeout.
// thrsleep unlocks m->waitsemalock.
if(ns < 0)
runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock);
else {
ts.tv_sec = ns/1000000000LL;
ts.tv_nsec = ns%1000000000LL;
runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock);
}
// reacquire lock
while(runtime·xchg(&m->waitsemalock, 1))
runtime·osyield();
}
// lock held (again)
if(m->waitsemacount != 0) {
// semaphore is available.
m->waitsemacount--;
// spin-mutex unlock
runtime·atomicstore(&m->waitsemalock, 0);
return 0; // semaphore acquired
}
// semaphore not available.
// if there is a timeout, stop now.
// otherwise keep trying.
if(ns >= 0)
break;
}
m->waitsemacount--;
// lock held but giving up
// spin-mutex unlock
runtime·atomicstore(&m->waitsemalock, 0);
return -1;
}
void