preempt_disable

#define preempt_disable() /
  do { /
      inc_preempt_count(); /
      barrier(); /
  } while (0)

  實現很簡單,就兩行代碼,第一行把進程描述符中的preempt_count加1,第二行加一個優化屏障。展開inc_preempt_count()後就是:

  current->thread_info->preempt_count++;

  barrier();//有些CPU爲了優化並行度, 會調整指令執行的順序。barrier就是迫使cpu嚴格按照指令序執行的

內核搶佔發生在硬件中斷喚醒一個高優先級任務的時候,當發現當前任務的優先級低於被喚醒的任務的優先級且當前任務的preempt_count爲0,那麼就會搶佔當前任務。因此硬件中斷是導火索,也就是說只有在臨界區中的指令執行後,preempt_count++未執行前發生一個硬件中斷,纔有可能發生搶佔。但是硬件中斷都是precise interrupt,精確中斷,即中斷髮生時的PC指針記錄的指令之前的指令都已完成,之後的指令都未執行。這樣即使在上述情況發生一個硬件中斷,硬件只能有兩種方法來保證中斷的精確性: 1. 丟棄臨界區中指令的執行結果,將PC指針指向preempt_disable()。這樣即使被搶佔,臨界區中的指令的執行結果也被丟棄了,所以不會出問題。 2. 等preempt_disable()指令執行後,將PC指針指向臨界區中最後完成的指令的下一條指令。這樣由於preempt_count被加1了,該任務就不能被搶佔了,所以也不會出問題。 分析到這裏,可以看出此處確實不需要內存屏障了,用barrier()保證編譯器不亂排臨界區中的指令就可以了。但是實際上這裏這個barrier()還有另外一個作用,就是保證編譯器會產生寫內存的指令,把preempt_count的值寫到內存。否則編譯器可能對preempt_count進行優化,僅僅把更新後的值放到寄存器中。這樣會出問題,比如在臨界區中產生一箇中斷,中斷處理程序只能從內存中去讀preempt_count的值,它可能無法看到內核搶佔已經被禁止,而錯誤的將不能被搶佔的任務搶佔。這是中斷和進程共享數據時用barrier()來保持同步而不用鎖的一個很好的例子。

/* Optimization barrier *//* The "volatile" is due to gcc bugs */#define barrier() __asm__ __volatile__("": : :"memory")



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章