RCU (Read-Copy Update)是kernel同步機制之一,允許多個reader在writer更新資料的同時讀取資料,reader可能讀到更新前或更新後的,但是資料內容是一致的(不是新的就是舊的,這是因為RCU利用指標的dereference和assign達成的),另外,RCU也能確保資料在read-side使用時不會將之free(下一篇介紹RCU的原理在提吧)。
這裡有一張圖用來描述RCU再經典不過了。首先,藍色的reader的開始就是rcu_read_lock(),結束就是rcu_read_unlock(),下面的removal、grace period和reclamation代表著writer的狀態,這邊只要保證讀到舊資料的reader(就是開頭落在removal的reader),都能在grace period結束之前,離開read-side就可以了,聰明的你一定可以看出在grace period開始之後的reader都是讀到新資料,所以RCU就不管他想用多久。
RCU的三個階段
- removal:更新指標。
- grace period:等待所有持有舊資料的reader都離開RCU read-side。
- reclamation:回收舊資料。
RCU本身就是read-write lock的一種,所以我們介紹一下RCU的reader和writer的形式。
struct foo {
int x;
};
static struct foo *foo = NULL;
// Reader的形式
static int reader(void)
{
int ret;
rcu_read_lock();
ret = rcu_dereference(foo)->x;
rcu_read_unlock();
return ret;
}
// Writer的形式
static void writer(int x)
{
struct foo *new_foo, *old_foo = foo;
// 建立新的資料內容new_foo
new_foo = kmalloc(sizeof(struct foo), GFP_KERNEL);
// 複製原本的內容
*new_foo = *old_foo;
// 修改內容
new_foo->x = x;
// removal
rcu_assign_pointer(foo, new_foo);
// grace period
synchronize_rcu();
// reclamation:
kfree(old_foo);
}
synchronize_rcu()就是在等待所謂的grace period,等所有持舊資料的reader都離開RCU read-side才會往下執行kfree(old_foo)。