linux完成设备驱动程序,Linux设备驱动程序 之 完成量

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

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

1 #define DECLARE_COMPLETION(work)

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

1 structcompletion my_completion;2 /*初始化函数*/

3 static inline void init_completion(struct completion *x)

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

1 extern void wait_for_completion(struct completion *);2 extern void wait_for_completion_io(struct completion *);3 extern int wait_for_completion_interruptible(struct completion *x);4 extern int wait_for_completion_killable(struct completion *x);5 extern unsigned long wait_for_completion_timeout(struct completion *x,6 unsigned longtimeout);7 extern unsigned long wait_for_completion_io_timeout(struct completion *x,8 unsigned longtimeout);9 extern longwait_for_completion_interruptible_timeout(10 struct completion *x, unsigned longtimeout);11 extern longwait_for_completion_killable_timeout(12 struct completion *x, unsigned longtimeout);13 extern bool try_wait_for_completion(struct completion *x);

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

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

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

1 static inline void reinit_completion(struct completion *x)

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

1 void complete_and_exit(struct completion *comp, long code)

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

1 static int ldlm_pools_thread_main(void *arg)2 {3 struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;4 intc_time;5

6 thread_set_flags(thread, SVC_RUNNING);7 wake_up(&thread->t_ctl_waitq);8

9 CDEBUG(D_DLMTRACE, "%s: pool thread starting, process %d\n",10 "ldlm_poold", current_pid());11

12 while (1) {13 structl_wait_info lwi;14

15 /*

16 * Recal all pools on this tick.17 */

18 c_time =ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);19

20 /*

21 * Wait until the next check time, or until we're22 * stopped.23 */

24 lwi =LWI_TIMEOUT(cfs_time_seconds(c_time),25 NULL, NULL);26 l_wait_event(thread->t_ctl_waitq,27 thread_is_stopping(thread) ||

28 thread_is_event(thread),29 &lwi);30

31 if(thread_test_and_clear_flags(thread, SVC_STOPPING))32 break;33 thread_test_and_clear_flags(thread, SVC_EVENT);34 }35

36 thread_set_flags(thread, SVC_STOPPED);37 wake_up(&thread->t_ctl_waitq);38

39 CDEBUG(D_DLMTRACE, "%s: pool thread exiting, process %d\n",40 "ldlm_poold", current_pid());41

42 complete_and_exit(&ldlm_pools_comp, 0);

43 }

1 static void ldlm_pools_thread_stop(void)2 {3 if (!ldlm_pools_thread)4 return;5

6 thread_set_flags(ldlm_pools_thread, SVC_STOPPING);7 wake_up(&ldlm_pools_thread->t_ctl_waitq);8

9 /*

10 * Make sure that pools thread is finished before freeing @thread.11 * This fixes possible race and oops due to accessing freed memory12 * in pools thread.13 */

14 wait_for_completion(&ldlm_pools_comp);

15 kfree(ldlm_pools_thread);16 ldlm_pools_thread =NULL;17 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值