Linux completion完成量说明

mac2022-06-30  21

completion是内核中的一种同步机制,该机制主要借助等待队列实现同步,该同步机制是一种简单的同步机制。4

 

下面简要分析下该同步机制的实现(本次源码基于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的实现已在下面的流程中有介绍。

 

 

 

 

四、完成接口

完成接口的定义比较简单,就是增加done变量的计数,并调用__wake_up_common,唤醒等待队列。而__wake_up_common与__wait_common是相对应的,具体实现唤醒操作,此处没有再深入分析。

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); }

 

而complete_all则是唤醒该completion上所有等待的线程,此处将done值设置为UINT_MAX/2

/**  * complete_all: - signals all threads waiting on this completion  * @x:  holds the state of this particular completion  *  * This will wake up all threads waiting on this particular completion event.  *  * 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 (struct completion *x) { unsigned long flags; spin_lock_irqsave(&x->wait.lock, flags); x->done += UINT_MAX/2; __wake_up_common(&x->wait, TASK_NORMAL, 0, 0, NULL); spin_unlock_irqrestore(&x->wait.lock, flags); }

 

本文简单介绍了completion机制,主要是最近在看devtmpfs模块的代码时,看到了completion的应用,此处先记录下这个同步机制的实现说明。

最新回复(0)