ref: 65061470665b3f91f01d23bad6a54704e8aa5851
parent: 5458506881d9ff73287df354d3be75b35d339f24
author: cinap_lenrek <[email protected]>
date: Tue Jul 7 15:24:10 EDT 2015
libc/arm: implement _tas() with LDREX/STREX, execute memory barrier on smp systems (zynq)
--- 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)
--- a/sys/src/libc/arm/cas.s
+++ /dev/null
@@ -1,28 +1,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
--- /dev/null
+++ b/sys/src/libc/arm/lock.c
@@ -1,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);
+}
--- a/sys/src/libc/arm/mkfile
+++ b/sys/src/libc/arm/mkfile
@@ -23,6 +23,7 @@
cycles.c\
notejmp.c\
vlrt.c\
+ lock.c\
HFILES=/sys/include/libc.h
--- 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