介紹一篇LWN的文章[1],該文整理了atomic API的幾個使用時機,以及不建議的場合:
1. Simple flag (設後不理)
NFS RFC實作原本有很多的flag透過bit field表示狀態:
unsigned int sl_temp : 1; /* temp socket */
由於bit field的更新會造成同一個word的read-modify-write,所以原本作法是透過spin_lock來避免
在SMP下的race condition。但是spin_lock在這個情況下有點太肥,因為會限制其他field的同時存取,
後來改用set_bit()/clear_bit(),由硬體支援的atomic 指令來完成。
(EX: arch/arm64/lib/bitops.S)
所以:如果只有bit fields要更新,可考慮atomic API,避免不必要的lock。
2. Counters
很多kernel的統計資料會透過per-cpu counter逐次累加,需要獲取時才再加總。但是對於不是太常
更新的counter,可以透過一個global counter,然後使用atomic_add()來簡化設計
(EX:許多file system的logging stat)。
所以:per-cpu counter,可考慮改為單一global counter。
3. Exclusive ownership (設後要理)
#1只對flag作update,設後不理。但是如果flag是拿來當作互斥使用時,就要再考慮barrier的問題,
並使用對應的版本:
if (!test_and_set_bit_lock(BIT_NUM, &bitmap)) {
/* make use of exclusive ownership here */
clear_bit_unlock(BIT_NUM, &bitmap);
} else
/* try some other approach */
以上程式可以實現類似spin_trylock的動作,其中_lock/_unlock suffix是必須的。若沒有該suffix,
test_and_set_bit()會在前後都加barrier,而clear_bit()完全沒有barrier指令。後者幾乎肯定會是一個BUG,因為可能資料結構還沒更新完,bit就clear了…
由此可見,使用atomic operation來作互斥要比使用spinlock更為小心,要確認memory barrier的需求有被滿足。
作者建議,一般情況下不要使用atomic API來作互斥,因為有時即使連core developers,都要討論很久…
所以:互斥需求盡量不要使用atomic API,請改用已經包裝好的lock API。
4. Counters and pointers for exclusive ownership
其他巧妙的 atomic應用以拿到互斥所有權。主要都是根據driver的特性才有的假設。有興趣的朋友再繼續看下去吧。
留言
張貼留言