Linux try_cmpxchg神秘的内联汇编

标签 linux assembly locking

我需要一些帮助来理解 Linux 的 `try_cmpxchg 语义和实现。在内核源码中,它是这样实现的:

#define __raw_try_cmpxchg(_ptr, _pold, _new, size, lock)        \
({                                                              \
    bool success;                                               \
    __typeof__(_ptr) _old = (_pold);                            \
    __typeof__(*(_ptr)) __old = *_old;                          \
    __typeof__(*(_ptr)) __new = (_new);                         \
    switch (size) {                                             \
    case __X86_CASE_B:                                          \
    {                                                           \
        volatile u8 *__ptr = (volatile u8 *)(_ptr);             \
        asm volatile(lock "cmpxchgb %[new], %[ptr]"             \
                 CC_SET(z)                                      \
                 : CC_OUT(z) (success),                         \
                   [ptr] "+m" (*__ptr),                         \
                   [old] "+a" (__old)                           \
                 : [new] "q" (__new)                            \
                 : "memory");                                   \
        break;                                                  \
    }                                                           \
    case __X86_CASE_W:                                          \
    {                                                           \
        volatile u16 *__ptr = (volatile u16 *)(_ptr);           \
        asm volatile(lock "cmpxchgw %[new], %[ptr]"             \
                 CC_SET(z)                                      \
                 : CC_OUT(z) (success),                         \
                   [ptr] "+m" (*__ptr),                         \
                   [old] "+a" (__old)                           \
                 : [new] "r" (__new)                            \
                 : "memory");                                   \
        break;                                                  \
    }                                                           \
    case __X86_CASE_L:                                          \
    {                                                           \
        volatile u32 *__ptr = (volatile u32 *)(_ptr);           \
        asm volatile(lock "cmpxchgl %[new], %[ptr]"             \
                 CC_SET(z)                                      \
                 : CC_OUT(z) (success),                         \
                   [ptr] "+m" (*__ptr),                         \
                   [old] "+a" (__old)                           \
                 : [new] "r" (__new)                            \
                 : "memory");                                   \
        break;                                                  \
    }                                                           \
    case __X86_CASE_Q:                                          \
    {                                                           \
        volatile u64 *__ptr = (volatile u64 *)(_ptr);           \
        asm volatile(lock "cmpxchgq %[new], %[ptr]"             \
                 CC_SET(z)                                      \
                 : CC_OUT(z) (success),                         \
                   [ptr] "+m" (*__ptr),                         \
                   [old] "+a" (__old)                           \
                 : [new] "r" (__new)                            \
                 : "memory");                                   \
        break;                                                  \
    }                                                           \
    default:                                                    \
        __cmpxchg_wrong_size();                                 \
    }                                                           \
    if (unlikely(!success))                                     \
        *_old = __old;                                          \
    likely(success);                                            \
})

#define __try_cmpxchg(ptr, pold, new, size)     \
    __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX)

#define try_cmpxchg(ptr, pold, new)                 \
    __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))

我很好奇那些 CC_SETCC_OUT 是什么意思。它们被定义为:

/*
 * Macros to generate condition code outputs from inline assembly,
 * The output operand must be type "bool".
 */
#ifdef __GCC_ASM_FLAG_OUTPUTS__
# define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
# define CC_OUT(c) "=@cc" #c
#else
# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
# define CC_OUT(c) [_cc_ ## c] "=qm"
#endif

此外,如果您能解释 try_cmpxchg 的确切语义,那就太好了(不太了解原子 cmpxchg 怎么会失败...)

最佳答案

较新版本的 gcc(我相信从版本 6 开始)支持特定的标志输出。宏在那里使用此支持(如果可用),否则通过执行 setCC 指令和临时输出返回到旧方法。

至于 cmpxchg 如何“失败”:它进行比较,因此如果比较失败则失败,在这种情况下目标未更改,当前值是从内存中获取的。有关详细信息,请参阅指令集引用。

关于Linux try_cmpxchg神秘的内联汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45534231/

相关文章:

linux - 终止管道中的上一个命令

c++ - boost::mutex 和 boost::timed_mutex 的性能差异

c++ - 识别asm中的地址计算insns

c - C代码在Visual Studio中编译成什么汇编语言?

java - 这个(无锁)队列实现是线程安全的吗?

c# - FileStream 锁定文件以进行读写

c - 为什么 perf 显示的浮点事件少于预期?

python - 从挂载的文件系统生成requirements.txt?

Linux mv 命令时间加空格

c++ - 阅读汇编比较乘法与除法