This source file includes following definitions.
- runtime·lock
- runtime·unlock
- runtime·noteclear
- runtime·notewakeup
- runtime·notesleep
- notetsleep
- runtime·notetsleep
- runtime·notetsleepg
#include "runtime.h"
#include "stack.h"
#include "../../cmd/ld/textflag.h"
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");
if(runtime·casp((void**)&l->key, nil, (void*)LOCKED))
return;
if(m->waitsema == 0)
m->waitsema = runtime·semacreate();
spin = 0;
if(runtime·ncpu > 1)
spin = ACTIVE_SPIN;
for(i=0;; i++) {
v = (uintptr)runtime·atomicloadp((void**)&l->key);
if((v&LOCKED) == 0) {
unlocked:
if(runtime·casp((void**)&l->key, (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 {
for(;;) {
m->nextwaitm = (void*)(v&~LOCKED);
if(runtime·casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED)))
break;
v = (uintptr)runtime·atomicloadp((void**)&l->key);
if((v&LOCKED) == 0)
goto unlocked;
}
if(v&LOCKED) {
runtime·semasleep(-1);
i = 0;
}
}
}
}
void
runtime·unlock(Lock *l)
{
uintptr v;
M *mp;
for(;;) {
v = (uintptr)runtime·atomicloadp((void**)&l->key);
if(v == LOCKED) {
if(runtime·casp((void**)&l->key, (void*)LOCKED, nil))
break;
} else {
mp = (void*)(v&~LOCKED);
if(runtime·casp((void**)&l->key, (void*)v, mp->nextwaitm)) {
runtime·semawakeup(mp);
break;
}
}
}
if(--m->locks < 0)
runtime·throw("runtime·unlock: lock count");
if(m->locks == 0 && g->preempt)
g->stackguard0 = StackPreempt;
}
void
runtime·noteclear(Note *n)
{
n->key = 0;
}
void
runtime·notewakeup(Note *n)
{
M *mp;
do
mp = runtime·atomicloadp((void**)&n->key);
while(!runtime·casp((void**)&n->key, mp, (void*)LOCKED));
if(mp == nil) {
} else if(mp == (M*)LOCKED) {
runtime·throw("notewakeup - double wakeup");
} else {
runtime·semawakeup(mp);
}
}
void
runtime·notesleep(Note *n)
{
if(g != m->g0)
runtime·throw("notesleep not on g0");
if(m->waitsema == 0)
m->waitsema = runtime·semacreate();
if(!runtime·casp((void**)&n->key, nil, m)) {
if(n->key != LOCKED)
runtime·throw("notesleep - waitm out of sync");
return;
}
m->blocked = true;
runtime·semasleep(-1);
m->blocked = false;
}
#pragma textflag NOSPLIT
static bool
notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
{
if(!runtime·casp((void**)&n->key, nil, m)) {
if(n->key != LOCKED)
runtime·throw("notetsleep - waitm out of sync");
return true;
}
if(ns < 0) {
m->blocked = true;
runtime·semasleep(-1);
m->blocked = false;
return true;
}
deadline = runtime·nanotime() + ns;
for(;;) {
m->blocked = true;
if(runtime·semasleep(ns) >= 0) {
m->blocked = false;
return true;
}
m->blocked = false;
ns = deadline - runtime·nanotime();
if(ns <= 0)
break;
}
for(;;) {
mp = runtime·atomicloadp((void**)&n->key);
if(mp == m) {
if(runtime·casp((void**)&n->key, mp, nil))
return false;
} else if(mp == (M*)LOCKED) {
m->blocked = true;
if(runtime·semasleep(-1) < 0)
runtime·throw("runtime: unable to acquire - semaphore out of sync");
m->blocked = false;
return true;
} else
runtime·throw("runtime: unexpected waitm - semaphore out of sync");
}
}
bool
runtime·notetsleep(Note *n, int64 ns)
{
bool res;
if(g != m->g0 && !m->gcing)
runtime·throw("notetsleep not on g0");
if(m->waitsema == 0)
m->waitsema = runtime·semacreate();
res = notetsleep(n, ns, 0, nil);
return res;
}
bool
runtime·notetsleepg(Note *n, int64 ns)
{
bool res;
if(g == m->g0)
runtime·throw("notetsleepg on g0");
if(m->waitsema == 0)
m->waitsema = runtime·semacreate();
runtime·entersyscallblock();
res = notetsleep(n, ns, 0, nil);
runtime·exitsyscall();
return res;
}