5e: approximate LL/SC with cas()
This commit is contained in:
parent
fcfc849dd5
commit
e2a6e622c7
2 changed files with 33 additions and 32 deletions
|
@ -120,10 +120,13 @@ single(u32int instr)
|
||||||
*Rn = addr;
|
*Rn = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* atomic compare and swap from libc */
|
||||||
|
extern int cas(u32int *p, u32int old, u32int new);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
swap(u32int instr)
|
swap(u32int instr)
|
||||||
{
|
{
|
||||||
u32int *Rm, *Rn, *Rd, *targ, addr, tmp;
|
u32int *Rm, *Rn, *Rd, *targ, addr, old, new;
|
||||||
Segment *seg;
|
Segment *seg;
|
||||||
|
|
||||||
Rm = P->R + (instr & 15);
|
Rm = P->R + (instr & 15);
|
||||||
|
@ -134,19 +137,21 @@ swap(u32int instr)
|
||||||
addr = *Rn;
|
addr = *Rn;
|
||||||
if((instr & fB) == 0)
|
if((instr & fB) == 0)
|
||||||
addr = evenaddr(addr, 3);
|
addr = evenaddr(addr, 3);
|
||||||
clrex();
|
targ = (u32int *) vaddr(addr & ~3, 4, &seg);
|
||||||
targ = (u32int *) vaddr(addr, 4, &seg);
|
do {
|
||||||
lock(&seg->lock);
|
old = *targ;
|
||||||
if(instr & fB) {
|
new = *Rm;
|
||||||
tmp = *(u8int*) targ;
|
if(instr & fB){
|
||||||
*(u8int*) targ = *Rm;
|
new &= 0xFF;
|
||||||
*Rd = tmp;
|
new <<= 8*(addr&3);
|
||||||
} else {
|
new |= old & ~(0xFF << 8*(addr&3));
|
||||||
tmp = *targ;
|
|
||||||
*targ = *Rm;
|
|
||||||
*Rd = tmp;
|
|
||||||
}
|
}
|
||||||
unlock(&seg->lock);
|
} while(!cas(targ, old, new));
|
||||||
|
if(instr & fB) {
|
||||||
|
old >>= 8*(addr&3);
|
||||||
|
old &= 0xFF;
|
||||||
|
}
|
||||||
|
*Rd = old;
|
||||||
segunlock(seg);
|
segunlock(seg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,26 +406,24 @@ singleex(u32int instr)
|
||||||
invalid(instr);
|
invalid(instr);
|
||||||
addr = evenaddr(*Rn, 3);
|
addr = evenaddr(*Rn, 3);
|
||||||
if(instr & fS) {
|
if(instr & fS) {
|
||||||
clrex();
|
|
||||||
targ = vaddr(addr, 4, &seg);
|
targ = vaddr(addr, 4, &seg);
|
||||||
lock(&seg->lock);
|
|
||||||
P->excl = seg;
|
|
||||||
*Rd = *targ;
|
*Rd = *targ;
|
||||||
|
P->lladdr = addr;
|
||||||
|
P->llval = *Rd;
|
||||||
segunlock(seg);
|
segunlock(seg);
|
||||||
} else {
|
} else {
|
||||||
Rm = P->R + (instr & 15);
|
Rm = P->R + (instr & 15);
|
||||||
if(Rm == P->R + 15)
|
if(Rm == P->R + 15)
|
||||||
invalid(instr);
|
invalid(instr);
|
||||||
targ = vaddr(addr, 4, &seg);
|
targ = vaddr(addr, 4, &seg);
|
||||||
if(canlock(&seg->lock)) {
|
|
||||||
unlock(&seg->lock);
|
/*
|
||||||
*Rd = 1;
|
* this is not quite correct as we will succeed even
|
||||||
} else if(P->excl != seg) {
|
* if the value was modified and then restored to its
|
||||||
*Rd = 1;
|
* original value but good enougth approximation for
|
||||||
} else {
|
* libc's _tas(), _cas() and _xinc()/_xdec().
|
||||||
*targ = *Rm;
|
*/
|
||||||
*Rd = 0;
|
*Rd = addr != P->lladdr || !cas(targ, P->llval, *Rm);
|
||||||
}
|
|
||||||
segunlock(seg);
|
segunlock(seg);
|
||||||
clrex();
|
clrex();
|
||||||
}
|
}
|
||||||
|
@ -429,12 +432,8 @@ singleex(u32int instr)
|
||||||
void
|
void
|
||||||
clrex(void)
|
clrex(void)
|
||||||
{
|
{
|
||||||
Segment *seg;
|
P->lladdr = 0;
|
||||||
|
P->llval = 0;
|
||||||
seg = P->excl;
|
|
||||||
P->excl = nil;
|
|
||||||
if(seg != nil)
|
|
||||||
unlock(&seg->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -31,7 +31,10 @@ struct Process {
|
||||||
Ref *path; /* Ref + string data */
|
Ref *path; /* Ref + string data */
|
||||||
|
|
||||||
Segment *S[SEGNUM]; /* memory */
|
Segment *S[SEGNUM]; /* memory */
|
||||||
Segment *excl; /* recently acquired exclusive access */
|
|
||||||
|
u32int lladdr; /* LL/SC emulation */
|
||||||
|
u32int llval;
|
||||||
|
|
||||||
u32int R[16]; /* general purpose registers / PC (R15) */
|
u32int R[16]; /* general purpose registers / PC (R15) */
|
||||||
u32int CPSR; /* status register */
|
u32int CPSR; /* status register */
|
||||||
|
|
||||||
|
@ -66,7 +69,6 @@ struct Segment {
|
||||||
Ref;
|
Ref;
|
||||||
int flags;
|
int flags;
|
||||||
RWLock rw; /* lock for SEGFLLOCK segments */
|
RWLock rw; /* lock for SEGFLLOCK segments */
|
||||||
Lock lock; /* atomic accesses */
|
|
||||||
u32int start, size;
|
u32int start, size;
|
||||||
void *data;
|
void *data;
|
||||||
Ref *dref;
|
Ref *dref;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue