reverting semaphore lock changes from sources (r41ccd6d221da, rb28756e5ba29)

semaphore locks have much higher overhead than initially presented
in the "Semaphores in Plan9" paper. until the reason for it has been
found out i will revert the changes.
This commit is contained in:
cinap_lenrek 2013-09-26 22:24:31 +02:00
parent b4cdfc6c55
commit cdc2c30e99
39 changed files with 521 additions and 611 deletions

View file

@ -10,8 +10,7 @@
typedef struct
{
long key;
long sem;
int val;
} Lock;
#ifdef __cplusplus

View file

@ -409,19 +409,12 @@ enum {
}; /* what */
extern void prof(void (*fn)(void*), void *arg, int entries, int what);
/*
* atomic
*/
extern long ainc(long*);
extern long adec(long*);
/*
* synchronization
*/
typedef
struct Lock {
long key;
long sem;
int val;
} Lock;
extern int _tas(int*);
@ -708,6 +701,9 @@ extern char* sysname(void);
extern void werrstr(char*, ...);
#pragma varargck argpos werrstr 1
extern long ainc(long*);
extern long adec(long*);
extern char *argv0;
#define ARGBEGIN for((argv0||(argv0=*argv)),argv++,argc--;\
argv[0] && argv[0][0]=='-' && argv[0][1];\

View file

@ -1,121 +0,0 @@
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

View file

@ -1,35 +1,26 @@
#include "../plan9/lib.h"
#include "../plan9/sys9.h"
#define _LOCK_EXTENSION
#include "../plan9/sys9.h"
#include <lock.h>
void
lock(Lock *l)
{
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 tas(int*);
void
unlock(Lock *l)
lock(Lock *lk)
{
if(adec(&l->key) == 0)
return; /* changed from 1 -> 0: no contention */
_SEMRELEASE(&l->sem, 1);
while(tas(&lk->val))
_SLEEP(0);
}
int
canlock(Lock *l)
canlock(Lock *lk)
{
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;
if(tas(&lk->val))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->val = 0;
}

View file

@ -2,7 +2,6 @@ APE=/sys/src/ape
<$APE/config
LIB=/$objtype/lib/ape/libap.a
OFILES=\
atom.$O\
cycles.$O\
lock.$O\
main9.$O\

View file

@ -2,17 +2,19 @@
#include "../plan9/sys9.h"
#include <lock.h>
int tas(int*);
void
lock(Lock *lk)
{
while(tas((int*)&lk->key))
while(tas(&lk->val))
_SLEEP(0);
}
int
canlock(Lock *lk)
{
if(tas((int*)&lk->key))
if(tas(&lk->val))
return 0;
return 1;
}
@ -20,5 +22,5 @@ canlock(Lock *lk)
void
unlock(Lock *lk)
{
lk->key = 0;
lk->val = 0;
}

View file

@ -2,17 +2,19 @@
#include "../plan9/sys9.h"
#include <lock.h>
int tas(int*);
void
lock(Lock *lk)
{
while(tas((int*)&lk->key))
while(tas(&lk->val))
_SLEEP(0);
}
int
canlock(Lock *lk)
{
if(tas((int*)&lk->key))
if(tas(&lk->val))
return 0;
return 1;
}
@ -20,5 +22,5 @@ canlock(Lock *lk)
void
unlock(Lock *lk)
{
lk->key = 0;
lk->val = 0;
}

View file

@ -1,58 +0,0 @@
#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);
*/
TEXT cas+0(SB),0,$0 /* r0 holds p */
TEXT casp+0(SB),0,$0 /* r0 holds p */
MOVW ov+4(FP), R1
MOVW nv+8(FP), R2
spincas:
LDREX(0,3) /* LDREX 0(R0),R3 */
CMP.S R3, R1
BNE fail
STREX(2,0,4) /* STREX 0(R0),R2,R4 */
CMP.S $0, R4
BNE spincas
MOVW $1, R0
RET
fail:
CLREX
MOVW $0, R0
RET
TEXT _xinc(SB), $0 /* void _xinc(long *); */
TEXT ainc(SB), $0 /* long ainc(long *); */
spinainc:
LDREX(0,3) /* LDREX 0(R0),R3 */
ADD $1,R3
STREX(3,0,4) /* STREX 0(R0),R3,R4 */
CMP.S $0, R4
BNE spinainc
MOVW R3, R0
RET
TEXT _xdec(SB), $0 /* long _xdec(long *); */
TEXT adec(SB), $0 /* long adec(long *); */
spinadec:
LDREX(0,3) /* LDREX 0(R0),R3 */
SUB $1,R3
STREX(3,0,4) /* STREX 0(R0),R3,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

View file

@ -1,35 +1,26 @@
#include "../plan9/lib.h"
#include "../plan9/sys9.h"
#define _LOCK_EXTENSION
#include "../plan9/sys9.h"
#include <lock.h>
void
lock(Lock *l)
{
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 tas(int*);
void
unlock(Lock *l)
lock(Lock *lk)
{
if(adec(&l->key) == 0)
return; /* changed from 1 -> 0: no contention */
_SEMRELEASE(&l->sem, 1);
while(tas(&lk->val))
_SLEEP(0);
}
int
canlock(Lock *l)
canlock(Lock *lk)
{
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;
if(tas(&lk->val))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->val = 0;
}

View file

@ -2,7 +2,6 @@ APE=/sys/src/ape
<$APE/config
LIB=/$objtype/lib/ape/libap.a
OFILES=\
atom.$O\
cycles.$O\
div.$O\
getfcr.$O\

View file

@ -1,52 +0,0 @@
/*
* R4000 user-level atomic operations
*/
#define LL(base, rt) WORD $((060<<26)|((base)<<21)|((rt)<<16))
#define SC(base, rt) WORD $((070<<26)|((base)<<21)|((rt)<<16))
#define NOOP WORD $0x27
TEXT ainc(SB), 1, $-4 /* long ainc(long *); */
TEXT _xinc(SB), 1, $-4 /* void _xinc(long *); */
MOVW R1, R2 /* address of counter */
loop: MOVW $1, R3
LL(2, 1)
NOOP
ADDU R1, R3
MOVW R3, R1 /* return new value */
SC(2, 3)
NOOP
BEQ R3,loop
RET
TEXT adec(SB), 1, $-4 /* long adec(long*); */
TEXT _xdec(SB), 1, $-4 /* long _xdec(long *); */
MOVW R1, R2 /* address of counter */
loop1: MOVW $-1, R3
LL(2, 1)
NOOP
ADDU R1, R3
MOVW R3, R1 /* return new value */
SC(2, 3)
NOOP
BEQ R3,loop1
RET
/*
* int cas(uint* p, int ov, int nv);
*/
TEXT cas(SB), 1, $-4
MOVW ov+4(FP), R2
MOVW nv+8(FP), R3
spincas:
LL(1, 4) /* R4 = *R1 */
NOOP
BNE R2, R4, fail
SC(1, 3) /* *R1 = R3 */
NOOP
BEQ R3, spincas /* R3 == 0 means store failed */
MOVW $1, R1
RET
fail:
MOVW $0, R1
RET

View file

@ -1,35 +1,171 @@
#include "../plan9/lib.h"
#include "../plan9/sys9.h"
#define _LOCK_EXTENSION
#include <stdlib.h>
#include <string.h>
#include "../plan9/sys9.h"
#include <lock.h>
void
lock(Lock *l)
enum
{
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 */
Pagesize = 4096,
Semperpg = Pagesize/(16*sizeof(unsigned int)),
Lockaddr = 0x60000000,
POWER = 0x320,
MAGNUM = 0x330,
MAGNUMII = 0x340,
R4K = 0x500,
};
static int arch;
extern int C_3ktas(int*);
extern int C_4ktas(int*);
extern int C_fcr0(void);
static void
lockinit(void)
{
int n;
if(arch != 0)
return; /* allow multiple calls */
arch = C_fcr0();
switch(arch) {
case POWER:
if(_SEGATTACH(0, "lock", (void*)Lockaddr, Pagesize) == (void*)-1) {
arch = MAGNUM;
break;
}
memset((void*)Lockaddr, 0, Pagesize);
break;
case MAGNUM:
case MAGNUMII:
case R4K:
break;
default:
abort();
}
}
void
unlock(Lock *l)
lock(Lock *lk)
{
if(adec(&l->key) == 0)
return; /* changed from 1 -> 0: no contention */
_SEMRELEASE(&l->sem, 1);
int *hwsem;
int hash;
retry:
switch(arch) {
case 0:
lockinit();
goto retry;
case MAGNUM:
case MAGNUMII:
while(C_3ktas(&lk->val))
_SLEEP(0);
return;
case R4K:
for(;;){
while(lk->val)
;
if(C_4ktas(&lk->val) == 0)
return;
}
break;
case POWER:
/* Use low order lock bits to generate hash */
hash = ((int)lk/sizeof(int)) & (Semperpg-1);
hwsem = (int*)Lockaddr+hash;
for(;;) {
if((*hwsem & 1) == 0) {
if(lk->val)
*hwsem = 0;
else {
lk->val = 1;
*hwsem = 0;
return;
}
}
while(lk->val)
;
}
}
}
int
canlock(Lock *l)
canlock(Lock *lk)
{
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;
int *hwsem;
int hash;
retry:
switch(arch) {
case 0:
lockinit();
goto retry;
case MAGNUM:
case MAGNUMII:
if(C_3ktas(&lk->val))
return 0;
return 1;
case R4K:
if(C_4ktas(&lk->val))
return 0;
return 1;
case POWER:
/* Use low order lock bits to generate hash */
hash = ((int)lk/sizeof(int)) & (Semperpg-1);
hwsem = (int*)Lockaddr+hash;
if((*hwsem & 1) == 0) {
if(lk->val)
*hwsem = 0;
else {
lk->val = 1;
*hwsem = 0;
return 1;
}
}
return 0;
}
}
void
unlock(Lock *lk)
{
lk->val = 0;
}
int
tas(int *p)
{
int *hwsem;
int hash;
retry:
switch(arch) {
case 0:
lockinit();
goto retry;
case MAGNUM:
case MAGNUMII:
return C_3ktas(p);
case R4K:
return C_4ktas(p);
case POWER:
/* Use low order lock bits to generate hash */
hash = ((int)p/sizeof(int)) & (Semperpg-1);
hwsem = (int*)Lockaddr+hash;
if((*hwsem & 1) == 0) {
if(*p)
*hwsem = 0;
else {
*p = 1;
*hwsem = 0;
return 0;
}
}
return 1;
}
}

View file

@ -2,7 +2,6 @@ APE=/sys/src/ape
<$APE/config
LIB=/$objtype/lib/ape/libap.a
OFILES=\
atom.$O\
cycles.$O\
getfcr.$O\
lock.$O\

View file

@ -17,7 +17,6 @@ btas:
BLTZ R1, btas
RET
TEXT tas(SB),$0
TEXT C_4ktas(SB), $0
MOVW R1, R2 /* address of key */
tas1:

View file

@ -106,11 +106,8 @@ extern int _SEGDETACH(void*);
extern int _SEGFLUSH(void*, unsigned long);
extern int _SEGFREE(void*, unsigned long);
extern long long _SEEK(int, long long, int);
extern int _SEMACQUIRE(long*, int);
extern long _SEMRELEASE(long*, long);
extern int _SLEEP(long);
extern int _STAT(const char*, unsigned char*, int);
extern int _TSEMACQUIRE(long*, unsigned long);
extern Waitmsg* _WAIT(void);
extern long _WRITE(int, const void*, long);
extern int _WSTAT(const char*, unsigned char*, int);
@ -122,9 +119,3 @@ extern int __creat(char *, int);
extern int __link(char *, int);
extern int __stat(char *, struct stat *);
extern int __unlink(char *);
/*
* atomic
*/
extern long ainc(long*);
extern long adec(long*);

View file

@ -1,63 +0,0 @@
TEXT _xinc(SB),$0 /* void _xinc(long *); */
TEXT ainc(SB),$0 /* long ainc(long *); */
MOVW R3, R4
xincloop:
LWAR (R4), R3
ADD $1, R3
DCBT (R4) /* fix 405 errata cpu_210 */
STWCCC R3, (R4)
BNE xincloop
RETURN
TEXT _xdec(SB),$0 /* long _xdec(long *); */
TEXT adec(SB),$0 /* long adec(long *); */
MOVW R3, R4
xdecloop:
LWAR (R4), R3
ADD $-1, R3
DCBT (R4) /* fix 405 errata cpu_210 */
STWCCC R3, (R4)
BNE xdecloop
RETURN
TEXT loadlink(SB), $0
LWAR (R3), R3
RETURN
TEXT storecond(SB), $0
MOVW val+4(FP), R4
DCBT (R3) /* fix 405 errata cpu_210 */
STWCCC R4, (R3)
BNE storecondfail
MOVW $1, R3
RETURN
storecondfail:
MOVW $0, R3
RETURN
/*
* int cas(uint *p, int ov, int nv);
* int casp(void **p, void *ov, void *nv);
*/
TEXT cas+0(SB),0,$0
TEXT casp+0(SB),0,$0
MOVW ov+4(FP),R4
MOVW nv+8(FP),R8
LWAR (R3),R5
CMP R5,R4
BNE fail
DCBT (R3) /* fix 405 errata cpu_210 */
STWCCC R8,(R3)
BNE fail1
MOVW $1,R3
RETURN
fail:
DCBT (R3) /* fix 405 errata cpu_210 */
STWCCC R5,(R3) /* give up exclusive access */
fail1:
MOVW R0,R3
RETURN
END

View file

@ -3,33 +3,43 @@
#define _LOCK_EXTENSION
#include <lock.h>
void
lock(Lock *l)
{
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 tas(int*);
void
unlock(Lock *l)
lock(Lock *lk)
{
if(adec(&l->key) == 0)
return; /* changed from 1 -> 0: no contention */
_SEMRELEASE(&l->sem, 1);
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 *l)
canlock(Lock *lk)
{
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;
if(tas(&lk->val))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->val = 0;
}

View file

@ -2,7 +2,6 @@ APE=/sys/src/ape
<$APE/config
LIB=/$objtype/lib/ape/libap.a
OFILES=\
atom.$O\
cycles.$O\
getfcr.$O\
lock.$O\

View file

@ -2,17 +2,19 @@
#include "../plan9/sys9.h"
#include <lock.h>
int tas(int*);
void
lock(Lock *lk)
{
while(tas((int*)&lk->key))
while(tas(&lk->val))
_SLEEP(0);
}
int
canlock(Lock *lk)
{
if(tas((int*)&lk->key))
if(tas(&lk->val))
return 0;
return 1;
}
@ -20,5 +22,5 @@ canlock(Lock *lk)
void
unlock(Lock *lk)
{
lk->key = 0;
lk->val = 0;
}

View file

@ -24,6 +24,7 @@ SFILES=\
strlen.s\
CFILES=\
cycles.c\
notejmp.c\
vlrt.c\

View file

@ -1,41 +0,0 @@
#include <u.h>
#include <libc.h>
void
lock(Lock *lk)
{
int i;
/* once fast */
if(!_tas((int*)&lk->key))
return;
/* a thousand times pretty fast */
for(i=0; i<1000; i++){
if(!_tas((int*)&lk->key))
return;
sleep(0);
}
/* now nice and slow */
for(i=0; i<1000; i++){
if(!_tas((int*)&lk->key))
return;
sleep(100);
}
/* take your time */
while(_tas((int*)&lk->key))
sleep(1000);
}
int
canlock(Lock *lk)
{
if(_tas((int*)&lk->key))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->key = 0;
}

View file

@ -26,7 +26,7 @@ SFILES=\
vlop.s\
CFILES=\
lock.c\
cycles.c\
notejmp.c\
vlrt.c\

View file

@ -0,0 +1,7 @@
#include <u.h>
#include <libc.h>
void cycles(uvlong*u)
{
*u = 0LL;
}

View file

@ -1,41 +0,0 @@
#include <u.h>
#include <libc.h>
void
lock(Lock *lk)
{
int i;
/* once fast */
if(!_tas((int*)&lk->key))
return;
/* a thousand times pretty fast */
for(i=0; i<1000; i++){
if(!_tas((int*)&lk->key))
return;
sleep(0);
}
/* now nice and slow */
for(i=0; i<1000; i++){
if(!_tas((int*)&lk->key))
return;
sleep(100);
}
/* take your time */
while(_tas((int*)&lk->key))
sleep(1000);
}
int
canlock(Lock *lk)
{
if(_tas((int*)&lk->key))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->key = 0;
}

View file

@ -18,7 +18,7 @@ SFILES=\
CFILES=\
_seek.c\
lock.c\
cycles.c\
notejmp.c\
HFILES=/sys/include/libc.h

10
sys/src/libc/arm/cycles.c Normal file
View file

@ -0,0 +1,10 @@
#include <u.h>
#include <libc.h>
#pragma profile off
void
cycles(uvlong*u)
{
*u = 0LL;
}

View file

@ -20,6 +20,7 @@ SFILES=\
vlop.s\
CFILES=\
cycles.c\
notejmp.c\
vlrt.c\

View file

@ -12,8 +12,7 @@ TEXT _xinc(SB), 1, $-4 /* void _xinc(long *); */
loop: MOVW $1, R3
LL(2, 1)
NOOP
ADDU R1, R3
MOVW R3, R1 /* return new value */
ADD R1,R3,R3
SC(2, 3)
NOOP
BEQ R3,loop
@ -25,8 +24,8 @@ TEXT _xdec(SB), 1, $-4 /* long _xdec(long *); */
loop1: MOVW $-1, R3
LL(2, 1)
NOOP
ADDU R1, R3
MOVW R3, R1 /* return new value */
ADD R1,R3,R3
MOVW R3, R1
SC(2, 3)
NOOP
BEQ R3,loop1
@ -50,3 +49,9 @@ spincas:
fail:
MOVW $0, R1
RET
/* general-purpose abort */
_trap:
MOVD $0, R0
MOVD 0(R0), R0
RET

171
sys/src/libc/mips/lock.c Normal file
View file

@ -0,0 +1,171 @@
#include <u.h>
#include <libc.h>
enum
{
Pagesize = 4096,
Semperpg = Pagesize/(16*sizeof(uint)),
Lockaddr = 0x60000000,
POWER = 0x320,
MAGNUM = 0x330,
MAGNUMII = 0x340,
R4K = 0x500,
};
static int arch;
extern int C_3ktas(int*);
extern int C_4ktas(int*);
extern int C_fcr0(void);
static void
lockinit(void)
{
void *v;
if(arch != 0)
return; /* allow multiple calls */
arch = C_fcr0();
switch(arch) {
case POWER:
v = (void*)Lockaddr;
if(segattach(SG_CEXEC, "lock", v, Pagesize) == (void*)-1) {
arch = MAGNUM;
break;
}
memset(v, 0, Pagesize);
break;
case MAGNUM:
case MAGNUMII:
case R4K:
break;
default:
arch = R4K;
break;
}
}
void
lock(Lock *lk)
{
int *hwsem;
int hash;
retry:
switch(arch) {
case 0:
lockinit();
goto retry;
case MAGNUM:
case MAGNUMII:
while(C_3ktas(&lk->val))
sleep(0);
return;
case R4K:
for(;;){
while(lk->val)
;
if(C_4ktas(&lk->val) == 0)
return;
}
break;
case POWER:
/* Use low order lock bits to generate hash */
hash = ((int)lk/sizeof(int)) & (Semperpg-1);
hwsem = (int*)Lockaddr+hash;
for(;;) {
if((*hwsem & 1) == 0) {
if(lk->val)
*hwsem = 0;
else {
lk->val = 1;
*hwsem = 0;
return;
}
}
while(lk->val)
;
}
}
}
int
canlock(Lock *lk)
{
int *hwsem;
int hash;
retry:
switch(arch) {
case 0:
lockinit();
goto retry;
case MAGNUM:
case MAGNUMII:
if(C_3ktas(&lk->val))
return 0;
return 1;
case R4K:
if(C_4ktas(&lk->val))
return 0;
return 1;
case POWER:
/* Use low order lock bits to generate hash */
hash = ((int)lk/sizeof(int)) & (Semperpg-1);
hwsem = (int*)Lockaddr+hash;
if((*hwsem & 1) == 0) {
if(lk->val)
*hwsem = 0;
else {
lk->val = 1;
*hwsem = 0;
return 1;
}
}
break;
}
return 0;
}
void
unlock(Lock *lk)
{
lk->val = 0;
}
int
_tas(int *p)
{
int *hwsem;
int hash;
retry:
switch(arch) {
case 0:
lockinit();
goto retry;
case MAGNUM:
case MAGNUMII:
return C_3ktas(p);
case R4K:
return C_4ktas(p);
case POWER:
/* Use low order lock bits to generate hash */
hash = ((int)p/sizeof(int)) & (Semperpg-1);
hwsem = (int*)Lockaddr+hash;
if((*hwsem & 1) == 0) {
if(*p)
*hwsem = 0;
else {
*p = 1;
*hwsem = 0;
return 0;
}
}
break;
}
return 1;
}

View file

@ -23,6 +23,7 @@ SFILES=\
CFILES=\
cycles.c\
lock.c\
notejmp.c\
sqrt.c\
vlrt.c\

View file

@ -17,7 +17,6 @@ btas:
BLTZ R1, btas
RET
TEXT _tas(SB),$0
TEXT C_4ktas(SB), $0
MOVW R1, R2 /* address of key */
tas1:

View file

@ -37,7 +37,7 @@ update:V:
cd $i
mk $MKFLAGS update
}
update $UPDATEFLAGS /$objtype/lib/libc.a
update $UPDATEFLAGS /386/lib/libc.a
installall:V:
for(objtype in $CPUS) mk $MKFLAGS install

View file

@ -2,32 +2,40 @@
#include <libc.h>
void
lock(Lock *l)
lock(Lock *lk)
{
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 i;
void
unlock(Lock *l)
{
if(adec(&l->key) == 0)
return; /* changed from 1 -> 0: no contention */
semrelease(&l->sem, 1);
/* 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 *l)
canlock(Lock *lk)
{
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;
if(_tas(&lk->val))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->val = 0;
}

View file

@ -122,18 +122,16 @@ Profuser = 1;
Profkernel = 2;
Proftime = 3;
Profsample = 4;
sizeofLock = 8;
sizeofLock = 4;
aggr Lock
{
'D' 0 key;
'D' 4 sem;
'D' 0 val;
};
defn
Lock(addr) {
complex Lock addr;
print(" key ", addr.key, "\n");
print(" sem ", addr.sem, "\n");
print(" val ", addr.val, "\n");
};
sizeofQLp = 12;
@ -152,13 +150,13 @@ QLp(addr) {
print(" state ", addr.state, "\n");
};
sizeofQLock = 20;
sizeofQLock = 16;
aggr QLock
{
Lock 0 lock;
'D' 8 locked;
'A' QLp 12 $head;
'A' QLp 16 $tail;
'D' 4 locked;
'A' QLp 8 $head;
'A' QLp 12 $tail;
};
defn
@ -172,14 +170,14 @@ QLock(addr) {
print(" $tail ", addr.$tail\X, "\n");
};
sizeofRWLock = 24;
sizeofRWLock = 20;
aggr RWLock
{
Lock 0 lock;
'D' 8 readers;
'D' 12 writer;
'A' QLp 16 $head;
'A' QLp 20 $tail;
'D' 4 readers;
'D' 8 writer;
'A' QLp 12 $head;
'A' QLp 16 $tail;
};
defn
@ -440,12 +438,12 @@ Tos(addr) {
};
complex Tos _tos;
sizeofPrivate = 16;
sizeofPrivate = 12;
aggr Private
{
Lock 0 lk;
'D' 8 pid;
'D' 12 printfd;
'D' 4 pid;
'D' 8 printfd;
};
defn

View file

@ -19,7 +19,6 @@ CFILES=\
cleanname.c\
crypt.c\
ctype.c\
cycles.c\
encodefmt.c\
execl.c\
exp.c\

View file

@ -122,18 +122,16 @@ Profuser = 1;
Profkernel = 2;
Proftime = 3;
Profsample = 4;
sizeofLock = 8;
sizeofLock = 4;
aggr Lock
{
'D' 0 key;
'D' 4 sem;
'D' 0 val;
};
defn
Lock(addr) {
complex Lock addr;
print(" key ", addr.key, "\n");
print(" sem ", addr.sem, "\n");
print(" val ", addr.val, "\n");
};
sizeofQLp = 12;
@ -152,13 +150,13 @@ QLp(addr) {
print(" state ", addr.state, "\n");
};
sizeofQLock = 20;
sizeofQLock = 16;
aggr QLock
{
Lock 0 lock;
'D' 8 locked;
'A' QLp 12 $head;
'A' QLp 16 $tail;
'D' 4 locked;
'A' QLp 8 $head;
'A' QLp 12 $tail;
};
defn
@ -172,14 +170,14 @@ QLock(addr) {
print(" $tail ", addr.$tail\X, "\n");
};
sizeofRWLock = 24;
sizeofRWLock = 20;
aggr RWLock
{
Lock 0 lock;
'D' 8 readers;
'D' 12 writer;
'A' QLp 16 $head;
'A' QLp 20 $tail;
'D' 4 readers;
'D' 8 writer;
'A' QLp 12 $head;
'A' QLp 16 $tail;
};
defn
@ -506,20 +504,34 @@ MINBLOCKSIZE = 32;
complex Free checklist:t;
complex Free checklist:q;
complex Free checktree:t;
complex Free ltreewalk:t;
complex Free ltreewalk:f;
complex Free treeinsert:tree;
complex Free treeinsert:node;
complex Free treeinsert:loc;
complex Free treeinsert:repl;
complex Free treedelete:tree;
complex Free treedelete:node;
complex Free treedelete:loc;
complex Free treedelete:lsucc;
complex Free treedelete:succ;
complex Free treelookupgt:t;
complex Free treelookupgt:lastgood;
complex Free treesplay:t;
complex Free treesplay:N;
complex Free treesplay:l;
complex Free treesplay:r;
complex Free treesplay:y;
complex Free listadd:list;
complex Free listadd:node;
complex Free listdelete:list;
complex Free listdelete:node;
complex Pool pooladd:p;
complex Alloc pooladd:anode;
complex Free pooladd:lst;
complex Free pooladd:olst;
complex Free pooladd:node;
complex Free pooladd:root;
complex Free pooladd:parent;
complex Pool pooldel:p;
complex Free pooldel:node;
complex Free pooldel:root;
complex Free pooldel:lst;
complex Free pooldel:olst;
complex Free pooldel:parent;
complex Pool dsize2bsize:p;
complex Pool bsize2asize:p;
complex Pool blockmerge:pool;

View file

@ -1,41 +0,0 @@
#include <u.h>
#include <libc.h>
void
lock(Lock *lk)
{
int i;
/* once fast */
if(!_tas((int*)&lk->key))
return;
/* a thousand times pretty fast */
for(i=0; i<1000; i++){
if(!_tas((int*)&lk->key))
return;
sleep(0);
}
/* now nice and slow */
for(i=0; i<1000; i++){
if(!_tas((int*)&lk->key))
return;
sleep(100);
}
/* take your time */
while(_tas((int*)&lk->key))
sleep(1000);
}
int
canlock(Lock *lk)
{
if(_tas((int*)&lk->key))
return 0;
return 1;
}
void
unlock(Lock *lk)
{
lk->key = 0;
}

View file

@ -22,7 +22,7 @@ SFILES=\
vlop.s
CFILES=\
lock.c\
cycles.c\
notejmp.c\
sqrt.c\
vlrt.c\