Linux内核同步机制之completion

发表于:2012-3-29 09:57

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:bullbat的专栏

  内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束。这个活动可能是,创建一个新的内核线程或者新的用户空间进程、对一个已有进程的某个请求,或者某种类型的硬件动作,等等。在这种情况下,我们可以使用信号量来同步这两个任务。然而,内核中提供了另外一种机制——completion接口。Completion是一种轻量级的机制,他允许一个线程告诉另一个线程某个工作已经完成。

  结构与初始化

  Completion在内核中的实现基于等待队列(关于等待队列理论知识在前面的文章中有介绍),completion结构很简单:

struct completion {
 unsigned int done;/*用于同步的原子量*/
 wait_queue_head_t wait;/*等待事件队列*/
};

  和信号量一样,初始化分为静态初始化和动态初始化两种情况:

  静态初始化:

#define COMPLETION_INITIALIZER(work) \
 { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }

#define DECLARE_COMPLETION(work) \
 struct completion work = COMPLETION_INITIALIZER(work)

  动态初始化:

static inline void init_completion(struct completion *x)
{
 x->done = 0;
 init_waitqueue_head(&x->wait);
}

  可见,两种初始化都将用于同步的done原子量置位了0,后面我们会看到,该变量在wait相关函数中减一,在complete系列函数中加一。

  实现

  同步函数一般都成对出现,completion也不例外,我们看看最基本的两个complete和wait_for_completion函数的实现。

  wait_for_completion最终由下面函数实现:

static inline long __sched
do_wait_for_common(struct completion *x, long timeout, int state)
{
 if (!x->done) {
  DECLARE_WAITQUEUE(wait, current);

  wait.flags |= WQ_FLAG_EXCLUSIVE;
  __add_wait_queue_tail(&x->wait, &wait);
  do {
   if (signal_pending_state(state, current)) {
    timeout = -ERESTARTSYS;
    break;
   }
   __set_current_state(state);
   spin_unlock_irq(&x->wait.lock);
   timeout = schedule_timeout(timeout);
   spin_lock_irq(&x->wait.lock);
  } while (!x->done && timeout);
  __remove_wait_queue(&x->wait, &wait);
  if (!x->done)
   return timeout;
 }
 x->done--;
 return timeout ?: 1;
}

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号