我在互联网上找到了__sync_val_compare_and_swap的实现:
#define LOCK_PREFIX "lock ; "
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
unsigned long prev;
switch (size) {
case 1:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 2:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
case 4:
__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
: "=a"(prev)
: "q"(new), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
}
return old;
}
#define cmpxchg(ptr,o,n)\
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
当我为i386架构编译和使用此函数(cmpxchg)时 - 一切都很好!但是,当我在Sparc架构下编译时,我遇到以下错误:
error: impossible constraint in `asm'
有什么问题?
答案 0 :(得分:5)
cmpxchgb
是一条i386指令,它不会在Sparc下工作。
答案 1 :(得分:3)
在Solaris上,最好不要为此编写自己的代码(在SPARC和x86上都没有);相反,为此目的使用atomic_cas(3C)
函数:
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
switch (size) {
case 1: return atomic_cas_8(ptr, (unsigned char)old, (unsigned char)new);
case 2: return atomic_cas_16(ptr, (unsigned short)old, (unsigned short)new);
case 4: return atomic_cas_32(ptr, (unsigned int)old, (unsigned int)new);
#ifdef _LP64
case 8: return atomic_cas_64(ptr, old, new);
#endif
default: break;
}
return old;
}
这对Solaris有用。
编辑:如果您必须内联此类内容,请使用的SPARC(v8 +,又名UltraSPARC)指令是“比较和交换”,即CAS
。它总是原子的(sparc不知道锁前缀)。它只有32位和64位(CASX
)变体,因此8/16位库函数执行32位CAS
屏蔽非目标字/字节。我不会帮助重新实现 - 这不是一个好主意,使用库接口。
Edit2:有些帮助您重新实现reading the sourcecode(如果您无法与Solaris libc链接)。
答案 2 :(得分:1)
您无法为sparc编译x86 asm。这是我使用clang得到的:
[~] main% ~/ellcc/bin/sparc-linux-ecc asm.c
asm.c:13:20: error: invalid output constraint '=a' in asm
: "=a"(prev)
'a'不是sparc寄存器,它特定于x86。
即使你要修复约束,当sparc汇编程序看到cmpxchgb操作码时,你会得到汇编时错误,这是特定于x86的。