国产激情久久久久影院小草_国产91高跟丝袜_99精品视频99_三级真人片在线观看

Linux內(nèi)核中的RCU機(jī)制

時(shí)間:2024-09-23 13:26:11 Linux認(rèn)證 我要投稿
  • 相關(guān)推薦

Linux內(nèi)核中的RCU機(jī)制

  RCU的設(shè)計(jì)思想比較明確,通過(guò)新老指針替換的方式來(lái)實(shí)現(xiàn)免鎖方式的共享保護(hù)。但是具體到代碼的層面,理解起來(lái)多少還是會(huì)有些困難。下面小編準(zhǔn)備了關(guān)于Linux內(nèi)核中的RCU機(jī)制的文章,提供給大家參考!

  RCU讀取側(cè)進(jìn)入臨界區(qū)的標(biāo)志是調(diào)用rcu_read_lock,這個(gè)函數(shù)的代碼是:

  static inline void rcu_read_lock(void)

  {

  __rcu_read_lock();

  __acquire(RCU);

  rcu_read_acquire();

  }

  該實(shí)現(xiàn)里面貌似有三個(gè)函數(shù)調(diào)用,但實(shí)質(zhì)性的工作由第一個(gè)函數(shù)__rcu_read_lock()來(lái)完成,__rcu_read_lock()通過(guò)調(diào)用 preempt_disable()關(guān)閉內(nèi)核可搶占性。但是中斷是允許的,假設(shè)讀取者正處于rcu臨界區(qū)中且剛讀取了一個(gè)共享數(shù)據(jù)區(qū)的指針p(但是還沒(méi)有訪問(wèn)p中的數(shù)據(jù)成員),發(fā)生了一個(gè)中斷,而該中斷處理例程ISR恰好需要修改p所指向的數(shù)據(jù)區(qū),按照RCU的設(shè)計(jì)原則,ISR會(huì)新分配一個(gè)同樣大小的數(shù)據(jù)區(qū)new_p,再把老數(shù)據(jù)區(qū)p中的數(shù)據(jù)拷貝到新數(shù)據(jù)區(qū),接著是在new_p的基礎(chǔ)上做數(shù)據(jù)修改的工作(因?yàn)槭窃趎ew_p空間中修改,所以不存在對(duì)p的并發(fā)訪問(wèn),因此說(shuō)RCU是一種免鎖機(jī)制,原因就在這里),ISR在把數(shù)據(jù)更新的工作完成后,將new_p賦值給p(p=new_p),最后它會(huì)再注冊(cè)一個(gè)回調(diào)函數(shù)用以在適當(dāng)?shù)臅r(shí)候釋放老指針p。因此,只要對(duì)老指針p上的所有引用都結(jié)束了,釋放p就不會(huì)有問(wèn)題。當(dāng)中斷處理例程做完這些工作返回后,被中斷的進(jìn)程將依然訪問(wèn)到p空間上的數(shù)據(jù),也就是老數(shù)據(jù),這樣的結(jié)果是RCU機(jī)制所允許的。RCU規(guī)則對(duì)讀取者與寫(xiě)入者之間因指針切換所造成的短暫的資源視圖不一致問(wèn)題是允許的。

  接下來(lái)關(guān)于RCU一個(gè)有趣的問(wèn)題是:何時(shí)才能釋放老指針。我見(jiàn)過(guò)很多書(shū)中對(duì)此的回答是:當(dāng)系統(tǒng)中所有處理器上都發(fā)生了一次進(jìn)程切換。這種程式化的回答常常讓剛接觸RCU機(jī)制的讀者感到一頭霧水,為什么非要等所有處理器上都發(fā)生一次進(jìn)程切換才可以調(diào)用回調(diào)函數(shù)釋放老指針呢?這其實(shí)是RCU的設(shè)計(jì)規(guī)則決定的: 所有對(duì)老指針的引用只可能發(fā)生在rcu_read_lock與rcu_read_unlock所包括的臨界區(qū)中,而在這個(gè)臨界區(qū)中不可能發(fā)生進(jìn)程切換,而一旦出了該臨界區(qū)就不應(yīng)該再有任何形式的對(duì)老指針p的引用。很明顯,這個(gè)規(guī)則要求讀取者在臨界區(qū)中不能發(fā)生進(jìn)程切換,因?yàn)橐坏┯羞M(jìn)程切換,釋放老指針的回調(diào)函數(shù)就有可能被調(diào)用,從而導(dǎo)致老指針被釋放掉,當(dāng)被切換掉的進(jìn)程被重新調(diào)度運(yùn)行時(shí)它就有可能引用到一個(gè)被釋放掉的內(nèi)存空間。

  現(xiàn)在我們看到為什么rcu_read_lock只需要關(guān)閉內(nèi)核可搶占性就可以了,因?yàn)樗沟眉幢阍谂R界區(qū)中發(fā)生了中斷,當(dāng)前進(jìn)程也不可能被切換除去。 內(nèi)核開(kāi)發(fā)者,確切地說(shuō),RCU的設(shè)計(jì)者所能做的只能到這個(gè)程度。接下來(lái)就是使用者的責(zé)任了,如果在rcu的臨界區(qū)中調(diào)用了一個(gè)函數(shù),該函數(shù)可能睡眠,那么RCU的設(shè)計(jì)規(guī)則就遭到了破壞,系統(tǒng)將進(jìn)入一種不穩(wěn)定的狀態(tài)。

  這再次說(shuō)明,如果想使用一個(gè)東西,一定要搞清楚其內(nèi)在的機(jī)制,象上面剛提到的那個(gè)例子,即便現(xiàn)在程序不出現(xiàn)問(wèn)題,但是系統(tǒng)中留下的隱患如同一個(gè)定時(shí)炸彈, 隨時(shí)可能被引爆,尤其是過(guò)了很長(zhǎng)時(shí)間問(wèn)題才突然爆發(fā)出來(lái)。絕大多數(shù)情形下,找到問(wèn)題所花費(fèi)的時(shí)間可能要遠(yuǎn)遠(yuǎn)大于靜下心來(lái)仔細(xì)搞懂RCU的原理要多得多。

  RCU中的讀取者相對(duì)rwlock的讀取者而言,自由度更高。因?yàn)镽CU的讀取者在訪問(wèn)一個(gè)共享資源時(shí),不需要考慮寫(xiě)入者的感受,這不同于rwlock的寫(xiě)入者,rwlock reader在讀取共享資源時(shí)需要確保沒(méi)有寫(xiě)入者在操作該資源。兩者之間的差異化源自RCU對(duì)共享資源在讀取者與寫(xiě)入者之間進(jìn)行了分離,而rwlock的 讀取者和寫(xiě)入者則至始至終只使用共享資源的一份拷貝。這也意味著RCU中的寫(xiě)入者要承擔(dān)更多的責(zé)任,而且對(duì)同一共享資源進(jìn)行更新的多個(gè)寫(xiě)入者之間必須引入某種互斥機(jī)制,所以RCU屬于一種"免鎖機(jī)制"的說(shuō)法僅限于讀取者與寫(xiě)入者之間。所以我們看到:RCU機(jī)制應(yīng)該用在有大量的讀取操作,而更新操作相對(duì)較少的情形下。此時(shí)RCU可以大大提升系統(tǒng)系能,因?yàn)镽CU的讀取操作相對(duì)其他一些有鎖機(jī)制而言,在鎖上的開(kāi)銷(xiāo)幾乎沒(méi)有。

  實(shí)際使用中,共享的資源常常以鏈表的形式存在,內(nèi)核為RCU模式下的鏈表操作實(shí)現(xiàn)了幾個(gè)接口函數(shù),讀取者和使用者應(yīng)該使用這些內(nèi)核函數(shù),比如 list_add_tail_rcu, list_add_rcu,hlist_replace_rcu等等,具體的使用可以參考某些內(nèi)核編程或者設(shè)備驅(qū)動(dòng)程序方面的資料。

  在釋放老指針?lè)矫,Linux內(nèi)核提供兩種方法供使用者使用,一個(gè)是調(diào)用call_rcu,另一個(gè)是調(diào)用synchronize_rcu。前者是一種異步 方式,call_rcu會(huì)將釋放老指針的回調(diào)函數(shù)放入一個(gè)結(jié)點(diǎn)中,然后將該結(jié)點(diǎn)加入到當(dāng)前正在運(yùn)行call_rcu的處理器的本地鏈表中,在時(shí)鐘中斷的 softirq部分(RCU_SOFTIRQ), rcu軟中斷處理函數(shù)rcu_process_callbacks會(huì)檢查當(dāng)前處理器是否經(jīng)歷了一個(gè)休眠期(quiescent,此處涉及內(nèi)核進(jìn)程調(diào)度等方面的內(nèi)容),rcu的內(nèi)核代碼實(shí)現(xiàn)在確定系統(tǒng)中所有的處理器都經(jīng)歷過(guò)了一個(gè)休眠期之后(意味著所有處理器上都發(fā)生了一次進(jìn)程切換,因此老指針此時(shí)可以被安全釋放掉了),將調(diào)用call_rcu提供的回調(diào)函數(shù)。

  synchronize_rcu的實(shí)現(xiàn)則利用了等待隊(duì)列,在它的實(shí)現(xiàn)過(guò)程中也會(huì)向call_rcu那樣向當(dāng)前處理器的本地鏈表中加入一個(gè)結(jié)點(diǎn),與 call_rcu不同之處在于該結(jié)點(diǎn)中的回調(diào)函數(shù)是wakeme_after_rcu,然后synchronize_rcu將在一個(gè)等待隊(duì)列中睡眠,直到系統(tǒng)中所有處理器都發(fā)生了一次進(jìn)程切換,因而wakeme_after_rcu被rcu_process_callbacks所調(diào)用以喚醒睡眠的 synchronize_rcu,被喚醒之后,synchronize_rcu知道它現(xiàn)在可以釋放老指針了。

  所以我們看到,call_rcu返回后其注冊(cè)的回調(diào)函數(shù)可能還沒(méi)被調(diào)用,因而也就意味著老指針還未被釋放,而synchronize_rcu返回后老指針肯定被釋放了。所以,是調(diào)用call_rcu還是synchronize_rcu,要視特定需求與當(dāng)前上下文而定,比如中斷處理的上下文肯定不能使用 synchronize_rcu函數(shù)了。

【Linux內(nèi)核中的RCU機(jī)制】相關(guān)文章:

Linux內(nèi)核和驅(qū)動(dòng)考試題06-13

Linux中du命令參數(shù)的用法11-01

Linux中的more命令解讀202405-06

linux中php如何安裝CURL06-10

linux命令中su和sudo區(qū)別08-10

java程序中如何調(diào)用linux命令08-27

績(jī)效管理中的溝通機(jī)制建設(shè)12-13

perl- javascript中class的機(jī)制05-03

Linux系統(tǒng)中的SSH如何添加雙重認(rèn)證09-01

php內(nèi)核知識(shí)解讀09-06