這裡簡單介紹的介紹一下Kernel Synchronization的幾個觀念的幾個觀念。
- Race Condition
當多個process同時對同一個資料進行存取,且執行結果和其存取順序的不同而有所不同,稱為race condition。
- Critical Regions(或稱critical sections)
指的是一個存取共用資源的程式片斷。
- Kernel Synchronization
簡單說防止kernel發生race condition。保護的重點是shared data,而且保護的範圍和負擔越小越好。
Kernel Synchronization常見的作法就是locking,每次只允許一個process可以存取share data,就可以避免race condition了。
在kernel中有幾種引發concurrency的可能
- Interrupt
當CPU收到interrupt會立刻中斷目前工作去執行interrupt handler。
- Softirq
當softirq被raise起來就會中斷目前工作去執行softirq。
- kernel preemption
如果kernel preemption被開啟,那麼task就可能被中斷。
- Sleeping
如果kernel執行到blocking code,就可能被schedule出去。
- SMP
同時間兩個以上的CPU存取相同的資料就會發生race condition。
在linunx kernel中,執行的context主要分成兩種interrupt context和process context,凡是只要in_interrupt()都是interrupt context,所以引起的原因包含Hardware interrupt和softirq兩種。以下就擷取片段程式碼說明。
// thread_info存放在task的stack裡面
# define task_thread_info(task) ((struct thread_info *)(task)->stack)
// thread_info中的preempt_count分成幾個部份
// bits 0-7 are the preemption count (max preemption depth: 256)
// bits 8-15 are the softirq count (max # of softirqs: 256)
// bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
// bit 26 is the NMI_MASK
// bit 28 is the PREEMPT_ACTIVE flag
struct thread_info {
struct task_struct *task; /* main task structure */
int preempt_count; /* 0 => preemptable */
};
# define preempt_count() (current_thread_info()->preempt_count)
# define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)
// 當每次呼叫irq_enter()就會將preempt_count屬於HARDIRQ的部份遞增
#define __irq_enter() \
do { \
account_system_vtime(current); \
add_preempt_count(HARDIRQ_OFFSET); \
trace_hardirq_enter(); \
} while (0)
# define invoke_softirq() do_softirq()
# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
/*
* Exit an interrupt context. Process softirqs if needed and possible:
*/
void irq_exit(void)
{
// 離開hard interrupt所以要減回去HARDIRQ_OFFSET
sub_preempt_count(IRQ_EXIT_OFFSET);
// 如果不在interrupt context(如softirq裡面),
// 而且softirq有被raise就執行softirq
if (!in_interrupt() && local_softirq_pending())
invoke_softirq();
}
此圖出於http://blog.csdn.net/hero7935/archive/2011/05/07/6401522.aspx
參考資料:
- Linux Kernel Development 2nd, Novell Press