2012-06-13 99 views
2

我有一個驅動程序想要向用戶發送有關狀態更改的通知。在當前的實現中,它使用proc文件系統來執行此操作。讀取過程圍繞read()循環到proc文件系統。 read()塊與wait_event_interruptible(),直到內核得到一箇中斷,導致write_new_data()函數call wake_up_interruptible()。這裏是基本的代碼(去掉所有不需要的雜波):wait_event和wake_up之間的競爭條件

static int flag=0; 
DECLARE_WAIT_QUEUE_HEAD(info_wq); 

//user process call read() on /proc/myfile to get to this function 
int my_proc_read (struct file *filp, char *buf, size_t count, loff_t *pos) 
{ 
    wait_event_interruptible(info_wq, flag != 0); 
    flag = 0; 

    //copy buffers to user 
    return 0; 
} 


//when an interrupt comes it schedules this function on the systems' work queue 
void write_new_data() 
{ 
    //fill buffer with data 
    flag = 1; 
    wake_up_interruptible(&info_wq); 
} 

現在考慮下面的流程:

  1. 用戶進程調用read(),然後等待。
  2. 發生中斷 - >write_new_data()被調用。寫數據並致電wake_up_interruptible()
  3. read()被喚醒,讀取數據但進程沒有重新運行讀取(沒有安排 運行,沒有得到它,因爲下一個中斷...)。發生
  4. 中斷 - >write_new_data()再次被觸發,調用wake_up_interruptible()但沒有等待線程正在等待...
  5. 過程調用read和塊。

注意:這一切都發生在單處理器系統上。另外只有一個線程讀取和一個線程寫入新數據。

如何避免丟失第二個中斷? (一種解決方案是使用netlink的插座,但我不知道是否有一種方法可以做到這一點在/ proc土地)

+0

是什麼樣的驅動程序?以及它正在追查什麼狀態? –

回答

1

由於中斷可以調用wait_event_interruptibleflag = 0之間發生,它會影響在該flag變量不想要的方式。

請注意,即使在UP機器上,根據配置,內核可能是搶先式的,並且該代碼會因此受到影響。

另外,我建議不要使用簡單的'int'標誌。相反,您應該使用atomic_tatomic_dec/inc_*操作。在內核中查看完成的實現,它和你在這裏做的事情類似。

關於這個問題本身:

如果你會看在wait_event_interruptible的代碼,你會發現,如果條件爲真,睡眠不會發生 - 所以你的問題是一個非問題。

+0

那麼,爲了簡單起見,我拿出了帶自旋鎖的代碼部分來控制旗子的變化。感謝有關atomic_dec/inc和完成的提示 - 我將詳細閱讀這些內容。仍然是我的基本問題仍然沒有答案... –

+0

你提出的流程有一些不太正確的地方。在第二次中斷之後,標誌== 1,並且下一次調用'read',即使它被中斷延遲了,似乎也無法阻塞,因爲由於提供的條件,wait_Event_interruptible將立即退出。 –

+0

這裏我們不同意。我的理解是,如果喚醒被調用時,沒有線程在等待隊列上(不稱爲wait_event),那麼條件爲真的事實將無濟於事,進程將休眠直到有人再次調用wake_up(並且只有這樣條件檢查是否正確) –

3

丹,這裏是wait_event_interruptible的代碼:

#define wait_event_interruptible(wq, condition)    \ 
({         \ 
    int __ret = 0;       \ 
    if (!(condition))      \ 
     __wait_event_interruptible(wq, condition, __ret); \ 
    __ret;        \ 
}) 

如果只是之間發生了中斷,「如果((條件)!)」和「__wait_event_interruptible」,睡眠會發生和讀取過程將直到發生另一箇中斷爲止。

+0

不,看看__wait_event_interrupts() - 它確實如果(條件)break'睡覺前。 –

+0

錯字;我的意思是看__wait_event_interruptible()。它再次檢查條件。爲了進一步闡明 - 即使中斷髮生在第二次檢查後,調用schedule()將立即返回,因爲在中斷中調用了wake_up。 __wait_event_interruptible在再次檢查條件之前調用prepare_to_wait()*的原因是爲了防止條件更新上的競爭。因此,API是有效的,但在問題中處理'flag'仍然是一個錯誤。 –

+0

好的,謝謝丹。 – Adrien