libc/arm: implement _tas() with LDREX/STREX, execute memory barrier on smp systems (zynq)
This commit is contained in:
parent
5458506881
commit
6506147066
5 changed files with 127 additions and 64 deletions
|
@ -1,58 +1,50 @@
|
|||
#define CLREX WORD $0xf57ff01f
|
||||
#define LDREX(a,r) WORD $(0xe<<28|0x01900f9f | (a)<<16 | (r)<<12)
|
||||
/* `The order of operands is from left to right in dataflow order' - asm man */
|
||||
#define STREX(v,a,r) WORD $(0xe<<28|0x01800f90 | (a)<<16 | (r)<<12 | (v)<<0)
|
||||
|
||||
/*
|
||||
* int cas(ulong *p, ulong ov, ulong nv);
|
||||
* int cas32(u32int *p, u32int ov, u32int nv);
|
||||
* int cas(uint *p, int ov, int nv);
|
||||
* int casp(void **p, void *ov, void *nv);
|
||||
* int casl(ulong *p, ulong ov, ulong nv);
|
||||
*/
|
||||
|
||||
TEXT cas+0(SB),0,$0 /* r0 holds p */
|
||||
TEXT casp+0(SB),0,$0 /* r0 holds p */
|
||||
TEXT cas32(SB), 1, $-4
|
||||
TEXT cas(SB), 1, $-4
|
||||
TEXT casp(SB), 1, $-4
|
||||
TEXT casl(SB), 1, $-4
|
||||
MOVW ov+4(FP), R1
|
||||
MOVW nv+8(FP), R2
|
||||
spincas:
|
||||
LDREX(0,3) /* LDREX 0(R0),R3 */
|
||||
LDREX (R0), R3
|
||||
CMP.S R3, R1
|
||||
BNE fail
|
||||
STREX(2,0,4) /* STREX 0(R0),R2,R4 */
|
||||
STREX R2, (R0), R4
|
||||
CMP.S $0, R4
|
||||
BNE spincas
|
||||
MOVW $1, R0
|
||||
RET
|
||||
MOVW _barrier(SB), R5
|
||||
B (R5)
|
||||
fail:
|
||||
CLREX
|
||||
MOVW $0, R0
|
||||
RET
|
||||
|
||||
TEXT _xinc(SB), $0 /* void _xinc(long *); */
|
||||
TEXT ainc(SB), $0 /* long ainc(long *); */
|
||||
TEXT _xinc(SB), 1, $-4 /* void _xinc(long *); */
|
||||
TEXT ainc(SB), 1, $-4 /* long ainc(long *); */
|
||||
spinainc:
|
||||
LDREX(0,3) /* LDREX 0(R0),R3 */
|
||||
LDREX (R0), R3
|
||||
ADD $1,R3
|
||||
STREX(3,0,4) /* STREX 0(R0),R3,R4 */
|
||||
STREX R3, (R0), R4
|
||||
CMP.S $0, R4
|
||||
BNE spinainc
|
||||
MOVW R3, R0
|
||||
RET
|
||||
MOVW _barrier(SB), R5
|
||||
B (R5)
|
||||
|
||||
TEXT _xdec(SB), $0 /* long _xdec(long *); */
|
||||
TEXT adec(SB), $0 /* long adec(long *); */
|
||||
TEXT _xdec(SB), 1, $-4 /* long _xdec(long *); */
|
||||
TEXT adec(SB), 1, $-4 /* long adec(long *); */
|
||||
spinadec:
|
||||
LDREX(0,3) /* LDREX 0(R0),R3 */
|
||||
LDREX (R0), R3
|
||||
SUB $1,R3
|
||||
STREX(3,0,4) /* STREX 0(R0),R3,R4 */
|
||||
STREX R3, (R0), R4
|
||||
CMP.S $0, R4
|
||||
BNE spinadec
|
||||
MOVW R3, R0
|
||||
RET
|
||||
|
||||
TEXT loadlinked(SB), $0 /* long loadlinked(long *); */
|
||||
LDREX(0,0) /* LDREX 0(R0),R0 */
|
||||
RET
|
||||
|
||||
TEXT storecond(SB), $0 /* int storecond(long *, long); */
|
||||
MOVW ov+4(FP), R3
|
||||
STREX(3,0,0) /* STREX 0(R0),R3,R0 */
|
||||
RSB $1, R0
|
||||
RET
|
||||
MOVW _barrier(SB), R5
|
||||
B (R5)
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
/*
|
||||
* int swp(int r, int *p);
|
||||
* uchar swpb(uchar r, uchar *p);
|
||||
*
|
||||
* int cas(uintptr *p, uintptr ov, uintptr nv);
|
||||
*/
|
||||
|
||||
#define LDREX(a,r) WORD $(0xe<<28|0x01900f9f | (a)<<16 | (r)<<12)
|
||||
#define STREX(a,v,r) WORD $(0xe<<28|0x01800f90 | (a)<<16 | (r)<<12 | (v)<<0)
|
||||
|
||||
TEXT cas+0(SB),0,$12 /* r0 holds p */
|
||||
MOVW ov+4(FP), R1
|
||||
MOVW nv+8(FP), R2
|
||||
spin:
|
||||
/* LDREX 0(R0),R3 */
|
||||
LDREX(0,3)
|
||||
CMP.S R3, R1
|
||||
BNE fail
|
||||
/* STREX 0(R0),R2,R4 */
|
||||
STREX(0,2,4)
|
||||
CMP.S $0, R4
|
||||
BNE spin
|
||||
MOVW $1, R0
|
||||
RET
|
||||
fail:
|
||||
MOVW $0, R0
|
||||
RET
|
89
sys/src/libc/arm/lock.c
Normal file
89
sys/src/libc/arm/lock.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static long lockinit(long);
|
||||
|
||||
/*
|
||||
* barrier is called from atom.s and tas.s assembly
|
||||
* to execute memory barrier.
|
||||
*/
|
||||
long (*_barrier)(long) = lockinit;
|
||||
|
||||
static int
|
||||
cpus(void)
|
||||
{
|
||||
char buf[256], *p;
|
||||
int f, n;
|
||||
|
||||
f = open("#c/sysstat", OREAD);
|
||||
if(f < 0)
|
||||
return -1;
|
||||
n = read(f, buf, sizeof(buf)-1);
|
||||
close(f);
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
buf[n] = '\0';
|
||||
n = 0;
|
||||
p = buf;
|
||||
while(*p != '\0'){
|
||||
if(*p == '\n')
|
||||
n++;
|
||||
p++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
long _dmb(long);
|
||||
|
||||
static long
|
||||
_nop(long r0)
|
||||
{
|
||||
return r0;
|
||||
}
|
||||
|
||||
static long
|
||||
lockinit(long r0)
|
||||
{
|
||||
if(cpus() > 1)
|
||||
_barrier = _dmb;
|
||||
else
|
||||
_barrier = _nop;
|
||||
return (*_barrier)(r0);
|
||||
}
|
||||
|
||||
void
|
||||
lock(Lock *lk)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* once fast */
|
||||
if(!_tas(&lk->val))
|
||||
return;
|
||||
/* a thousand times pretty fast */
|
||||
for(i=0; i<1000; i++){
|
||||
if(!_tas(&lk->val))
|
||||
return;
|
||||
sleep(0);
|
||||
}
|
||||
/* now nice and slow */
|
||||
for(i=0; i<1000; i++){
|
||||
if(!_tas(&lk->val))
|
||||
return;
|
||||
sleep(100);
|
||||
}
|
||||
/* take your time */
|
||||
while(_tas(&lk->val))
|
||||
sleep(1000);
|
||||
}
|
||||
|
||||
int
|
||||
canlock(Lock *lk)
|
||||
{
|
||||
return _tas(&lk->val) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
unlock(Lock *lk)
|
||||
{
|
||||
lk->val = (*_barrier)(0);
|
||||
}
|
|
@ -23,6 +23,7 @@ CFILES=\
|
|||
cycles.c\
|
||||
notejmp.c\
|
||||
vlrt.c\
|
||||
lock.c\
|
||||
|
||||
HFILES=/sys/include/libc.h
|
||||
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
TEXT _tas(SB), 1, $-4
|
||||
MOVW R0,R1
|
||||
MOVW $1,R0
|
||||
SWPW R0,(R1) /* fix: deprecated in armv7 */
|
||||
TEXT _tas(SB), 1, $-4
|
||||
MOVW $1, R2
|
||||
_tas1:
|
||||
LDREX (R0), R1
|
||||
STREX R2, (R0), R3
|
||||
CMP.S $0, R3
|
||||
BNE _tas1
|
||||
MOVW R1, R0
|
||||
MOVW _barrier(SB), R4
|
||||
B (R4)
|
||||
|
||||
TEXT _dmb(SB), 1, $-4
|
||||
WORD $0xf57ff05f
|
||||
RET
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue