我想了解如何在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並計劃返回 - 儘管不一定馬上。 只要測試發生在進程將自己置於 等待隊列並更改其狀態後,事情就會起作用。
啊..我現在明白了。感謝您的解釋。 – alex