shithub: riscv

Download patch

ref: cd92790c50433ee99fc3a3b3a95792e1daf2aed1
parent: 65061470665b3f91f01d23bad6a54704e8aa5851
author: cinap_lenrek <[email protected]>
date: Tue Jul 7 15:53:26 EDT 2015

ape: port libc smp tas() for arm

--- a/sys/src/ape/lib/ap/arm/lock.c
+++ b/sys/src/ape/lib/ap/arm/lock.c
@@ -2,25 +2,91 @@
 #include "../plan9/sys9.h"
 #include <lock.h>
 
-int	tas(int*);
+int tas(int*);	/* tas.s */
 
+static long lockinit(long);
+
+/*
+ * barrier is called from 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", 0);
+	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)
 {
-	while(tas(&lk->val))
+	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)
 {
-	if(tas(&lk->val))
-		return 0;
-	return 1;
+	return tas(&lk->val) == 0;
 }
 
 void
 unlock(Lock *lk)
 {
-	lk->val = 0;
+	lk->val = (*_barrier)(0);
 }
--- a/sys/src/ape/lib/ap/arm/tas.s
+++ b/sys/src/ape/lib/ap/arm/tas.s
@@ -1,5 +1,14 @@
-TEXT	tas(SB), $-4
-	MOVW	R0,R1
-	MOVW	$1,R0
-	SWPW	R0,(R1)
+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