Transferred from: http://blog.csdn.net/batoom/article/details/6298267
Completion is a lightweight mechanism that allows a thread to tell another thread that the work has been done. You can create completion statically using the following macro:
Declare_completion (my_completion);
If the runtime creates completion, it must be dynamically created and initialized in the following ways:
struct Compltion my_completion;
Init_completion (&my_completion);
The relevant definitions of completion are included in the Kernel/include/linux/completion.h:
struct Completion {
unsigned int done;
wait_queue_head_t wait;
};
#define COMPLETION_INITIALIZER (Work)/
{0, __wait_queue_head_initializer (work). WAIT)}
#define DECLARE_COMPLETION (Work)/
struct Completion work = Completion_initializer (work)
static inline void init_completion (struct completion *x)
{
X->done = 0;
Init_waitqueue_head (&x->wait);
}
To wait for completion, the following calls can be made:
void Wait_for_completion (struct completion *c);
To trigger the completion event, call:
void complete (struct completion *c); Wake up a waiting thread
void Complete_all (struct completion *c);//Wake Up all waiting threads
To illustrate how the completion is used, the code for the complete module in the Linux device driver book is summarized below:
/*
* COMPLETE.C--The writers awake the readers
*
* Copyright (C) 2003 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2003 O ' Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* Should list, the code comes from the "Linux Device
* Drivers "by Alessandro Rubini and Jonathan Corbet, published
* by O ' Reilly & Associates. No warranty is attached;
* We cannot take responsibility for errors or fitness for use.
*
* $Id: Complete.c,v 1.2 2004/09/26 07:02:43 Gregkh EXP $
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h> * * Current and everything */
#include <linux/kernel.h>/* PRINTK () */
#include <linux/fs.h>/* Everything ... * *
#include <linux/types.h>/* size_t */
#include <linux/completion.h>
Module_license ("Dual BSD/GPL");
static int complete_major = 253;//Specifies the main device number
Declare_completion (comp);
ssize_t complete_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
; PRINTK (kern_debug "Process%i (%s) going to sleep/n",
current->pid, Current->comm);
wait_for_completion (&comp);
PRINTK (kern_debug "Awoken%i (%s)/n", Current->pid, current- >COMM);
return 0;/* EOF */
}
ssize_t complete_write (struct file *filp, const char __user *buf, size_t count,
loff_t *pos)
{
PRINTK (kern_debug "Process%i (%s) awakening the readers.../n",
Current->pid, Current->comm);
Complete (&COMP);
return count; /* Succeed, to avoid retrial */
}
struct File_operations complete_fops = {
. Owner = This_module,
. Read = Complete_read,
. write = Complete_write,
};
int complete_init (void)
{
int result;
/*
* Register your major, and accept a dynamic number
*/
result = Register_chrdev (Complete_major, "complete", &complete_fops);
if (Result < 0)
return result;
if (Complete_major = = 0)
Complete_major = result; /* Dynamic */
return 0;
}
void Complete_cleanup (void)
{
Unregister_chrdev (Complete_major, "complete");
}
Module_init (Complete_init);
Module_exit (Complete_cleanup);
The module defines a simple completion device: Any process that attempts to read from the device waits until the other device writes to the device. The makefile for compiling this module are as follows:
Obj-m: = COMPLETE.O
Kdir: =/lib/modules/$ (Shell uname-r)/build
PWD: = $ (shell pwd)
Default
$ (make)-C $ (Kdir) m=$ (PWD) modules
Clean
Rm-f *.ko *.O *.MOD.C
Execute the following command in the Linux terminal, compile the build module, and load it dynamically.
#make
#mknod completion C 253 0
#insmod Complete.ko
Open three more terminals, one for the read process:
#cat completion
One for the write process:
#echo >completion
Another view system log:
#tail-F/var/log/messages
It is worth noting that when we use the Complete_all interface, if you want to reuse a completion structure, you must perform a init_completion (struct completion c) to reinitialize it. The definition of this macro can be found in Kernel/include/linux/completion.h:
#define INIT_COMPLETION (x) ((x). done = 0)
The following code makes some changes to the code in the book, the wake-up interface from the original complete to Complete_all, and in order to reuse the completion structure, all the read process is completed after the initialization of the completion structure, the specific code is as follows:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/completion.h>
Module_license ("Dual BSD/GPL");
#undef Kern_debug
#define KERN_DEBUG "<1>"
static int complete_major=253;
static int reader_count = 0;
Declare_completion (comp);
ssize_t complete_read (struct file *filp,char __user *buf,size_t count,loff_t *pos)
{
PRINTK (kern_debug "Process%i (%s) going to sleep,waiting for writer/n", CURRENT->PID,CURRENT->COMM);
reader_count++;
PRINTK (kern_debug "in Read, before Comletion: Reader count =%d/n ", reader_count);
wait_for_completion (&comp);
reader_count--;
PRINTK (kern_debug "awoken%s (%i)/n",current-> COMM,CURRENT->PID);
PRINTK (kern_debug "in Read,after completion: Reader count =%d/n ", reader_count);
/* If you use Complete_all, the completion structure can only be used once, and you must call this macro to reinitialize when you use it again */
if (Reader_count = = 0)
init_completion (comp);
return 0;
}
ssize_t complete_write (struct file *filp,const char __user *buf,size_t count,loff_t *pos)
{
PRINTK (kern_debug "Process%i (%s) awoking the readers.../n", CURRENT->PID,CURRENT->COMM);
PRINTK (kern_debug "in write, before do Complete_all : Reader count =%d/n ", reader_count);
if (reader_count! = 0)
Complete _all (&comp);
PRINTK (kern_debug "in write, after do Complete_ All:reader count =%d/n ", reader_count);
return count;
}
struct File_operations complete_fops={
. Owner = This_module,
. Read = Complete_read,
. write = Complete_write,
};
int complete_init (void)
{
int result;
Result=register_chrdev (Complete_major, "complete", &complete_fops);
if (result<0)
return result;
if (complete_major==0)
Complete_major =result;
PRINTK (kern_debug "complete driver test init! complete_major=%d/n ", complete_major);
PRINTK (kern_debug "static initialization completion/n");
return 0;
}
void Complete_exit (void)
{
Unregister_chrdev (Complete_major, "complete");
PRINTK (kern_debug "complete driver is removed/n");
}
Module_init (Complete_init);
Module_exit (Complete_exit);
Here the test steps are the same as above, except that you need to open several terminals to perform multiple simultaneous read operations.
____________
Resources:
1.Jonathan Corbet Wait, Wei Yongming, etc. linux device Drivers (third edition)
2.Linux Kernel
Analysis of completion interface in Linux driver (wait_for_complete example, very good) "turn"