219 lines
3.4 KiB
C
219 lines
3.4 KiB
C
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
#define D(c)
|
|
|
|
static void
|
|
mcslock(Lock *lk, LockEntry *ql)
|
|
{
|
|
LockEntry *pred;
|
|
|
|
D('!');
|
|
ql->next = nil;
|
|
ql->locked = 1;
|
|
pred = xchgm(&lk->head, ql);
|
|
if(pred != nil){
|
|
pred->next = ql;
|
|
if(SUPPORT_MWAIT){
|
|
while(mwait32(&ql->locked, 1) == 1)
|
|
{}
|
|
}else{
|
|
while(ql->locked)
|
|
pause(); /* spin, could monwait */
|
|
}
|
|
} else {
|
|
/* nobody else wait for ql->locked to become zero,
|
|
* but keep things clean
|
|
*/
|
|
ql->locked = 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
mcscanlock(Lock *lk, LockEntry *ql)
|
|
{
|
|
D('?');
|
|
ql->next = nil;
|
|
ql->locked = 0;
|
|
return CASV(&lk->head, nil, ql);
|
|
}
|
|
|
|
static LockEntry*
|
|
mcsunlock(Lock *lk, LockEntry *ql)
|
|
{
|
|
D('#');
|
|
if(ql->next != nil || !CASV(&lk->head, ql, nil)){
|
|
/* successor, wait for list to catch up */
|
|
while(ql->next == nil)
|
|
{}
|
|
xchg32(&ql->next->locked, 0);
|
|
}
|
|
return ql;
|
|
}
|
|
|
|
static LockEntry*
|
|
allocle(Lock *l, uintptr_t pc)
|
|
{
|
|
LockEntry *a, *e;
|
|
|
|
a = &m->locks[0];
|
|
e = a + nelem(m->locks);
|
|
while(a < e && !CASV(&a->used, nil, l))
|
|
++a;
|
|
if(a == e)
|
|
panic("allocle: need more m->locks");
|
|
a->pc = pc;
|
|
a->p = up;
|
|
a->m = m;
|
|
a->isilock = 0;
|
|
return a;
|
|
}
|
|
|
|
static LockEntry*
|
|
findle(Lock *l)
|
|
{
|
|
LockEntry *a;
|
|
|
|
a = l->e;
|
|
if(a->used != l)
|
|
panic("findle");
|
|
return a;
|
|
}
|
|
|
|
int
|
|
lock(Lock *l)
|
|
{
|
|
LockEntry *ql;
|
|
|
|
if(up != nil)
|
|
up->nlocks++;
|
|
ql = allocle(l, getcallerpc());
|
|
mcslock(l, ql);
|
|
l->e = ql;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
canlock(Lock *l)
|
|
{
|
|
LockEntry *ql;
|
|
|
|
if(up != nil)
|
|
up->nlocks++;
|
|
ql = allocle(l, getcallerpc());
|
|
if(mcscanlock(l, ql)){
|
|
l->e = ql;
|
|
return 1;
|
|
}
|
|
ql->used = nil;
|
|
if(up != nil)
|
|
up->nlocks--;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
unlock(Lock *l)
|
|
{
|
|
LockEntry *ql;
|
|
|
|
if(l->head == nil){
|
|
jehanne_print("unlock: not locked: pc %#p\n", getcallerpc());
|
|
return;
|
|
}
|
|
ql = findle(l);
|
|
if(ql->isilock)
|
|
panic("unlock of ilock: pc %#p", getcallerpc());
|
|
if(ql->p != up)
|
|
panic("unlock: up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p",
|
|
getcallerpc(), ql->pc, ql->p, up);
|
|
mcsunlock(l, ql);
|
|
ql->used = nil;
|
|
if(up != nil && --up->nlocks == 0 && up->delaysched && islo()){
|
|
/*
|
|
* Call sched if the need arose while locks were held
|
|
* But, don't do it from interrupt routines, hence the islo() test
|
|
*/
|
|
sched();
|
|
}
|
|
}
|
|
|
|
void
|
|
ilock(Lock *l)
|
|
{
|
|
uintptr_t pc;
|
|
Mreg s;
|
|
LockEntry *ql;
|
|
|
|
pc = getcallerpc();
|
|
s = splhi();
|
|
ql = allocle(l, pc);
|
|
ql->isilock = 1;
|
|
ql->sr = s;
|
|
/* the old taslock code would splx(s) to allow interrupts while waiting (if not nested) */
|
|
mcslock(l, ql);
|
|
l->e = ql;
|
|
m->ilockdepth++;
|
|
m->ilockpc = pc;
|
|
if(up != nil)
|
|
up->lastilock = l;
|
|
}
|
|
|
|
void
|
|
iunlock(Lock *l)
|
|
{
|
|
Mreg s;
|
|
LockEntry *ql;
|
|
|
|
if(islo())
|
|
panic("iunlock while lo: pc %#p\n", getcallerpc());
|
|
ql = findle(l);
|
|
if(!ql->isilock)
|
|
panic("iunlock of lock: pc %#p\n", getcallerpc());
|
|
if(ql->m != m){
|
|
panic("iunlock by cpu%d, locked by cpu%d: pc %#p\n",
|
|
m->machno, ql->m->machno, getcallerpc());
|
|
}
|
|
mcsunlock(l, ql);
|
|
s = ql->sr;
|
|
ql->used = nil;
|
|
m->ilockdepth--;
|
|
if(up != nil)
|
|
up->lastilock = nil;
|
|
splx(s);
|
|
}
|
|
|
|
int
|
|
ownlock(Lock *l)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < nelem(m->locks); i++)
|
|
if(m->locks[i].used == l)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
uintptr_t
|
|
lockgetpc(Lock *l)
|
|
{
|
|
LockEntry *ql;
|
|
|
|
ql = l->e;
|
|
if(ql != nil && ql->used == l)
|
|
return ql->pc;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
locksetpc(Lock *l, uintptr_t pc)
|
|
{
|
|
LockEntry *ql;
|
|
|
|
ql = l->e;
|
|
if(ql != nil && ql->used == l && ql->m == m)
|
|
ql->pc = pc;
|
|
}
|