首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ARM命令LDREX和STREX实现spinlock

ARM命令LDREX和STREX实现spinlock

在 include/asm-arm/spinlock.h 下有這麼一段
#if __LINUX_ARM_ARCH__ < 6
#error SMP not supported on pre-ARMv6 CPUs
#endif
好啦,前提就是:只有 ARM core 版本 >=6 才可以繼續
all spin lock primitives 到最後都是使用下面這個基本型:
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
    unsigned long tmp;

1      __asm__ __volatile__(
2"1:    ldrex    %0, [%1]\n"
3"    teq    %0, #0\n"
4"    strexeq    %0, %2, [%1]\n"
5"    teqeq    %0, #0\n"
6"    bne    1b"
7   : "=&r" (tmp)
8  : "r" (&lock->lock), "r" (1)
9 : "cc");

    smp_mb();
}

[指令重點]:
ldrex 指令是 core 6 以後才有的,跟 strex 配成一對指令,可以請 bus 監控從 ldrex 到 strex 之間有無其他的 CPU 或 DMA 來存取這個位址 ,若有的話,strex 會在第一個 register 裡設定值為 1(non-exclusive by this CPU) 並且令 store 動作失敗,若沒有,strex 會在第一個 register 裡設定值為 0(exclusive access by this CPU) 並且令 store 動作成功。
Code Trace Discussion:
Line 1: __volatile__ 告訴 compiler ,不要對這塊 assembly template 做最佳化動作,因為我們裡面有 loop 讀取 memory 動作,最佳化的結果可能導致 compiler 用一個 register 來 cache 它的值,不會老老實實的去讀 memory... 呵呵,這不是我們想要的動作喔!
Line 2: 把 lock 讀到 tmp,並請 bus monitor 這個 memory
Line 3: 測試 lock 是否為 0,若非 0,表示 lock 已經被別人取得了,則 Line 4,5 都不做了,然後  Line 6 一定 branch,做 spin 的動作。若為 0,表示有機會取得 lock,繼續做 Line 4.5.
Line 4: 重點來了!,核對 bus monitor 的結果,若是exclusive access 則 tmp 設為 0 並且把 1 儲存到 lock,若是 non-exclusive access(有其他 CPU 來動過) 則 tmp設為 1並且不做儲存 lock 的動作。
Line 5: 測試 tmp
Line 6: 若 tmp 為 0 表示剛剛對 lock 動作是 exclusive,可以離開迴圈,若 tmp 為 1,則做 spin 動作。
Line 7: tmp 用 register 來操作,同時是 input 及 output 令它為 %0
Line 8: &lock->lock 用 register 來操作 ,令它為 %1,值 1 用用 register 來操作 ,令它為 %2
Line 9: 此 template 會改到 condition code,加入 clobber list 以告訴 compiler 有這回事
好了,終於看完了,真的很佩服那些 coding 的 kernel hackers ....
思考問題: ARM v6 以前有個  SWP 指令可以 lock bus and swap memory ,一樣可以用來完成 exclusive access ,但是比起 ldrex,strex 這對指令有什麼缺點呢?
ANS: 用滑鼠反白下幾行
SWP lock bus,其他 CPU 所有動作都不能做,但是 ldrex,strex就不會有這種現象,使用 ldrex,strex 時若其他 CPU不來 access 這個特定的 memory 就可以平行的做動作,增加平行執行的 performance
返回列表