1

我在互联网上找到了__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'

有什么问题?

4

3 回答 3

5

cmpxchgb是 i386 指令,它在 Sparc 下不起作用。

于 2012-02-14T12:39:48.800 回答
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:通过阅读源代码(如果您无法与 Solaris libc 链接),您可以获得一些重新实现的帮助。

于 2012-02-14T16:21:30.853 回答
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 汇编器看到 x86 特定的 cmpxchgb 操作码时,您也会收到汇编时间错误。

于 2012-02-14T12:39:31.703 回答