diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-21 19:55:52 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-21 19:55:52 +0200 |
commit | f811708ffcb776be52a81637224c06b700177566 (patch) | |
tree | 05a9632fef0f4e5ad835c2e6d426631e485e90d1 /sys/src/ape/lib/ap/386 | |
parent | 3d05e77ca1f743e5b4091c6bfe311460175ed9ae (diff) |
ape: change tas/sleep locks to cas/semacquire/semrelease locks (from sources)
Diffstat (limited to 'sys/src/ape/lib/ap/386')
-rwxr-xr-x | sys/src/ape/lib/ap/386/atom.s | 121 | ||||
-rw-r--r-- | sys/src/ape/lib/ap/386/lock.c | 37 | ||||
-rw-r--r-- | sys/src/ape/lib/ap/386/mkfile | 1 |
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\ |