并发控制____完成量(comletion)

 

    完成量用于一个执行单元等待另一个执行单元完成某些工作。强调代码片或执行单元的执行顺序,就用完成量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;
		
//...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值