Linux內核的同步機制:completion

在Linux內核中,completion是一種簡單的同步機制,標誌"things may proceed"。要使用completion,必須在文件中包含<linux/completion.h>,同時創建一個類型爲 structcompletion的變量。這個變量可以靜態地聲明和初始化:

DECLARE_COMPLETION(my_comp);

或者動態初始化:

struct completionmy_comp;

init_completion(&my_comp);

 

如果驅動程序要在執行後面操作之前等待某個過程的完成,它可以調用wait_for_completion ,以要完成的事件爲參數:

void wait_for_completion(struct completion *comp);

如果其它部分代碼可以確定事件已經完成,可以調用下面兩個函數之一來喚醒等待該事件的進程:

void complete(struct completion *comp);

void complete_all(struct completion *comp); /* Linux 2.5.x以上版本 */

 

前一個函數將只喚醒一個等待進程,而後一個函數喚醒等待該事件的所以進程。由於completion的實現方式,即使complete在wait_for_competion之前調用,也可以正常工作。

 

例如,在MD設備驅動程序實現中,有一個恢復線程md_recovery_thread。驅動程序通過md_register_thread和md_unregister_thread來註冊和註銷恢復線程。恢復線程的執行邏輯在md_thread函數中,大致如下:

int md_thread(void * arg)

{

      線程初始化;

      while (運行) {

          處理邏輯;

          接收信號;

      }

      return 0;

}

md_register_thread將創建一個恢復線程,它必須在線程真正初始化結束之後才能返回該線程的指針。因此,其邏輯是:

mdk_thread_t*md_register_thread(void (*run) (void *), void *data, const char *name)

{

      mdk_thread_t *thread;

      ……

      struct completion event;

      /* 爲線程分配空間 */

      thread = (mdk_thread_t *) kmalloc(sizeof(mdk_thread_t), GFP_KERNEL);

      ……

      init_completion(&event);

      ……

      thread->event = &event;

      /* 創建內核線程 */

      ret = kernel_thread(md_thread, thread,0);

      /* 等待線程初始化結束 */

      ……

      wait_for_completion(&event);

      /* 返回線程指針 */

      return thread;

}

而md_unregister_thread通過向線程發送SIGKILL信號註銷恢復線程,它也需要在線程真正退出後才能釋放線程所佔用的內存。因此,其邏輯是:

void md_unregister_thread(mdk_thread_t*thread)

{

      struct completion event;

      init_completion(&event);

      thread->event = &event;

      ……

      /* 向線程發送SIGKILL信號終止其運行 */

      md_interrupt_thread(thread);

      /* 等待線程退出 */

      wait_for_completion(&event);

      /* 釋放線程所佔用的內存 */

      kfree(thread);

}

如果考慮completion,md_thread的邏輯是:

int md_thread(void * arg)

{

      線程初始化;

      complete(thread->event);

      while (運行) {

          處理邏輯;

          接收信號;

      }

      complete(thread->event);

      return 0;

}

需要說明的是,由於等待事件是在驅動程序和恢復線程中的一個共享資源,它必須是一個全局變量,或者如實現代碼中,定義爲一個局部變量,而將其指針放在恢復線程結構中。

typedef struct mdk_thread_s {

      ……

      struct completion *event;

      ……

} mdk_thread_t;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章