完成变量(一种简单的信号量)

struct completion:

有的时候我们需要在一个线程里面发起另外一个线程里的某些动作,然后等待另外一个线程的动作完成.这个我们可以用completion.这是信号量的一种简单实现.

完成变量是信号量的一种简单的实现。当一个任务运行需要请求某个资源或条件的情况下, wait_for_completion() 函数将此任务放入等待队列,等待。另外一个任务使用完这个资源通过 complete() 函数发送一个完成变量,通知等待队列中的这个任务继续执行。

 

完成变量的实现函数

 

struct completion {

unsigned int done;

wait_queue_head_t wait;

};

 

void fastcall __sched wait_for_completion(struct completion *x)

{

might_sleep();

 

spin_lock_irq(&x->wait.lock);

if (!x->done) {

DECLARE_WAITQUEUE(wait, current);

 

wait.flags |= WQ_FLAG_EXCLUSIVE;

__add_wait_queue_tail(&x->wait, &wait);

do {

__set_current_state(TASK_UNINTERRUPTIBLE);

spin_unlock_irq(&x->wait.lock);

schedule();

spin_lock_irq(&x->wait.lock);

} while (!x->done);

__remove_wait_queue(&x->wait, &wait);

}

x->done–;

spin_unlock_irq(&x->wait.lock);

}

 

 

void fastcall complete(struct completion *x)

{

unsigned long flags;

 

spin_lock_irqsave(&x->wait.lock, flags);

x->done++;

__wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,

1, 0, NULL);

spin_unlock_irqrestore(&x->wait.lock, flags);

}

 

 

完成变量的使用举例

 

demo 程序

 

/*

* chardev.c: Creates a read-only char device that says how many times

* you’ve read from the dev file

*/

 

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

/* for put_user */

#include <linux/completion.h>

 

#if 1

static int device_open(struct inode *, struct file *);

static int device_release(struct inode *, struct file *);

static ssize_t device_read(struct file *, char *, size_t, loff_t *);

static ssize_t device_write(struct file *, const char *, size_t, loff_t *);

#endif

#define SUCCESS 0

#define DEVICE_NAME “chardev”

/* Dev name as it appears in /proc/devices   */

//#define BUF_LEN 80

 

MODULE_LICENSE(“GPL”);

MODULE_AUTHOR(“Edwin”);

 

static int Major;

//struct completion mr_completion;

//init_completion(&mr_completion);

 

DECLARE_COMPLETION(mr_completion);

 

//struct completion mr_completion;

 

 

 

static struct file_operations fops = {

.read = device_read,

.write = device_write,

.open = device_open,

.release = device_release

};

 

/*

* Functions

*/

 

int completion_init(void)

{

Major = register_chrdev(0, DEVICE_NAME, &fops);

 

if (Major < 0) {

printk(“Registering the character device failed with %d/n”,

Major);

return Major;

}

#if 1

printk(“<1>I was assigned major number %d.  To talk to/n”, Major);

printk(“<1>the driver, create a dev file with/n”);

printk(“‘mknod /dev/hello c %d 0’./n”, Major);

printk(“<1>Try various minor numbers.  Try to cat and echo to/n”);

printk(“the device file./n”);

printk(“<1>Remove the device file and module when done./n”);

#endif

return 0;

}

 

void completion_exit(void)

{

/*

* Unregister the device

*/

int ret = unregister_chrdev(Major, DEVICE_NAME);

if (ret < 0)

printk(“Error in unregister_chrdev: %d/n”, ret);

else

printk(“The %s moudle is released./n”,DEVICE_NAME);

}

 

module_init(completion_init);

module_exit(completion_exit);

 

/*

* Methods

*/

 

/*

* Called when a process tries to open the device file, like

* “cat /dev/mycharfile”

*/

static int device_open(struct inode *inode, struct file *file)

{

 

try_module_get(THIS_MODULE);

 

return SUCCESS;

}

 

/*

* Called when a process closes the device file.

*/

static int device_release(struct inode *inode, struct file *file)

{

 

/*

* Decrement the usage count, or else once you opened the file, you’ll

* never get get rid of the module.

*/

module_put(THIS_MODULE);

 

return SUCCESS;

}

 

/*

* Called when a process, which already opened the dev file, attempts to

* read from it.

*/

static ssize_t device_read(struct file *filp,

/* see include/linux/fs.h   */

 

char *buffer,

size_t length,

loff_t * offset)

{

 

printk(“<1>the current process %i %s will sleep at once./n”, current->pid, current->comm);

 

 

wait_for_completion(&mr_completion);

printk(“<1>the completion sig is released……………………………/n”);

//printk(“<1> device_read operation is executed/n”);

 

return 0;

 

}

 

/* 

* Called when a process writes to dev file: echo “hi” > /dev/hello

*/

static ssize_t

device_write(struct file *filp, const char *buff, size_t len, loff_t * off)

{

printk(“<1>the echo operation is executing /n”);

 

complete(&mr_completion);

printk(“<1>the completion sig  is launched /n”);

 

//printk(“<1>Sorry, this operation isn’t supported./n”);

//return -EINVAL;

}

分享到: 

点赞