分类:
Linux Kernel
2009-03-11 17:16
在Linux内核
中,completion是一种简单的同步机制,标志"things may
proceed"。要使用completion,必须在文件中包含<linux/completion.h>,同时创建一个类型为
struct completion的变量。这个变量可以静态地声明和初始化:
DECLARE_COMPLETION(my_comp); 或者动态初始化: struct completion my_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; |
|