本文基linux内核版本 2.6.32-131.17.1.el6.i686源码。
1、原子读、赋值
00016: /**
00017: *atomic_read-readatomicvariable
00018: * @v:pointeroftypeatomic_t
00019: *
00020: *Atomicallyreadsthevalueof @v.
00021: */
00022: staticinlineint atomic_read(constatomic_t*v)
00023: {
00024: returnv–>counter;
00025: }
00026:
00027: /**
00028: *atomic_set-setatomicvariable
00029: * @v:pointeroftypeatomic_t
00030: * @i:requiredvalue
00031: *
00032: *Atomicallysetsthevalueof @vto @i.
00033: */
00034: staticinlinevoid atomic_set(atomic_t*v,inti)
00035: {
00036: v–>counter= i;
00037: }
00038:
2、原子加减
00039: /**
00040: *atomic_add-addintegertoatomicvariable
00041: * @i:integervaluetoadd
00042: * @v:pointeroftypeatomic_t
00043: *
00044: *Atomicallyadds @ito @v.
00045: */
00046: staticinlinevoid atomic_add(inti,atomic_t*v)
00047: {
00048: asmvolatile(LOCK_PREFIX“addl%1,%0”
00049: :“+m” (v–>counter)
00050: :“ir”(i));
00051: }
00052:
00053: /**
00054: *atomic_sub-subtractintegerfromatomicvariable
00055: * @i:integervaluetosubtract
00056: * @v:pointeroftypeatomic_t
00057: *
00058: *Atomicallysubtracts @ifrom @v.
00059: */
00060: staticinlinevoid atomic_sub(inti,atomic_t*v)
00061: {
00062: asmvolatile(LOCK_PREFIX“subl%1,%0”
00063: :“+m” (v–>counter)
00064: :“ir”(i));
00065: }
00066:
3、原子加减1
00085:
00086: /**
00087: *atomic_inc-incrementatomicvariable
00088: * @v:pointeroftypeatomic_t
00089: *
00090: *Atomicallyincrements @vby1.
00091: */
00092: staticinlinevoid atomic_inc(atomic_t*v)
00093: {
00094: asmvolatile(LOCK_PREFIX“incl%0”
00095: :“+m” (v–>counter));
00096: }
00097:
00098: /**
00099: *atomic_dec-decrementatomicvariable
00100: * @v:pointeroftypeatomic_t
00101: *
00102: *Atomicallydecrements @vby1.
00103: */
00104: staticinlinevoid atomic_dec(atomic_t*v)
00105: {
00106: asmvolatile(LOCK_PREFIX“decl%0”
00107: :“+m” (v–>counter));
00108: }
00109:
5、LOCK_PREFIX理解
在原子加减操作中,我们可以发现实现都基于关键指令LOCK_PREFIX。该宏定义在文件arch/x86/include/asm/alternative.h中。
00030: #ifdefCONFIG_SMP
00031: #defineLOCK_PREFIX\
00032: “.section.smp_locks,\”a\”\n”\
00033: _ASM_ALIGN“\n” \
00034: _ASM_PTR “661f\n”/*address*/ \
00035: “.previous\n” \
00036: “661:\n\tlock;”
00037:
00038: #else/*!CONFIG_SMP*/
00039: #defineLOCK_PREFIX“”
00040: #endif
也就是LOCK_PREFIX只有在SMP系统中才有效。在单CPU(UniProcessor)中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。但在多处理器结构中(Symmetric Multi-Processor)就不同了,由于系统中有多个处理器独立运行,即使能在单条指令中完成的操作也有可能受到干扰。在X86平台生,CPU提供了在指令执行期间对总线加锁的手段。CPU上有一根引线#HLOCK pin连到北桥,如果汇编语言的程序中在一条指令前面加上前缀“LOCK”,经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。
LOCK_PREFIX宏扩展开后,就是在语句前加上lock前缀。
atomic_add():
/root/rpmbuild/BUILD/kernel-2.6.32-131.17.1.el6/linux-2.6.32-131.17.1.el6.i686/arch/x86/include/asm/atomic_32.h:48
*
* Atomically adds @i to @v.
*/
static inline void atomic_add(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX “addl %1,%0”
c041c21b: 8b 44 24 20 mov 0x20(%esp),%eax
c041c21f: f0 01 05 1c 8f af c0 lock add %eax,0xc0af8f1c
atomic_add_return():
/root/rpmbuild/BUILD/kernel-2.6.32-131.17.1.el6/linux-2.6.32-131.17.1.el6.i686/arch/x86/include/asm/atomic_32.h:182
if (unlikely(boot_cpu_data.x86 <= 3))
goto no_xadd;
#endif
/* Modern 486+ processor */
__i = i;
asm volatile(LOCK_PREFIX “xaddl %0, %1”
c041c226: bf 01 00 00 00 mov $0x1,%edi
c041c22b: f0 0f c1 3d 18 8f af lock xadd %edi,0xc0af8f18
c041c232: c0
6、其他原子操作
减操作后判断是否为0:atomic_sub_and_test()。
00067: /**
00068: *atomic_sub_and_test-subtractvaluefromvariableandtestresult
00069: * @i:integervaluetosubtract
00070: * @v:pointeroftypeatomic_t
00071: *
00072: *Atomicallysubtracts @ifrom @vandreturns
00073: *trueiftheresultiszero,orfalseforall
00074: *othercases.
00075: */
00076: staticinlineint atomic_sub_and_test(inti,atomic_t*v)
00077: {
00078: unsignedchar c;
00079:
00080: asmvolatile(LOCK_PREFIX“subl%2,%0;sete%1”
00081: :“+m” (v–>counter),“=qm”(c)
00082: :“ir”(i):“memory”);
00083: returnc;
00084: }
递减后判断是否为0:atomic_dec_and_test()。
00110: /**
00111: *atomic_dec_and_test-decrementandtest
00113: *
00114: *Atomicallydecrements @vby1and
00115: *returnstrueiftheresultis0,orfalseforallother
00116: *cases.
00117: */
00118: staticinlineint atomic_dec_and_test(atomic_t*v)
00119: {
00120: unsignedchar c;
00121:
00122: asmvolatile(LOCK_PREFIX“decl%0;sete%1”
00123: :“+m” (v–>counter),“=qm”(c)
00124: :: “memory”);
00125: returnc !=0;
00126: }
00127:
自增后判断是否为0:atomic_inc_and_test()。
00128: /**
00129: *atomic_inc_and_test-incrementandtest
00130: * @v:pointeroftypeatomic_t
00131: *
00132: *Atomicallyincrements @vby1
00133: *andreturnstrueiftheresultiszero,orfalseforall
00134: *othercases.
00135: */
00136: staticinlineint atomic_inc_and_test(atomic_t*v)
00137: {
00138: unsignedchar c;
00139:
00140: asmvolatile(LOCK_PREFIX“incl%0;sete%1”
00141: :“+m” (v–>counter),“=qm”(c)
00142: :: “memory”);
00143: returnc !=0;
00144: }
00145:
相加后是否为负值 :atomic_add_negative()。
00146: /**
00147: *atomic_add_negative-addandtestifnegative
00148: * @v:pointeroftypeatomic_t
00149: * @i:integervaluetoadd
00150: *
00151: *Atomicallyadds @ito @vandreturnstrue
00152: *iftheresultisnegative,orfalsewhen
00153: *resultisgreaterthanorequaltozero.
00154: */
00155: staticinlineint atomic_add_negative(inti,atomic_t*v)
00156: {
00157: unsignedchar c;
00158:
00159: asmvolatile(LOCK_PREFIX“addl%2,%0;sets%1”
00160: :“+m” (v–>counter),“=qm”(c)
00161: :“ir”(i):“memory”);
00162: returnc;
00163: }
00164:
相加后返回: atomic_add_return()。
00165: /**
00166: *atomic_add_return-addintegerandreturn
00168: * @i:integervaluetoadd
00169: *
00170: *Atomicallyadds @ito @vandreturns @i+ @v
00171: */
00172: staticinlineint atomic_add_return(inti,atomic_t*v)
00173: {
00174: int__i;
00175: #ifdefCONFIG_M386
00176: unsignedlongflags;
00177: if(unlikely(boot_cpu_data .x86<= 3))
00178: goto¯no_xadd;
00179: #endif
00180: /*Modern486+processor*/
00181: __i =i;
00182: asmvolatile(LOCK_PREFIX“xaddl%0,%1”
00183: :“+r”(i),“+m” (v–>counter)
00184: :: “memory”);
00185: returni+__i;
00186:
00187: #ifdefCONFIG_M386
00188: no_xadd:/*Legacy386processor*/
00189: local_irq_save(flags);
00190: __i =atomic_read(v);
00191: atomic_set(v,i+__i);
00192: local_irq_restore(flags);
00193: returni+__i;
00194: #endif
00195: }? endatomic_add_return?
00196:
相减后返回:atomic_sub_return()。
00197: /**
00198: *atomic_sub_return-subtractintegerandreturn
00199: * @v:pointeroftypeatomic_t
00200: * @i:integervaluetosubtract
00201: *
00202: *Atomicallysubtracts @ifrom @vandreturns @v– @i
00203: */
00204: staticinlineint atomic_sub_return(inti,atomic_t*v)
00205: {
00206: returnatomic_add_return(–i,v);
00207: }
00208:
Leave a Reply