Linux内核完成量机制

struct completion {
	unsigned int done;
	wait_queue_head_t wait;
};

int mdss_mdp_wfd_wait_for_finish(struct mdss_mdp_wfd *wfd)
{
	int ret;
	init_completion(&wfd->comp); // 初始化完成量
	ret = wait_for_completion_timeout(&wfd->comp,     // 等待wfd->comp的complete函数执行,将以等待队列项为载体放在wfd->comp的等待队列头中的current进程唤醒
				msecs_to_jiffies(WFD_TIMEOUT_IN_MS))
	return ret;
}

void mdss_mdp_wfd_remove_data(struct mdss_mdp_wfd *wfd,
	struct mdss_mdp_wfd_data *wfd_data)
{
	mutex_lock(&wfd->lock);
	list_del_init(&wfd_data->next);
	if (list_empty(&wfd->data_queue))
		complete(&wfd->comp); // 当data_queue为空时,执行完成函数,唤醒睡眠在完成量的等待队列头上的进程
	mutex_unlock(&wfd->lock);
	mdss_mdp_data_free(&wfd_data->data, true, DMA_FROM_DEVICE);
	kfree(wfd_data);
}

第一部分 init_completion 初始化完成量

static inline void init_completion(struct completion *x)
    {
    	x->done = 0;    // done 标志位初始化为0
    	init_waitqueue_head(&x->wait);  // 初始化 completion中的等待队列头
    }

第二部分 wait_for_completion_timeout 等待完成

     unsigned long __sched  wait_for_completion_timeout(struct completion *x, unsigned long timeout)
    {
    	return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE); // TASK_UNINTERRUPTIBLE不可被信号中断
    }
    
 
     static long __sched  wait_for_common(struct completion *x, long timeout, int state)
    {
    	return __wait_for_common(x, schedule_timeout, timeout, state);  // schedule_timeout用来让出cpu,当指定时间过后或指定时间内该进程被唤醒,则重新运行此进程
    }
    
 
   static inline long __sched    __wait_for_common(struct completion *x,
    		  long (*action)(long), long timeout, int state)
    {
    	might_sleep();
    
    	spin_lock_irq(&x->wait.lock);
    	timeout = do_wait_for_common(x, action, timeout, state); // action即为 schdule_timeout
    	spin_unlock_irq(&x->wait.lock);
    	return timeout;
    }
    
   
     static inline long __sched do_wait_for_common(struct completion *x,
    		   long (*action)(long), long timeout, int state)
    {
    	if (!x->done) {
    		DECLARE_WAITQUEUE(wait, current);  // 初始化1个等待队列项,内含current进程指针和默认的唤醒current进程的函数
    
    		__add_wait_queue_tail_exclusive(&x->wait, &wait); // 将此等待队列项加入完成量中的等待队列头中
    		do {
    			if (signal_pending_state(state, current)) {
    				timeout = -ERESTARTSYS;
    				break;
    			}
    			__set_current_state(state); // 设置当前进程状态为TASK_UNINTERRUPTIBLE)
    			spin_unlock_irq(&x->wait.lock);
    			timeout = action(timeout);  // 让出cpu
    			spin_lock_irq(&x->wait.lock);
    		} while (!x->done && timeout);  // 只有在执行了complete函数(将x->done++)或者超时才会退出此循环,否则,每次调度回来后,都会被重新调度出去
    		__remove_wait_queue(&x->wait, &wait); // 被唤醒后,把含有当前进程的等待队列项从完成量的等待队列头中删除
    		if (!x->done)
    			return timeout;
    	}
    	x->done--;  // x->done恢复初始值
    	return timeout ?: 1;
    }

第三部分 complete执行完成函数

void complete(struct completion *x)
{
	unsigned long flags;

	spin_lock_irqsave(&x->wait.lock, flags);
	x->done++; // 保证睡眠的进程唤醒后能退出 do .. while 循环
	__wake_up_locked(&x->wait, TASK_NORMAL, 1);
	spin_unlock_irqrestore(&x->wait.lock, flags);
}
void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr)
{
	__wake_up_common(q, mode, nr, 0, NULL); // mode为TASK_NORMAL
}

static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
			int nr_exclusive, int wake_flags, void *key)
{
	wait_queue_t *curr, *next;

	list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
		unsigned flags = curr->flags;  

		if (curr->func(curr, mode, wake_flags, key) &&    // 对等待队列上睡眠的每个进程,执行对应等待队列项上的唤醒函数,此处一般为默认唤醒函数,并设置进程状态为TASK_NORMAL
				(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
			break;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值