diff --git a/sys/src/libc/arm/atom.s b/sys/src/libc/arm/atom.s index b59a89d90..a2aeef5d7 100644 --- a/sys/src/libc/arm/atom.s +++ b/sys/src/libc/arm/atom.s @@ -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) diff --git a/sys/src/libc/arm/cas.s b/sys/src/libc/arm/cas.s deleted file mode 100644 index 7bb3a05f7..000000000 --- a/sys/src/libc/arm/cas.s +++ /dev/null @@ -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 diff --git a/sys/src/libc/arm/lock.c b/sys/src/libc/arm/lock.c new file mode 100644 index 000000000..9cbbbf016 --- /dev/null +++ b/sys/src/libc/arm/lock.c @@ -0,0 +1,89 @@ +#include +#include + +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); +} diff --git a/sys/src/libc/arm/mkfile b/sys/src/libc/arm/mkfile index 14f81e1b8..b9226f618 100644 --- a/sys/src/libc/arm/mkfile +++ b/sys/src/libc/arm/mkfile @@ -23,6 +23,7 @@ CFILES=\ cycles.c\ notejmp.c\ vlrt.c\ + lock.c\ HFILES=/sys/include/libc.h diff --git a/sys/src/libc/arm/tas.s b/sys/src/libc/arm/tas.s index 6c34f5227..03a4e65bd 100644 --- a/sys/src/libc/arm/tas.s +++ b/sys/src/libc/arm/tas.s @@ -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