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 cas32(SB), 1, $-4
|
||||||
TEXT cas+0(SB),0,$0 /* r0 holds p */
|
TEXT cas(SB), 1, $-4
|
||||||
TEXT casp+0(SB),0,$0 /* r0 holds p */
|
TEXT casp(SB), 1, $-4
|
||||||
|
TEXT casl(SB), 1, $-4
|
||||||
MOVW ov+4(FP), R1
|
MOVW ov+4(FP), R1
|
||||||
MOVW nv+8(FP), R2
|
MOVW nv+8(FP), R2
|
||||||
spincas:
|
spincas:
|
||||||
LDREX(0,3) /* LDREX 0(R0),R3 */
|
LDREX (R0), R3
|
||||||
CMP.S R3, R1
|
CMP.S R3, R1
|
||||||
BNE fail
|
BNE fail
|
||||||
STREX(2,0,4) /* STREX 0(R0),R2,R4 */
|
STREX R2, (R0), R4
|
||||||
CMP.S $0, R4
|
CMP.S $0, R4
|
||||||
BNE spincas
|
BNE spincas
|
||||||
MOVW $1, R0
|
MOVW $1, R0
|
||||||
RET
|
MOVW _barrier(SB), R5
|
||||||
|
B (R5)
|
||||||
fail:
|
fail:
|
||||||
CLREX
|
CLREX
|
||||||
MOVW $0, R0
|
MOVW $0, R0
|
||||||
RET
|
RET
|
||||||
|
|
||||||
TEXT _xinc(SB), $0 /* void _xinc(long *); */
|
TEXT _xinc(SB), 1, $-4 /* void _xinc(long *); */
|
||||||
TEXT ainc(SB), $0 /* long ainc(long *); */
|
TEXT ainc(SB), 1, $-4 /* long ainc(long *); */
|
||||||
spinainc:
|
spinainc:
|
||||||
LDREX(0,3) /* LDREX 0(R0),R3 */
|
LDREX (R0), R3
|
||||||
ADD $1,R3
|
ADD $1,R3
|
||||||
STREX(3,0,4) /* STREX 0(R0),R3,R4 */
|
STREX R3, (R0), R4
|
||||||
CMP.S $0, R4
|
CMP.S $0, R4
|
||||||
BNE spinainc
|
BNE spinainc
|
||||||
MOVW R3, R0
|
MOVW R3, R0
|
||||||
RET
|
MOVW _barrier(SB), R5
|
||||||
|
B (R5)
|
||||||
|
|
||||||
TEXT _xdec(SB), $0 /* long _xdec(long *); */
|
TEXT _xdec(SB), 1, $-4 /* long _xdec(long *); */
|
||||||
TEXT adec(SB), $0 /* long adec(long *); */
|
TEXT adec(SB), 1, $-4 /* long adec(long *); */
|
||||||
spinadec:
|
spinadec:
|
||||||
LDREX(0,3) /* LDREX 0(R0),R3 */
|
LDREX (R0), R3
|
||||||
SUB $1,R3
|
SUB $1,R3
|
||||||
STREX(3,0,4) /* STREX 0(R0),R3,R4 */
|
STREX R3, (R0), R4
|
||||||
CMP.S $0, R4
|
CMP.S $0, R4
|
||||||
BNE spinadec
|
BNE spinadec
|
||||||
MOVW R3, R0
|
MOVW R3, R0
|
||||||
RET
|
MOVW _barrier(SB), R5
|
||||||
|
B (R5)
|
||||||
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
|
|
||||||
|
|
|
@ -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\
|
cycles.c\
|
||||||
notejmp.c\
|
notejmp.c\
|
||||||
vlrt.c\
|
vlrt.c\
|
||||||
|
lock.c\
|
||||||
|
|
||||||
HFILES=/sys/include/libc.h
|
HFILES=/sys/include/libc.h
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
TEXT _tas(SB), 1, $-4
|
TEXT _tas(SB), 1, $-4
|
||||||
MOVW R0,R1
|
MOVW $1, R2
|
||||||
MOVW $1,R0
|
_tas1:
|
||||||
SWPW R0,(R1) /* fix: deprecated in armv7 */
|
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
|
RET
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue