1. 基础知识
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()