mirror of
https://github.com/postgres/postgres.git
synced 2025-05-11 05:41:32 +03:00
Adjust TAS assembly as per recent discussions: use "+m"(*lock) everywhere
to reference the spinlock variable, and specify "memory" as a clobber operand to be sure gcc does not try to keep shared-memory values in registers across a spinlock acquisition. Also tighten the S/390 asm sequence, which was apparently written with only minimal study of the gcc asm documentation. I have personally tested i386, ia64, ppc, hppa, and s390 variants --- there is some small chance that I broke the others, but I doubt it.
This commit is contained in:
parent
c1d9dec3e3
commit
1098677482
@ -66,7 +66,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.125 2004/01/03 05:47:44 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.126 2004/06/19 23:02:32 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -85,16 +85,26 @@
|
|||||||
* Other compilers use __cpu or __cpu__ so we test for both in those cases.
|
* Other compilers use __cpu or __cpu__ so we test for both in those cases.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*----------
|
||||||
* Standard gcc asm format is:
|
* Standard gcc asm format (assuming "volatile slock_t *lock"):
|
||||||
*
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" command \n"
|
" instruction \n"
|
||||||
" command \n"
|
" instruction \n"
|
||||||
" command \n"
|
" instruction \n"
|
||||||
: "=r"(_res) return value, in register
|
: "=r"(_res), "+m"(*lock) // return register, in/out lock value
|
||||||
: "r"(lock) argument, 'lock pointer', in register
|
: "r"(lock) // lock pointer, in input register
|
||||||
: "r0"); inline code uses this register
|
: "memory", "cc"); // show clobbered registers here
|
||||||
|
|
||||||
|
* The output-operands list (after first colon) should always include
|
||||||
|
* "+m"(*lock), whether or not the asm code actually refers to this
|
||||||
|
* operand directly. This ensures that gcc believes the value in the
|
||||||
|
* lock variable is used and set by the asm code. Also, the clobbers
|
||||||
|
* list (after third colon) should always include "memory"; this prevents
|
||||||
|
* gcc from thinking it can cache the values of shared-memory fields
|
||||||
|
* across the asm code. Add "cc" if your asm code changes the condition
|
||||||
|
* code register, and also list any temp registers the code uses.
|
||||||
|
*----------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -117,8 +127,9 @@ tas(volatile slock_t *lock)
|
|||||||
" lock \n"
|
" lock \n"
|
||||||
" xchgb %0,%1 \n"
|
" xchgb %0,%1 \n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
: "=q"(_res), "=m"(*lock)
|
: "+q"(_res), "+m"(*lock)
|
||||||
: "0"(_res));
|
:
|
||||||
|
: "memory", "cc");
|
||||||
return (int) _res;
|
return (int) _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +139,7 @@ static __inline__ void
|
|||||||
spin_delay(void)
|
spin_delay(void)
|
||||||
{
|
{
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" rep; nop \n"
|
" rep; nop \n");
|
||||||
: : : "memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __i386__ || __x86_64__ */
|
#endif /* __i386__ || __x86_64__ */
|
||||||
@ -150,10 +160,9 @@ tas(volatile slock_t *lock)
|
|||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" xchg4 %0=%1,%2 \n"
|
" xchg4 %0=%1,%2 \n"
|
||||||
: "=r"(ret), "=m"(*lock)
|
: "=r"(ret), "+m"(*lock)
|
||||||
: "r"(1), "1"(*lock)
|
: "r"(1)
|
||||||
: "memory");
|
: "memory");
|
||||||
|
|
||||||
return (int) ret;
|
return (int) ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,17 +182,18 @@ tas(volatile slock_t *lock)
|
|||||||
register slock_t _res = 1;
|
register slock_t _res = 1;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" swpb %0, %0, [%3] \n"
|
" swpb %0, %0, [%2] \n"
|
||||||
: "=r"(_res), "=m"(*lock)
|
: "+r"(_res), "+m"(*lock)
|
||||||
: "0"(_res), "r"(lock));
|
: "r"(lock)
|
||||||
|
: "memory");
|
||||||
return (int) _res;
|
return (int) _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __arm__ */
|
#endif /* __arm__ */
|
||||||
|
|
||||||
|
|
||||||
#if defined(__s390__) && !defined(__s390x__)
|
#if defined(__s390__) || defined(__s390x__)
|
||||||
/* S/390 Linux */
|
/* S/390 and S/390x Linux (32- and 64-bit zSeries) */
|
||||||
#define HAS_TEST_AND_SET
|
#define HAS_TEST_AND_SET
|
||||||
|
|
||||||
typedef unsigned int slock_t;
|
typedef unsigned int slock_t;
|
||||||
@ -193,51 +203,17 @@ typedef unsigned int slock_t;
|
|||||||
static __inline__ int
|
static __inline__ int
|
||||||
tas(volatile slock_t *lock)
|
tas(volatile slock_t *lock)
|
||||||
{
|
{
|
||||||
int _res;
|
int _res = 0;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" la 1,1 \n"
|
" cs %0,%3,0(%2) \n"
|
||||||
" l 2,%2 \n"
|
: "+d"(_res), "+m"(*lock)
|
||||||
" slr 0,0 \n"
|
: "a"(lock), "d"(1)
|
||||||
" cs 0,1,0(2) \n"
|
: "memory", "cc");
|
||||||
" lr %1,0 \n"
|
return _res;
|
||||||
: "=m"(lock), "=d"(_res)
|
|
||||||
: "m"(lock)
|
|
||||||
: "0", "1", "2");
|
|
||||||
|
|
||||||
return (_res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __s390__ */
|
#endif /* __s390__ || __s390x__ */
|
||||||
|
|
||||||
|
|
||||||
#if defined(__s390x__)
|
|
||||||
/* S/390x Linux (64-bit zSeries) */
|
|
||||||
#define HAS_TEST_AND_SET
|
|
||||||
|
|
||||||
typedef unsigned int slock_t;
|
|
||||||
|
|
||||||
#define TAS(lock) tas(lock)
|
|
||||||
|
|
||||||
static __inline__ int
|
|
||||||
tas(volatile slock_t *lock)
|
|
||||||
{
|
|
||||||
int _res;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
" la 1,1 \n"
|
|
||||||
" lg 2,%2 \n"
|
|
||||||
" slr 0,0 \n"
|
|
||||||
" cs 0,1,0(2) \n"
|
|
||||||
" lr %1,0 \n"
|
|
||||||
: "=m"(lock), "=d"(_res)
|
|
||||||
: "m"(lock)
|
|
||||||
: "0", "1", "2");
|
|
||||||
|
|
||||||
return (_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __s390x__ */
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__sparc__)
|
#if defined(__sparc__)
|
||||||
@ -250,12 +226,13 @@ typedef unsigned char slock_t;
|
|||||||
static __inline__ int
|
static __inline__ int
|
||||||
tas(volatile slock_t *lock)
|
tas(volatile slock_t *lock)
|
||||||
{
|
{
|
||||||
register slock_t _res = 1;
|
register slock_t _res;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" ldstub [%2], %0 \n"
|
" ldstub [%2], %0 \n"
|
||||||
: "=r"(_res), "=m"(*lock)
|
: "=r"(_res), "+m"(*lock)
|
||||||
: "r"(lock));
|
: "r"(lock)
|
||||||
|
: "memory");
|
||||||
return (int) _res;
|
return (int) _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,11 +260,11 @@ tas(volatile slock_t *lock)
|
|||||||
int _res;
|
int _res;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" lwarx %0,0,%2 \n"
|
" lwarx %0,0,%3 \n"
|
||||||
" cmpwi %0,0 \n"
|
" cmpwi %0,0 \n"
|
||||||
" bne 1f \n"
|
" bne 1f \n"
|
||||||
" addi %0,%0,1 \n"
|
" addi %0,%0,1 \n"
|
||||||
" stwcx. %0,0,%2 \n"
|
" stwcx. %0,0,%3 \n"
|
||||||
" beq 2f \n"
|
" beq 2f \n"
|
||||||
"1: li %1,1 \n"
|
"1: li %1,1 \n"
|
||||||
" b 3f \n"
|
" b 3f \n"
|
||||||
@ -296,10 +273,9 @@ tas(volatile slock_t *lock)
|
|||||||
" li %1,0 \n"
|
" li %1,0 \n"
|
||||||
"3: \n"
|
"3: \n"
|
||||||
|
|
||||||
: "=&r" (_t), "=r" (_res)
|
: "=&r"(_t), "=r"(_res), "+m"(*lock)
|
||||||
: "r" (lock)
|
: "r"(lock)
|
||||||
: "cc", "memory"
|
: "memory", "cc");
|
||||||
);
|
|
||||||
return _res;
|
return _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,10 +306,9 @@ tas(volatile slock_t *lock)
|
|||||||
" clrl %0 \n"
|
" clrl %0 \n"
|
||||||
" tas %1 \n"
|
" tas %1 \n"
|
||||||
" sne %0 \n"
|
" sne %0 \n"
|
||||||
: "=d"(rv), "=m"(*lock)
|
: "=d"(rv), "+m"(*lock)
|
||||||
: "1"(*lock)
|
:
|
||||||
: "cc");
|
: "memory", "cc");
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,13 +332,13 @@ tas(volatile slock_t *lock)
|
|||||||
register int _res;
|
register int _res;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" movl $1, r0 \n"
|
" movl $1, %0 \n"
|
||||||
" bbssi $0, (%1), 1f \n"
|
" bbssi $0, (%2), 1f \n"
|
||||||
" clrl r0 \n"
|
" clrl %0 \n"
|
||||||
"1: movl r0, %0 \n"
|
"1: \n"
|
||||||
: "=r"(_res)
|
: "=&r"(_res), "+m"(*lock)
|
||||||
: "r"(lock)
|
: "r"(lock)
|
||||||
: "r0");
|
: "memory");
|
||||||
return _res;
|
return _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,9 +358,11 @@ tas(volatile slock_t *lock)
|
|||||||
register int _res;
|
register int _res;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" sbitb 0, %0 \n"
|
" sbitb 0, %1 \n"
|
||||||
" sfsd %1 \n"
|
" sfsd %0 \n"
|
||||||
: "=m"(*lock), "=r"(_res));
|
: "=r"(_res), "+m"(*lock)
|
||||||
|
:
|
||||||
|
: "memory");
|
||||||
return _res;
|
return _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,12 +381,6 @@ tas(volatile slock_t *lock)
|
|||||||
typedef unsigned long slock_t;
|
typedef unsigned long slock_t;
|
||||||
|
|
||||||
#define TAS(lock) tas(lock)
|
#define TAS(lock) tas(lock)
|
||||||
#define S_UNLOCK(lock) \
|
|
||||||
do \
|
|
||||||
{\
|
|
||||||
__asm__ __volatile__ (" mb \n"); \
|
|
||||||
*((volatile slock_t *) (lock)) = 0; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static __inline__ int
|
static __inline__ int
|
||||||
tas(volatile slock_t *lock)
|
tas(volatile slock_t *lock)
|
||||||
@ -417,24 +388,30 @@ tas(volatile slock_t *lock)
|
|||||||
register slock_t _res;
|
register slock_t _res;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" ldq $0, %0 \n"
|
" ldq $0, %1 \n"
|
||||||
" bne $0, 2f \n"
|
" bne $0, 2f \n"
|
||||||
" ldq_l %1, %0 \n"
|
" ldq_l %0, %1 \n"
|
||||||
" bne %1, 2f \n"
|
" bne %0, 2f \n"
|
||||||
" mov 1, $0 \n"
|
" mov 1, $0 \n"
|
||||||
" stq_c $0, %0 \n"
|
" stq_c $0, %1 \n"
|
||||||
" beq $0, 2f \n"
|
" beq $0, 2f \n"
|
||||||
" mb \n"
|
" mb \n"
|
||||||
" br 3f \n"
|
" br 3f \n"
|
||||||
"2: mov 1, %1 \n"
|
"2: mov 1, %0 \n"
|
||||||
"3: \n"
|
"3: \n"
|
||||||
: "=m"(*lock), "=r"(_res)
|
: "=&r"(_res), "+m"(*lock)
|
||||||
:
|
:
|
||||||
: "0");
|
: "memory", "0");
|
||||||
|
|
||||||
return (int) _res;
|
return (int) _res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define S_UNLOCK(lock) \
|
||||||
|
do \
|
||||||
|
{\
|
||||||
|
__asm__ __volatile__ (" mb \n"); \
|
||||||
|
*((volatile slock_t *) (lock)) = 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif /* __alpha || __alpha__ */
|
#endif /* __alpha || __alpha__ */
|
||||||
|
|
||||||
|
|
||||||
@ -540,8 +517,9 @@ tas(volatile slock_t *lock)
|
|||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
" ldcwx 0(0,%2),%0 \n"
|
" ldcwx 0(0,%2),%0 \n"
|
||||||
: "=r"(lockval), "=m"(*lockword)
|
: "=r"(lockval), "+m"(*lockword)
|
||||||
: "r"(lockword));
|
: "r"(lockword)
|
||||||
|
: "memory");
|
||||||
return (lockval == 0);
|
return (lockval == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user