zoukankan      html  css  js  c++  java
  • Linux设备驱动程序 之 完成量

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

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

    1 #define DECLARE_COMPLETION(work)

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

    1 struct completion 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 long timeout);
     7 extern unsigned long wait_for_completion_io_timeout(struct completion *x,
     8                             unsigned long timeout);
     9 extern long wait_for_completion_interruptible_timeout(
    10     struct completion *x, unsigned long timeout);
    11 extern long wait_for_completion_killable_timeout(
    12     struct completion *x, unsigned long timeout);
    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     int c_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
    ",
    10            "ldlm_poold", current_pid());
    11 
    12     while (1) {
    13         struct l_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're
    22          * 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
    ",
    40            "ldlm_poold", current_pid());
    41 
    42     <strong>complete_and_exit(&ldlm_pools_comp, 0);</strong>
    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 memory
    12      * in pools thread.
    13      */
    14     <strong>wait_for_completion(&ldlm_pools_comp);</strong>
    15     kfree(ldlm_pools_thread);
    16     ldlm_pools_thread = NULL;
    17 }
  • 相关阅读:
    MashupGoogle Map API与饭否API的整合应用
    request Form request QueryString
    .net宏
    仿Google的一个鼠标拖动效果(转)
    保存图片时出现"800700de错误"的解决方法
    收到了csdn寄来的书
    网站可以如此复制?
    关于聚会
    GIS区域空间搜索一个必要的优化
    videobox,一个错误的名字
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11759841.html
Copyright © 2011-2022 走看看