summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/ap/386
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-09-21 19:55:52 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-09-21 19:55:52 +0200
commitf811708ffcb776be52a81637224c06b700177566 (patch)
tree05a9632fef0f4e5ad835c2e6d426631e485e90d1 /sys/src/ape/lib/ap/386
parent3d05e77ca1f743e5b4091c6bfe311460175ed9ae (diff)
ape: change tas/sleep locks to cas/semacquire/semrelease locks (from sources)
Diffstat (limited to 'sys/src/ape/lib/ap/386')
-rwxr-xr-xsys/src/ape/lib/ap/386/atom.s121
-rw-r--r--sys/src/ape/lib/ap/386/lock.c37
-rw-r--r--sys/src/ape/lib/ap/386/mkfile1
3 files changed, 145 insertions, 14 deletions
diff --git a/sys/src/ape/lib/ap/386/atom.s b/sys/src/ape/lib/ap/386/atom.s
new file mode 100755
index 000000000..5f51daf81
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/atom.s
@@ -0,0 +1,121 @@
+TEXT ainc(SB), 1, $-4 /* int ainc(int*); */
+ MOVL arg+0(FP), BX
+ MOVL $1, AX
+ LOCK; BYTE $0x0f; BYTE $0xc1; BYTE $0x03/* XADDL AX, (BX) */
+ ADDL $1, AX /* overflow if -ve or 0 */
+ RET
+
+TEXT adec(SB), 1, $-4 /* int adec(int*); */
+ MOVL arg+0(FP), BX
+ MOVL $-1, AX
+ LOCK; BYTE $0x0f; BYTE $0xc1; BYTE $0x03/* XADDL AX, (BX) */
+ SUBL $1, AX /* underflow if -ve */
+ RET
+
+/*
+ * 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);
+ */
+
+/*
+ * CMPXCHG (CX), DX: 0000 1111 1011 000w oorr rmmm,
+ * mmm = CX = 001; rrr = DX = 010
+ */
+
+#define CMPXCHG BYTE $0x0F; BYTE $0xB1; BYTE $0x11
+
+TEXT cas32+0(SB),0,$0
+TEXT cas+0(SB),0,$0
+TEXT casp+0(SB),0,$0
+TEXT casl+0(SB),0,$0
+ MOVL p+0(FP), CX
+ MOVL ov+4(FP), AX
+ MOVL nv+8(FP), DX
+ LOCK
+ CMPXCHG
+ JNE fail
+ MOVL $1,AX
+ RET
+fail:
+ MOVL $0,AX
+ RET
+
+/*
+ * int cas64(u64int *p, u64int ov, u64int nv);
+ */
+
+/*
+ * CMPXCHG64 (DI): 0000 1111 1100 0111 0000 1110,
+ */
+
+#define CMPXCHG64 BYTE $0x0F; BYTE $0xC7; BYTE $0x0F
+
+TEXT cas64+0(SB),0,$0
+ MOVL p+0(FP), DI
+ MOVL ov+0x4(FP), AX
+ MOVL ov+0x8(FP), DX
+ MOVL nv+0xc(FP), BX
+ MOVL nv+0x10(FP), CX
+ LOCK
+ CMPXCHG64
+ JNE fail
+ MOVL $1,AX
+ RET
+
+/*
+ * Versions of compare-and-swap that return the old value
+ * (i.e., the value of *p at the time of the operation
+ * xcas(p, o, n) == o
+ * yields the same value as
+ * cas(p, o, n)
+ * xcas can be used in constructs like
+ * for(o = *p; (oo = xcas(p, o, o+1)) != o; o = oo)
+ * ;
+ * to avoid the extra dereference of *p (the example is a silly
+ * way to increment *p atomically)
+ *
+ * u32int xcas32(u32int *p, u32int ov, u32int nv);
+ * u64int xcas64(u64int *p, u64int ov, u64int nv);
+ * int xcas(int *p, int ov, int nv);
+ * void* xcasp(void **p, void *ov, void *nv);
+ * ulong xcasl(ulong *p, ulong ov, ulong nv);
+ */
+
+TEXT xcas32+0(SB),0,$0
+TEXT xcas+0(SB),0,$0
+TEXT xcasp+0(SB),0,$0
+TEXT xcasl+0(SB),0,$0
+ MOVL p+0(FP), CX
+ MOVL ov+4(FP), AX /* accumulator */
+ MOVL nv+8(FP), DX
+ LOCK
+ CMPXCHG
+ RET
+
+/*
+ * The CMPXCHG8B instruction also requires three operands:
+ * a 64-bit value in EDX:EAX, a 64-bit value in ECX:EBX,
+ * and a destination operand in memory. The instruction compar
+ * es the 64-bit value in the EDX:EAX registers with the
+ * destination operand. If they are equal, the 64-bit value
+ * in the ECX:EBX register is stored in the destination
+ * operand. If the EDX:EAX register and the destination ar
+ * e not equal, the destination is loaded in the EDX:EAX
+ * register. The CMPXCHG8B instruction can be combined with
+ * the LOCK prefix to perform the operation atomically
+ */
+
+TEXT xcas64+0(SB),0,$0
+ MOVL p+4(FP), DI
+ MOVL ov+0x8(FP), AX
+ MOVL ov+0xc(FP), DX
+ MOVL nv+0x10(FP), BX
+ MOVL nv+0x14(FP), CX
+ LOCK
+ CMPXCHG64
+ MOVL .ret+0x0(FP),CX /* pointer to return value */
+ MOVL AX,0x0(CX)
+ MOVL DX,0x4(CX)
+ RET
diff --git a/sys/src/ape/lib/ap/386/lock.c b/sys/src/ape/lib/ap/386/lock.c
index 91c0ba233..65a65df7b 100644
--- a/sys/src/ape/lib/ap/386/lock.c
+++ b/sys/src/ape/lib/ap/386/lock.c
@@ -1,26 +1,35 @@
-#define _LOCK_EXTENSION
+#include "../plan9/lib.h"
#include "../plan9/sys9.h"
+#define _LOCK_EXTENSION
#include <lock.h>
-int tas(int*);
-
void
-lock(Lock *lk)
+lock(Lock *l)
{
- while(tas(&lk->val))
- _SLEEP(0);
+ if(ainc(&l->key) == 1)
+ return; /* changed from 0 -> 1: we hold lock */
+ /* otherwise wait in kernel */
+ while(_SEMACQUIRE(&l->sem, 1) < 0){
+ /* interrupted; try again */
+ }
}
-int
-canlock(Lock *lk)
+void
+unlock(Lock *l)
{
- if(tas(&lk->val))
- return 0;
- return 1;
+ if(adec(&l->key) == 0)
+ return; /* changed from 1 -> 0: no contention */
+ _SEMRELEASE(&l->sem, 1);
}
-void
-unlock(Lock *lk)
+int
+canlock(Lock *l)
{
- lk->val = 0;
+ if(ainc(&l->key) == 1)
+ return 1; /* changed from 0 -> 1: success */
+ /* Undo increment (but don't miss wakeup) */
+ if(adec(&l->key) == 0)
+ return 0; /* changed from 1 -> 0: no contention */
+ _SEMRELEASE(&l->sem, 1);
+ return 0;
}
diff --git a/sys/src/ape/lib/ap/386/mkfile b/sys/src/ape/lib/ap/386/mkfile
index e19a4b852..680c7b4e4 100644
--- a/sys/src/ape/lib/ap/386/mkfile
+++ b/sys/src/ape/lib/ap/386/mkfile
@@ -2,6 +2,7 @@ APE=/sys/src/ape
<$APE/config
LIB=/$objtype/lib/ape/libap.a
OFILES=\
+ atom.$O\
cycles.$O\
lock.$O\
main9.$O\