`ll/sc` 指令在`linux`中的软件实现

load-linkstore-conditional (LL/SC)是一对用于并发同步访问内存的CPU指令。Load-link返回内存位置处的当前值,随后的store-conditional在该内存位置处保存新值(如果从load-link后没有被修改)。这被用于实现无锁算法read-modify-write原子操作。

linux<asm/atomic.h><asm/system.h><asm/cmpxchg.h><asm/bitops.h><asm/local.h>中实现了多种基本的原子操作,以最简单的atomic_add来举例:

/*
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 *
 * Atomically adds @i to @v.
 */
static __inline__ void atomic_add(int i, atomic_t * v)
{
    if (kernel_uses_llsc && R10000_LLSC_WAR) {
        int temp;

        __asm__ __volatile__(
        "   .set    mips3                   \n"
        "1: ll  %0, %1      # atomic_add        \n"
        "   addu    %0, %2                  \n"
        "   sc  %0, %1                  \n"
        "   beqzl   %0, 1b                  \n"
        "   .set    mips0                   \n"
        : "=&r" (temp), "=m" (v->counter)
        : "Ir" (i), "m" (v->counter));
    } else if (kernel_uses_llsc) {
        int temp;

        __asm__ __volatile__(
        "   .set    mips3                   \n"
        "1: ll  %0, %1      # atomic_add        \n"
        "   addu    %0, %2                  \n"
        "   sc  %0, %1                  \n"
        "   beqz    %0, 2f                  \n"
        "   .subsection 2                   \n"
        "2: b   1b                  \n"
        "   .previous                   \n"
        "   .set    mips0                   \n"
        : "=&r" (temp), "=m" (v->counter)
        : "Ir" (i), "m" (v->counter));
    } else {
        unsigned long flags;

        raw_local_irq_save(flags);
        v->counter += i;
        raw_local_irq_restore(flags);
    }
}

其中,kernel_uses_llsc是一个宏定义,当定义为0时就需要软件实现。raw_local_irq_saveraw_local_irq_restore函数定义在<linux/irqflags.h>,对于不同的mips cpu有不同的实现,最简单的实现如下:

    .macro irq_enable_hazard; _ssnop; _ssnop; _ssnop;; .endm
    .macro irq_disable_hazard; nop; nop; nop; .endm

        .macro  raw_local_irq_save result           
    .set    push                        
    .set    reorder                     
    .set    noat                        
    mfc0    \result, $12                    
    ori $1, \result, 0x1f               
    xori    $1, 0x1f                    
    .set    noreorder                   
    mtc0    $1, $12                     
    irq_disable_hazard                  
    .set    pop                     
    .endm                           

        .macro  raw_local_irq_restore flags         
    .set    push                        
    .set    noreorder                   
    .set    noat                        
    mfc0    $1, $12                     
    andi    \flags, 1                   
    ori $1, 0x1f                    
    xori    $1, 0x1f                    
    or  \flags, $1                  
    mtc0    \flags, $12                 
    irq_disable_hazard                  
    .set    pop                     
    .endm                           

raw_local_irq_saveraw_local_irq_restore被实现为两个mips的宏定义,raw_local_irq_savecp0status寄存器进行修改,让cpu进入kernek modeERLEXL0,同时禁止中断,从而保证了原子性。raw_local_irq_restore将中断使能打开。

转载于:https://www.cnblogs.com/PowerofChoas/p/11247281.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值