Linux内核同步机制之completion

原文地址点击打开链接

在Linux内核中,completion是一种简单的同步机制,标志"things may proceed"。

要使用completion,必须在文件中包含<linux/completion.h>,同时创建一个类型为struct completion的变量。

  1. 这个变量可以静态地声明和初始化:  
  2. DECLARE_COMPLETION(my_comp);  
  3. 或者动态初始化:  
  4. struct completion my_comp;  
  5. init_completion(&my_comp);  

如果驱动程序要在执行后面操作之前等待某个过程的完成,它可以调用wait_for_completion ,以要完成的事件为参数:

[html] view plaincopy
  1. void wait_for_completion(struct completion *comp);  

wait_for_completion等待在completion上。如果加了interruptible,就表示线程等待可被外部发来的信号打断;如果加了killable,就表示线程只可被kill信号打断;如果加了timeout,表示等待超出一定时间会自动结束等待,timeout的单位是系统所用的时间片jiffies(多为1ms)。

如果其它部分代码可以确定事件已经完成,可以调用下面两个函数之一来唤醒等待该事件的进程:

  1. void complete(struct completion *comp);  
  2. 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函数中,大致如下:

  1. int md_thread(void * arg)  
  2. {  
  3.     线程初始化;  
  4.     while (运行) {  
  5.         处理逻辑;  
  6.         接收信号;  
  7.     }  
  8.     return 0;  
  9. }  

md_register_thread将创建一个恢复线程,它必须在线程真正初始化结束之后才能返回该线程的指针。因此,其逻辑是:

  1. mdk_thread_t *md_register_thread(void (*run) (void *), void *data, const char *name)  
  2. {  
  3.     mdk_thread_t *thread;  
  4.     ……  
  5.     struct completion event;  
  6.     /* 为线程分配空间 */  
  7.     thread = (mdk_thread_t *) kmalloc (sizeof(mdk_thread_t), GFP_KERNEL);  
  8.     ……  
  9.     init_completion(&event);  
  10.     ……  
  11.     thread->event = &event;  
  12.     /* 创建内核线程 */  
  13.     ret = kernel_thread(md_thread, thread, 0);  
  14.     /* 等待线程初始化结束 */  
  15.     ……  
  16.     wait_for_completion(&event);  
  17.     /* 返回线程指针 */  
  18.     return thread;  
  19. }  


而md_unregister_thread通过向线程发送SIGKILL信号注销恢复线程,它也需要在线程真正退出后才能释放线程所占用的内存。因此,其逻辑是:

  1. void md_unregister_thread(mdk_thread_t *thread)  
  2. {  
  3.     struct completion event;  
  4.     init_completion(&event);  
  5.     thread->event = &event;  
  6.     ……  
  7.     /* 向线程发送SIGKILL信号终止其运行 */  
  8.     md_interrupt_thread(thread);  
  9.     /* 等待线程退出 */  
  10.     wait_for_completion(&event);  
  11.     /* 释放线程所占用的内存 */  
  12.     kfree(thread);  
  13. }  

如果考虑completion,md_thread的逻辑是:

  1. int md_thread(void * arg)  
  2. {  
  3.     线程初始化;  
  4.     complete(thread->event);   
  5.     while (运行) {  
  6.         处理逻辑;  
  7.         接收信号;  
  8.     }  
  9.     complete(thread->event);   
  10.     return 0;  
  11. }  

需要说明的是,由于等待事件是在驱动程序和恢复线程中的一个共享资源,它必须是一个全局变量,或者如实现代码中,定义为一个局部变量,而将其指针放在恢复线程结构中。
typedef struct mdk_thread_s {
    ……
    struct completion *event;
    ……
} mdk_thread_t;


展开阅读全文

Z Shell Completion

03-29

As a Linux user, Whistler has tried several command-line shells. Among these shells, he likes the Z Shell('ZSH' for short) best because ZSH provides more amazing features.nnCommand-line shells usually provide some completion feature. For example, in the directory '/home/whistler', there is only a file named 'document'. Then you can type '/home/whistler/d' and press [TAB] to let the shell complete the word 'document'.nnZSH makes completion more enjoyable, especially for lazy guys. Completion in ZSH can be done using first several letters in each directory. Consider the same situation above, '/home/whistler/document' could be completed using '/h/wh/d' and a single [TAB], if there are no other files or directories with a full path of '/h*/wh*/d*'.nnUnfortunately, there is no ZSH on a remote system used by Whistler. And Whistler does not have enough permission to install ZSH on that system. So he asks you to implement a simple completion program.nnTo simplify the problem, there are several assumptions:nnThe names of directories and files only contain these characters: lower-case letters, numbers and '.'nThe minimum and maximum allowed length of a directory name or a file name are 1 and 32nThe directory separator is '/'nNo more than 11 '/' in the full path of any filenUsers will give full paths (that is, always start from root with a '/', no relative location)nUsers may give full path to a directory or a file and no '/' at the end of any full path (for example, '/h/wh' can be completed to '/home/whistler')nInputnnThis problem contains multi test cases (no more than 4). Please proceed to the end of input.nnThe 1st line only contains an integer N (0 <= N <= 10000).nnFollowing N lines are full paths of directories or files, one per line. It is guaranteed that full path of a directory occurs before files or directories it contains occur. (that is, '/blabla' occurs before any '/blabla/foo' occurs, where 'blabla' may contain one or more '/')nnThe N+2 line only contains an integer M (0 <= M <= 30000).nnFollowing M lines are inputs by users, one per line.nnThere is a blank line after each test case.nnNote that the largest test case is generated randomly, not from an existing file system.nnOutputnnFor each user input, if there is a unique completion, output that completion in one line, without tailing '/'. When there is more than one way or no way to complete, output an integer, which is the count of possible completions in one line.nnSample Inputnn5n/usrn/usr/localn/homen/home/whistlern/home/whon5n/un/homen/u/locn/ho/wn/binnnSample Outputnn/usrn/homen/usr/localn2n0 问答

没有更多推荐了,返回首页