Linux complete的使用記錄

之前使用complete的時候,程序總是wait_for_completion函數先執行,並且每次只有一個wait_for_completion在等待,因此對於complete函數也沒有太多的深入瞭解。後面再次需要使用這個功能的時候,想到如果wait_for_completion函數在complete之後執行會出現上面問題?

結論:如果wait_for_completion函數在complete之後執行,那麼執行wait_for_completion函數時,添加就直接滿足,不會再等待complete函數的執行。之所以是這樣,是因爲它實現的機制如下:

complete實現的函數如下:

void complete(struct completion *x)
{
	unsigned long flags;

	spin_lock_irqsave(&x->wait.lock, flags);
	x->done++;            //這個變量很重要
	__wake_up_locked(&x->wait, TASK_NORMAL, 1);
	spin_unlock_irqrestore(&x->wait.lock, flags);
}

wait_for_completion實現如下:

void __sched wait_for_completion(struct completion *x)
{
	wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(wait_for_completion);

static long __sched
wait_for_common(struct completion *x, long timeout, int state)
{
	return __wait_for_common(x, schedule_timeout, timeout, state);
}

static inline long __sched
__wait_for_common(struct completion *x,
		  long (*action)(long), long timeout, int state)
{
	might_sleep();

	spin_lock_irq(&x->wait.lock);
	timeout = do_wait_for_common(x, action, timeout, state);
	spin_unlock_irq(&x->wait.lock);
	return timeout;
}

static inline long __sched
do_wait_for_common(struct completion *x,
		   long (*action)(long), long timeout, int state)
{
	if (!x->done) {
		DECLARE_WAITQUEUE(wait, current);

		__add_wait_queue_tail_exclusive(&x->wait, &wait);
		do {
			if (signal_pending_state(state, current)) {
				timeout = -ERESTARTSYS;
				break;
			}
			__set_current_state(state);
			spin_unlock_irq(&x->wait.lock);
			timeout = action(timeout);
			spin_lock_irq(&x->wait.lock);
		} while (!x->done && timeout);
		__remove_wait_queue(&x->wait, &wait);
		if (!x->done)
			return timeout;
	}
	x->done--;            //complete函數裏面自加的變量
	return timeout ?: 1;
}

通過查看其實現的方式,發現complete實現的原理是:

struct completion {
    unsigned int done;
    wait_queue_head_t wait;
};

通過判斷done的值,來判斷complete是否執行,執行了多少次。

complete函數執行一次,done就加1

wait_for_completion函數執行一次,done就減1

如果done等於0,那麼wait_for_completion函數將一直等待下去。

 

下面附上complete的簡單實用:

struct completion temp_completion;    //定義一個變量
init_completion(&temp_completion);    //初始化變量

complete(&temp_completion);            //發送完成量    喚醒一個等待
wait_for_completion(&temp_completion);    //等待完成量


complete_all(&temp_completion);    //喚醒所有等待
wait_for_completion_timeout(&temp_completion, HZ);    //等待可以超時
wait_for_completion_interruptible(&temp_completion);    //等待可以被中斷
wait_for_completion_interruptible_timeout(&temp_completion);    //等待可以超時、被中斷

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章