a. 完成量結構
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
b. 定義完成量
struct completion my_completion;
c. 初始化完成量
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}
#define init_waitqueue_head(q) \
do { \
static struct lock_class_key __key; \
\
__init_waitqueue_head((q), #q, &__key); \
} while (0)
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
spin_lock_init(&q->lock); // 初始化自旋鎖
lockdep_set_class_and_name(&q->lock, key, name); // 不定義CONFIG_LOCKDEP(死鎖檢測)時,什麼也不做
INIT_LIST_HEAD(&q->task_list); // 初始化 task_let 鏈表頭
}
static inline void reinit_completion(struct completion *x) // 重新初始化一個完成量使之可以再利用
{
x->done = 0;
}
d. 等待完成量
/**
* wait_for_completion: - waits for completion of a task
* @x: holds the state of this particular completion
*
* This waits to be signaled for completion of a specific task. It is NOT
* interruptible and there is no timeout.
*
* See also similar routines (i.e. wait_for_completion_timeout()) with timeout
* and interrupt capability. Also see complete().
*/
void __sched wait_for_completion(struct completion *x) // 無超時時間
{
wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(wait_for_completion);
#define MAX_SCHEDULE_TIMEOUT LONG_MAX
#define LONG_MAX ((long)(~0UL>>1))
#define TASK_UNINTERRUPTIBLE 2 // 任務標誌位,表示不可中斷
/**
* wait_for_completion_timeout: - waits for completion of a task (w/timeout)
* @x: holds the state of this particular completion
* @timeout: timeout value in jiffies
*
* This waits for either a completion of a specific task to be signaled or for a
* specified timeout to expire. The timeout is in jiffies. It is not
* interruptible.
*
* Return: 0 if timed out, and positive (at least 1, or number of jiffies left
* till timeout) if completed.
*/
unsigned long __sched
wait_for_completion_timeout(struct completion *x, unsigned long timeout) // 有超時時間
{
return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(wait_for_completion_timeout);
e. 喚醒完成量
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);
}
EXPORT_SYMBOL(complete);
void complete_all(struct completion *x) // 釋放所有等待同一完成量的執行單元
{
unsigned long flags;
spin_lock_irqsave(&x->wait.lock, flags);
x->done += UINT_MAX/2;
__wake_up_locked(&x->wait, TASK_NORMAL, 0);
spin_unlock_irqrestore(&x->wait.lock, flags);
}
EXPORT_SYMBOL(complete_all);
f. 完成量同於同步的流程:
進程 P1 進程 P2
代碼區C1; wait_for_completion(&done);
complete(&done);
代碼區C2;
2. 相關代碼舉例
代碼位置:drivers/scsi/libsas/sas_expander.c
函數smp_execute_task()中 struct sas_task *task 先建立一個sas_task 並初始化,然後調用wait_for_completion函數
pr_debug("file:%s func:%s line:%d dr->attached_sas_addr = 0x%016llx retry = %d \n",__FILE__, __func__, __LINE__,SAS_ADDR(dr->attached_sas_addr),retry);
wait_for_completion(&task->slow_task->completion);
pr_debug("file:%s func:%s line:%d dr->attached_sas_addr = 0x%016llx retry = %d \n",__FILE__, __func__, __LINE__,SAS_ADDR(dr->attached_sas_addr),retry);
而該完成量在函數 smp_task_done() 中被喚醒
static void smp_task_done(struct sas_task *task)
{
pr_debug("file:%s func:%s line:%d \n",__FILE__, __func__, __LINE__);
if (!del_timer(&task->slow_task->timer))
return;
complete(&task->slow_task->completion);
}
而該函數由中斷處理函數mvs_interrupt()中調用,調用過程:
mvs_interrupt->mvs_94xx_isr()->mvs_int_full()->mvs_int_rx()->mvs_slot_complete()->smp_task_done()