2011年5月7日 星期六

Linux Kernel(14)- Kernel Synchronization


這裡簡單介紹的介紹一下Kernel Synchronization的幾個觀念的幾個觀念。
  1. Race Condition
  2. 當多個process同時對同一個資料進行存取,且執行結果和其存取順序的不同而有所不同,稱為race condition。
  3. Critical Regions(或稱critical sections)
  4. 指的是一個存取共用資源的程式片斷。
  5. Kernel Synchronization
  6. 簡單說防止kernel發生race condition。保護的重點是shared data,而且保護的範圍和負擔越小越好。

Kernel Synchronization常見的作法就是locking,每次只允許一個process可以存取share data,就可以避免race condition了。

    在kernel中有幾種引發concurrency的可能
  1. Interrupt
  2. 當CPU收到interrupt會立刻中斷目前工作去執行interrupt handler。
  3. Softirq
  4. 當softirq被raise起來就會中斷目前工作去執行softirq。
  5. kernel preemption
  6. 如果kernel preemption被開啟,那麼task就可能被中斷。
  7. Sleeping
  8. 如果kernel執行到blocking code,就可能被schedule出去。
  9. SMP
  10. 同時間兩個以上的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



沒有留言:

張貼留言

熱門文章