completion是内核中的一种同步机制,该机制主要借助等待队列实现同步,该同步机制是一种简单的同步机制。
下面简要分析下该同步机制的实现(本次源码基于linux 3.10)。
一、结构体说明
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
主要包括等待队列头以及完成量统计值done变量。
而针对等待队列头的结构体,主要包含自旋锁与链表。
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
二、completion的初始化
主要包括宏初始化与函数初始化两种方式
2.1宏初始化
宏初始化定义如下所示,主要是将done变量设置为0,并调用静态初始化等待队列头的宏
__WAIT_QUEUE_HEAD_INITIALIZER
#define COMPLETION_INITIALIZER(work) \
{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
2.2函数初始化
该接口逻辑简单,代码如下
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}
三、等待接口
该接口名称wait_for_completion,主要调用wait_for_common,而wait_for_common则主要是将当前线程加入等待队列,然后调用schedule将
自己调度出去,等到被唤醒后,则判断done变量是否大于0,若大于0则返回,否则继续等待,直至done变为1。
void __sched wait_for_completion(struct completion *x)
{
wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
关于wait_for_completion的调用流程图如下所示,针对completion来说,其虽然调用了__wait_for_common,但其并没有使用超时返回的操作,具体可通过schedule_timeout的实现确定,关于schedule_timeout的实现已在下面的流程中有介绍。