内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束;这个活动可能是,创建一个新的内核线程或者新的用户空间进程、对一个已有进程的某个请求,或者某种类型的硬件动作等;

内核提供了完成量(completion)来完成上述需求;完成量是一个轻量级的机制,它允许一个线程告诉另一个线程某个工作已经完成;为了使用完成量,代码需要包含<linux/completion.h>;可以利用下面的宏静态的创建和初始化完成量;

 #define DECLARE_COMPLETION(work)

或者使用下面的方法动态的创建和初始化完成量;

 struct completion my_completion;
/* 初始化函数 */
static inline void init_completion(struct completion *x)

需要等待完成,可以调用下面的方法,这些方法都以wait_for_completion开头,区别在于比如是否可以打断,是否提供超时等;

 extern void wait_for_completion(struct completion *);
extern void wait_for_completion_io(struct completion *);
extern int wait_for_completion_interruptible(struct completion *x);
extern int wait_for_completion_killable(struct completion *x);
extern unsigned long wait_for_completion_timeout(struct completion *x,
unsigned long timeout);
extern unsigned long wait_for_completion_io_timeout(struct completion *x,
unsigned long timeout);
extern long wait_for_completion_interruptible_timeout(
struct completion *x, unsigned long timeout);
extern long wait_for_completion_killable_timeout(
struct completion *x, unsigned long timeout);
extern bool try_wait_for_completion(struct completion *x);

实际的完成事件触发则通过调用下面函数之一来完成;

 extern void complete(struct completion *);
extern void complete_all(struct completion *);

这两个函数在是否有多个线程在等待相同的完成事件上有所不同,complete只会唤醒一个等待线程,而complete_all允许唤醒所有等待线程;大多数情况下,只会有一个等待者,因此这两个函数产生相同的结果;一个完成量通常是一个单次设备,也就是说,它只会被使用一次后就被丢弃;但是,完成量结构也可以重复使用,如果没有使用complete_all,则我们可以重复使用一个完成量结构,只要那个将要触发的事件是明确的,就不会有问题;但是如果使用了complete_all,则必须在重新使用该结构之前重新对它进行初始化;下面函数用来快速进行重新初始化;

 static inline void reinit_completion(struct completion *x)

完成量的典型使用是在模块退出时的内核线程终止;在这种原型中,某些驱动程序的内部工作由一个内核线程在while (1)循环中完成,当内核准备清除该模块时,exit函数会告诉该线程退出并等待完成量;为了实现这个目的,内核包含了可用于这种线程的一个特殊函数;

 void complete_and_exit(struct completion *comp, long code)

比如内核中下面代码就说明这种场景:

 static int ldlm_pools_thread_main(void *arg)
{
struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
int c_time; thread_set_flags(thread, SVC_RUNNING);
wake_up(&thread->t_ctl_waitq); CDEBUG(D_DLMTRACE, "%s: pool thread starting, process %d\n",
"ldlm_poold", current_pid()); while () {
struct l_wait_info lwi; /*
* Recal all pools on this tick.
*/
c_time = ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT); /*
* Wait until the next check time, or until we're
* stopped.
*/
lwi = LWI_TIMEOUT(cfs_time_seconds(c_time),
NULL, NULL);
l_wait_event(thread->t_ctl_waitq,
thread_is_stopping(thread) ||
thread_is_event(thread),
&lwi); if (thread_test_and_clear_flags(thread, SVC_STOPPING))
break;
thread_test_and_clear_flags(thread, SVC_EVENT);
} thread_set_flags(thread, SVC_STOPPED);
wake_up(&thread->t_ctl_waitq); CDEBUG(D_DLMTRACE, "%s: pool thread exiting, process %d\n",
"ldlm_poold", current_pid()); <strong>complete_and_exit(&ldlm_pools_comp, );</strong>
}
 static void ldlm_pools_thread_stop(void)
{
if (!ldlm_pools_thread)
return; thread_set_flags(ldlm_pools_thread, SVC_STOPPING);
wake_up(&ldlm_pools_thread->t_ctl_waitq); /*
* Make sure that pools thread is finished before freeing @thread.
* This fixes possible race and oops due to accessing freed memory
* in pools thread.
*/
<strong>wait_for_completion(&ldlm_pools_comp);</strong>
kfree(ldlm_pools_thread);
ldlm_pools_thread = NULL;
}

最新文章

  1. OSI7层模型详解
  2. div嵌套导致子区域margin-top失效不起作用的解决方法
  3. Python从零开始(1)新手常问
  4. windows上JSP开发环境全搭建
  5. Android上实现仿IOS弹性ScrollView
  6. NDN路由--OSPFN安装与配置
  7. Spring 的优秀工具类盘点第 2 部分
  8. Android应用开发中webview上传文件的几种思路
  9. 改变DM6467的内存划分
  10. socket select模型
  11. 使用dynamic特性处理XML文档
  12. Spring学习——从入门到精通
  13. delphi 10.1 Berlin 中使用自带的 Base64 编码
  14. badboy安装及使用
  15. 高可用性的负载均衡方案之lvs+keepalived和haproxy+heartbeat区别
  16. centos7.4 调整根目录大小
  17. Ubuntu 18.04 安装部署Net Core、Nginx全过程
  18. 【Java基本功】一文读懂String及其包装类的实现原理
  19. 一个生产可用的mysql参数文件my.cnf
  20. Lintcode: Find Peak Element

热门文章

  1. Swagger学习(四、配置API文档的分组)
  2. Oracle学习笔记:rank、dense_rank、row_number、ntile等排序算法
  3. LeetCode:196.删除重复的电子邮箱
  4. navigateTo防止多次跳转
  5. 使用Eclipse开发Java应用并部署到SAP云平台SCP上去
  6. python3学习特性
  7. 解决No module named &#39;sklearn.cross_validation&#39;
  8. macos下简单的socket服务器+客户端
  9. Python 实现快递查询
  10. angular reactive form