zoukankan      html  css  js  c++  java
  • `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					
    "
    		"1:	ll	%0, %1		# atomic_add		
    "
    		"	addu	%0, %2					
    "
    		"	sc	%0, %1					
    "
    		"	beqzl	%0, 1b					
    "
    		"	.set	mips0					
    "
    		: "=&r" (temp), "=m" (v->counter)
    		: "Ir" (i), "m" (v->counter));
    	} else if (kernel_uses_llsc) {
    		int temp;
    
    		__asm__ __volatile__(
    		"	.set	mips3					
    "
    		"1:	ll	%0, %1		# atomic_add		
    "
    		"	addu	%0, %2					
    "
    		"	sc	%0, %1					
    "
    		"	beqz	%0, 2f					
    "
    		"	.subsection 2					
    "
    		"2:	b	1b					
    "
    		"	.previous					
    "
    		"	.set	mips0					
    "
    		: "=&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	
    esult, $12					
    	ori	$1, 
    esult, 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将中断使能打开。

  • 相关阅读:
    运动会管理系统
    sql2008开发版
    wordpress改变ip或域名
    mssql技巧
    ubuntukylin ubuntu1304
    手把手玩转win8开发系列课程(13)
    手把手玩转win8开发系列课程(14)
    手把手玩转win8开发系列课程(19)
    手把手玩转win8开发系列课程(11)
    手把手玩转win8开发系列课程(17)
  • 原文地址:https://www.cnblogs.com/PowerofChoas/p/11247281.html
Copyright © 2011-2022 走看看