2015-08-28 18 views
0

我想了解如何在Linux內核中實現wait_event。在ldd3中有一個代碼示例,其中使用prepare_to_wait(http://www.makelinux.net/ldd3/chp-6-sect-2)解釋了內部實現。爲什麼在prepare_to_wait之後檢查wait_event中的條件是必須的?

static int scull_getwritespace(struct scull_pipe *dev, struct file *filp) 
{ 
    while (spacefree(dev) == 0) { 
     DEFINE_WAIT(wait); 

     up(&dev->sem); 
     if (filp->f_flags & O_NONBLOCK) 
      return -EAGAIN; 
     PDEBUG("\"%s\" writing: going to sleep\n",current->comm); 
     prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE); 
     if (spacefree(dev) == 0) // Why is this check necessary ?? 
      schedule(); 
     finish_wait(&dev->outq, &wait); 
     if (signal_pending(current)) 
      return -ERESTARTSYS; /* signal: tell the fs layer to handle it */ 
     if (down_interruptible(&dev->sem)) 
      return -ERESTARTSYS; 
    } 
    return 0; 
} 

在書中,它解釋如下。

然後對緩衝區進行強制檢查;我們必須處理 的情況,在我們輸入 while循環(並丟棄信號量)之後,但在將 置於等待隊列之前,緩衝區中的空間變得可用。如果沒有檢查,如果讀者進程是 能夠在那段時間完全清空緩衝區,我們可能會錯過只有喚醒,我們會永遠得到並永遠睡覺。滿意我們必須睡覺的 ,我們可以打電話給日程安排。

我無法理解這段解釋。如果在調用schedule()之前沒有完成if (spacefree(dev) == 0),我們將如何去無限期睡眠? 如果此強制性檢查不存在,則喚醒()仍會將進程狀態重置爲TASK_RUNNING並按照下一段中的說明計劃返回。

值得再看一下這種情況:如果在if語句測試和計劃調用之間發生喚醒 會發生什麼? 在這種情況下,一切都很好。喚醒將進程狀態重置爲 TASK_RUNNING並計劃返回 - 儘管不一定馬上。 只要測試發生在進程將自己置於 等待隊列並更改其狀態後,事情就會起作用。

回答

3

重要的是,(最後)檢查是prepare_to_wait()被稱爲後。

prepare_to_wait()將指向當前進程的指針放入等待隊列中。如果在prepare_to_wait()調用之前發生的喚醒,則喚醒將不能影響當前進程。

+0

啊..我現在明白了。感謝您的解釋。 – alex

相關問題