2011-11-02 07:42:01 -06:00
|
|
|
// Copyright 2011 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.
|
|
|
|
|
2011-12-19 13:51:13 -07:00
|
|
|
// +build darwin netbsd openbsd plan9 windows
|
|
|
|
|
2011-11-02 07:42:01 -06:00
|
|
|
#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
|
|
|
// This implementation depends on OS-specific implementations of
|
|
|
|
//
|
2011-12-19 21:56:37 -07:00
|
|
|
// uintptr runtime·semacreate(void)
|
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
|
|
|
// Create a semaphore, which will be assigned to m->waitsema.
|
|
|
|
// The zero value is treated as absence of any semaphore,
|
|
|
|
// so be sure to return a non-zero value.
|
|
|
|
//
|
2011-12-19 21:56:37 -07:00
|
|
|
// int32 runtime·semasleep(int64 ns)
|
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 ns < 0, acquire m->waitsema and return 0.
|
|
|
|
// If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds.
|
|
|
|
// Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
|
|
|
|
//
|
2011-12-19 21:56:37 -07:00
|
|
|
// int32 runtime·semawakeup(M *mp)
|
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
|
|
|
// Wake up mp, which is or will soon be sleeping on mp->waitsema.
|
|
|
|
//
|
|
|
|
|
2011-11-02 07:42:01 -06:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
LOCKED = 1,
|
|
|
|
|
|
|
|
ACTIVE_SPIN = 4,
|
|
|
|
ACTIVE_SPIN_CNT = 30,
|
|
|
|
PASSIVE_SPIN = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime·lock(Lock *l)
|
|
|
|
{
|
|
|
|
uintptr v;
|
|
|
|
uint32 i, spin;
|
|
|
|
|
|
|
|
if(m->locks++ < 0)
|
|
|
|
runtime·throw("runtime·lock: lock count");
|
|
|
|
|
|
|
|
// Speculative grab for lock.
|
|
|
|
if(runtime·casp(&l->waitm, nil, (void*)LOCKED))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(m->waitsema == 0)
|
|
|
|
m->waitsema = runtime·semacreate();
|
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
|
|
|
|
2011-11-02 07:42:01 -06:00
|
|
|
// On uniprocessor's, no point spinning.
|
|
|
|
// On multiprocessors, spin for ACTIVE_SPIN attempts.
|
|
|
|
spin = 0;
|
|
|
|
if(runtime·ncpu > 1)
|
|
|
|
spin = ACTIVE_SPIN;
|
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
|
|
|
|
2011-11-02 07:42:01 -06:00
|
|
|
for(i=0;; i++) {
|
|
|
|
v = (uintptr)runtime·atomicloadp(&l->waitm);
|
|
|
|
if((v&LOCKED) == 0) {
|
|
|
|
unlocked:
|
|
|
|
if(runtime·casp(&l->waitm, (void*)v, (void*)(v|LOCKED)))
|
|
|
|
return;
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
if(i<spin)
|
|
|
|
runtime·procyield(ACTIVE_SPIN_CNT);
|
|
|
|
else if(i<spin+PASSIVE_SPIN)
|
|
|
|
runtime·osyield();
|
|
|
|
else {
|
|
|
|
// Someone else has it.
|
|
|
|
// l->waitm points to a linked list of M's waiting
|
|
|
|
// for this lock, chained through m->nextwaitm.
|
|
|
|
// Queue this M.
|
|
|
|
for(;;) {
|
|
|
|
m->nextwaitm = (void*)(v&~LOCKED);
|
|
|
|
if(runtime·casp(&l->waitm, (void*)v, (void*)((uintptr)m|LOCKED)))
|
|
|
|
break;
|
|
|
|
v = (uintptr)runtime·atomicloadp(&l->waitm);
|
|
|
|
if((v&LOCKED) == 0)
|
|
|
|
goto unlocked;
|
|
|
|
}
|
|
|
|
if(v&LOCKED) {
|
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
|
|
|
// Queued. Wait.
|
|
|
|
runtime·semasleep(-1);
|
2011-11-02 07:42:01 -06:00
|
|
|
i = 0;
|
|
|
|
}
|
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
|
|
|
}
|
2011-11-02 07:42:01 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime·unlock(Lock *l)
|
|
|
|
{
|
|
|
|
uintptr v;
|
|
|
|
M *mp;
|
|
|
|
|
|
|
|
if(--m->locks < 0)
|
|
|
|
runtime·throw("runtime·unlock: lock count");
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
v = (uintptr)runtime·atomicloadp(&l->waitm);
|
|
|
|
if(v == LOCKED) {
|
|
|
|
if(runtime·casp(&l->waitm, (void*)LOCKED, nil))
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Other M's are waiting for the lock.
|
|
|
|
// Dequeue an M.
|
|
|
|
mp = (void*)(v&~LOCKED);
|
|
|
|
if(runtime·casp(&l->waitm, (void*)v, mp->nextwaitm)) {
|
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
|
|
|
// Dequeued an M. Wake it.
|
2011-11-02 07:42:01 -06:00
|
|
|
runtime·semawakeup(mp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// One-time notifications.
|
|
|
|
void
|
|
|
|
runtime·noteclear(Note *n)
|
|
|
|
{
|
|
|
|
n->waitm = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime·notewakeup(Note *n)
|
|
|
|
{
|
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
|
|
|
M *mp;
|
|
|
|
|
|
|
|
do
|
|
|
|
mp = runtime·atomicloadp(&n->waitm);
|
|
|
|
while(!runtime·casp(&n->waitm, mp, (void*)LOCKED));
|
|
|
|
|
|
|
|
// Successfully set waitm to LOCKED.
|
|
|
|
// What was it before?
|
|
|
|
if(mp == nil) {
|
|
|
|
// Nothing was waiting. Done.
|
|
|
|
} else if(mp == (M*)LOCKED) {
|
|
|
|
// Two notewakeups! Not allowed.
|
|
|
|
runtime·throw("notewakeup - double wakeup");
|
|
|
|
} else {
|
|
|
|
// Must be the waiting m. Wake it up.
|
|
|
|
runtime·semawakeup(mp);
|
|
|
|
}
|
2011-11-02 07:42:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime·notesleep(Note *n)
|
|
|
|
{
|
|
|
|
if(m->waitsema == 0)
|
|
|
|
m->waitsema = runtime·semacreate();
|
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(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup)
|
|
|
|
if(n->waitm != (void*)LOCKED)
|
|
|
|
runtime·throw("notesleep - waitm out of sync");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Queued. Sleep.
|
2012-02-28 14:18:24 -07:00
|
|
|
if(m->profilehz > 0)
|
|
|
|
runtime·setprof(false);
|
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·semasleep(-1);
|
2012-02-28 14:18:24 -07:00
|
|
|
if(m->profilehz > 0)
|
|
|
|
runtime·setprof(true);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime·notetsleep(Note *n, int64 ns)
|
|
|
|
{
|
|
|
|
M *mp;
|
|
|
|
int64 deadline, now;
|
|
|
|
|
|
|
|
if(ns < 0) {
|
|
|
|
runtime·notesleep(n);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m->waitsema == 0)
|
|
|
|
m->waitsema = runtime·semacreate();
|
|
|
|
|
|
|
|
// Register for wakeup on n->waitm.
|
|
|
|
if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup already)
|
|
|
|
if(n->waitm != (void*)LOCKED)
|
|
|
|
runtime·throw("notetsleep - waitm out of sync");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-28 14:18:24 -07:00
|
|
|
if(m->profilehz > 0)
|
|
|
|
runtime·setprof(false);
|
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
|
|
|
deadline = runtime·nanotime() + ns;
|
|
|
|
for(;;) {
|
|
|
|
// Registered. Sleep.
|
|
|
|
if(runtime·semasleep(ns) >= 0) {
|
|
|
|
// Acquired semaphore, semawakeup unregistered us.
|
|
|
|
// Done.
|
2012-02-28 14:18:24 -07:00
|
|
|
if(m->profilehz > 0)
|
|
|
|
runtime·setprof(true);
|
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
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interrupted or timed out. Still registered. Semaphore not acquired.
|
|
|
|
now = runtime·nanotime();
|
|
|
|
if(now >= deadline)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Deadline hasn't arrived. Keep sleeping.
|
|
|
|
ns = deadline - now;
|
|
|
|
}
|
|
|
|
|
2012-02-28 14:18:24 -07:00
|
|
|
if(m->profilehz > 0)
|
|
|
|
runtime·setprof(true);
|
|
|
|
|
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
|
|
|
// Deadline arrived. Still registered. Semaphore not acquired.
|
|
|
|
// Want to give up and return, but have to unregister first,
|
|
|
|
// so that any notewakeup racing with the return does not
|
|
|
|
// try to grant us the semaphore when we don't expect it.
|
|
|
|
for(;;) {
|
|
|
|
mp = runtime·atomicloadp(&n->waitm);
|
|
|
|
if(mp == m) {
|
|
|
|
// No wakeup yet; unregister if possible.
|
|
|
|
if(runtime·casp(&n->waitm, mp, nil))
|
|
|
|
return;
|
|
|
|
} else if(mp == (M*)LOCKED) {
|
|
|
|
// Wakeup happened so semaphore is available.
|
|
|
|
// Grab it to avoid getting out of sync.
|
|
|
|
if(runtime·semasleep(-1) < 0)
|
|
|
|
runtime·throw("runtime: unable to acquire - semaphore out of sync");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
runtime·throw("runtime: unexpected waitm - semaphore out of sync");
|
|
|
|
}
|
|
|
|
}
|
2011-11-02 07:42:01 -06:00
|
|
|
}
|