這裡簡單介紹的介紹一下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