完成量用于一个执行单元等待另一个执行单元完成某些工作。强调代码片或执行单元的执行顺序,就用完成量completion。
相关文件#include <linux/wait.h>
1. 定义:
如: struct completion my_completion;
因my_completion是多个执行单元的共享变量,是否在同一个文件中,自行决定要不要定义成static。
/*
* struct completion - structure used to maintain state for a "completion"
*
* This is the opaque structure used to maintain the state for a "completion".
* Completions currently use a FIFO to queue threads that have to wait for
* the "completion" event.
*
* See also: complete(), wait_for_completion() (and friends _timeout,
* _interruptible, _interruptible_timeout, and _killable), init_completion(),
* and macros DECLARE_COMPLETION(), DECLARE_COMPLETION_ONSTACK(), and
* INIT_COMPLETION().
*/
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
2. 初始化:
如: init_completion(&my_completion);
初始化后completion.done为0
/**
* init_completion - Initialize a dynamically allocated completion
* @x: completion structure that is to be initialized
*
* This inline function will initialize a dynamically created completion
* structure.
*/
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}
定义、初始化一起搞定:
如:DECLARE_COMPLETION(my_completion);
/**
* DECLARE_COMPLETION - declare and initialize a completion structure
* @work: identifier for the completion structure
*
* This macro declares and initializes a completion structure. Generally used
* for static declarations. You should use the _ONSTACK variant for automatic
* variables.
*/
#define DECLARE_COMPLETION(work) \
struct completion work = COMPLETION_INITIALIZER(work)
3. 等待
如:wait_for_completion(&my_completion);
wait_for_completion_interruptible(&my_completion);
区别:后者在阻塞等待时可以被信号打断
调用wait_xxx函数时,每调用一次wait,comletion.done就减1,直到0时就阻塞,继续等待其他地方的completion完成的唤醒。
wait_for_completion_killable()可被SIGKILL打断。
unsigned long wait_for_completion_timeout(struct completion *x,unsigned long timeout);超时等待不到就返回
/**
* 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, 0);
}
int wait_for_completion_interruptible(struct completion *x);
4. 唤醒
一般使用时,一个completion被一个执行单元阻塞等待,也有可能会有多个,这个时候complete()一次只能唤醒一个,而complete_all()一次可以唤醒多个等待该completion的执行单元,唤醒次序跟阻塞次序同,即FIFO。
complete()使done加1,而complete_all()将使done设为UINT_MAX/2,这就是为什么可以唤醒所有等待执行单元,除非等待者超过UINT_MAX/2个。
/**
* complete: - signals a single thread waiting on this completion
* @x: holds the state of this particular completion
*
* This will wake up a single thread waiting on this completion. Threads will be
* awakened in the same order in which they were queued.
*
* See also complete_all(), wait_for_completion() and related routines.
*
* It may be assumed that this function implies a write memory barrier before
* changing the task state if and only if any tasks are woken up.
*/
void complete(struct completion *x)
{
unsigned long flags;
spin_lock_irqsave(&x->wait.lock, flags);
x->done++;
__wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);
spin_unlock_irqrestore(&x->wait.lock, flags);
}
void complete_all(struct completion *);
5. 示例
这个示例来自linux 3.4内核中的keyboard/hil_kbd.c。
在初始化时,init_completion,写命令,然后wait_completion,在中断的命令处理函数后会调用completion,使得wait_completion代码的地方返回,这样的过程重复多次,使多个初始化命令完成。
struct hil_dev {
struct input_dev *dev;
struct serio *serio;
/* Input buffer and index for packets from HIL bus. */
hil_packet data[HIL_PACKET_MAX_LENGTH];
int idx4; /* four counts per packet */
/* Raw device info records from HIL bus, see hil.h for fields. */
char idd[HIL_PACKET_MAX_LENGTH]; /* DID byte and IDD record */
char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */
char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */
char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */
/*------->****<-----completion定义*/
struct completion cmd_done;
bool is_pointer;
/* Extra device details needed for pointing devices. */
unsigned int nbtn, naxes;
unsigned int btnmap[7];
};
/*发生中断,会调用命令响应函数hil_dev_handle_command_response,其中会执行completion*/
static irqreturn_t hil_dev_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
//...
hil_dev_handle_command_response(dev);
//...
}
/*命令响应后,会唤醒等待该命令结果的执行单元*/
static void hil_dev_handle_command_response(struct hil_dev *dev)
{
hil_packet p;
char *buf;
int i, idx;
idx = dev->idx4 / 4;
p = dev->data[idx - 1];
switch (p & HIL_PKT_DATA_MASK) {
case HIL_CMD_IDD:
buf = dev->idd;
break;
case HIL_CMD_RSC:
buf = dev->rsc;
break;
case HIL_CMD_EXD:
buf = dev->exd;
break;
case HIL_CMD_RNM:
dev->rnm[HIL_PACKET_MAX_LENGTH] = 0;
buf = dev->rnm;
break;
default:
/* These occur when device isn't present */
if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {
/* Anything else we'd like to know about. */
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
}
goto out;
}
for (i = 0; i < idx; i++)
buf[i] = dev->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_PACKET_MAX_LENGTH; i++)
buf[i] = 0;
out:
/*------->****<-----completion唤醒等待该资源的执行单元*/
complete(&dev->cmd_done);
}
/*连接成功后,多次初始化comletion,即初始化completion.done为0,然后写命令,等待命令执行结果
*可重复初始化,等待,返回
*/
static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
{
//...
/* Get device info. MLC driver supplies devid/status/etc. */
init_completion(&dev->cmd_done);
serio_write(serio, 0);
serio_write(serio, 0);
serio_write(serio, HIL_PKT_CMD >> 8);
serio_write(serio, HIL_CMD_IDD);
error = wait_for_completion_killable(&dev->cmd_done);/*只可被SIGKILL中断,或者有人调用了completion,才能返回*/
if (error)
goto bail1;
init_completion(&dev->cmd_done);
serio_write(serio, 0);
serio_write(serio, 0);
serio_write(serio, HIL_PKT_CMD >> 8);
serio_write(serio, HIL_CMD_RSC);
error = wait_for_completion_killable(&dev->cmd_done);
if (error)
goto bail1;
init_completion(&dev->cmd_done);
serio_write(serio, 0);
serio_write(serio, 0);
serio_write(serio, HIL_PKT_CMD >> 8);
serio_write(serio, HIL_CMD_RNM);
error = wait_for_completion_killable(&dev->cmd_done);
if (error)
goto bail1;
init_completion(&dev->cmd_done);
serio_write(serio, 0);
serio_write(serio, 0);
serio_write(serio, HIL_PKT_CMD >> 8);
serio_write(serio, HIL_CMD_EXD);
error = wait_for_completion_killable(&dev->cmd_done);
if (error)
goto bail1;
//...
}