linux驱动程序中可以使用的同步机制有很多,这里只介绍complete机制。
1. 什么是complete?
completion,它用于一个执行单元等待另一个执行单元执行完某事。Linux系统中与completion相关的操作主要有以下4种:
(1) 定义completion
struct completion my_completion;
(2) 初始化completion
init_completion(&my_completion);
对my_completion的定义和初始化可以通过如下快捷方式实现
DECLEARE_COMPLETION(my_completion);
(3) 等待completion
void wait_for_completion(struct completion *c);
(4) 唤醒completion
void complete(struct completion *c);
void complete_all(struct completion *c);
前者只唤醒一个等待的执行单元,后者唤醒所有等待同一completion的执行单元。
2. complete的原理
- 初始化complete时对done变量和队列进行初始化。
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_swait_head(&x->wait);
}
- 在complete函数中会累计产生complete的次数,并基于此次数对后续进行唤醒操作。
void complete(struct completion *x)
{
unsigned long flags;
raw_spin_lock_irqsave(&x->wait.lock, flags);
x->done++; //累计complete执行了多少次
__swait_wake_locked(&x->wait, TASK_NORMAL, 1);
raw_spin_unlock_irqrestore(&x->wait.lock, flags);
}
EXPORT_SYMBOL(complete);
- 在唤醒操作时,每唤醒一次,就将done减1,直到done为0时,线程就会一直处于等到阻塞状态。
do_wait_for_common(struct completion *x,
long (*action)(long), long timeout, int state)
{
if (!x->done) {
DEFINE_SWAITER(wait);
swait_prepare_locked(&x->wait, &wait);
do {
if (signal_pending_state(state, current)) {
timeout = -ERESTARTSYS;
break;
}
__set_current_state(state);
raw_spin_unlock_irq(&x->wait.lock);
timeout = action(timeout);
raw_spin_lock_irq(&x->wait.lock);
} while (!x->done && timeout);
swait_finish_locked(&x->wait, &wait);
if (!x->done)
return timeout;
}
x->done--; //每唤醒一次等待的线程,就自减一次
return timeout ?: 1;
}
3. 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); //等待可以超时、被中断