init_waitqueue_head
wait_event_interruptible
wake_up_interruptible
include/linux/wait.h
/*
* The below macro ___wait_event() has an explicit shadow of the __ret
* variable when used from the wait_event_*() macros.
*
* This is so that both can use the ___wait_cond_timeout() construct
* to wrap the condition.
*
* The type inconsistency of the wait_event_*() __ret variable is also
* on purpose; we use long where we can return timeout values and int
* otherwise.
*/
#define ___wait_event(wq, condition, state, exclusive, ret, cmd) \
({ \
__label__ __out; \
wait_queue_t __wait; \
long __ret = ret; /* explicit shadow */ \
\
INIT_LIST_HEAD(&__wait.task_list); \
if (exclusive) \
__wait.flags = WQ_FLAG_EXCLUSIVE; \
else \
__wait.flags = 0; \
\
for (;;) { \
long __int = prepare_to_wait_event(&wq, &__wait, state);\
\
if (condition) \
break; \
\
if (___wait_is_interruptible(state) && __int) { \
__ret = __int; \
if (exclusive) { \
abort_exclusive_wait(&wq, &__wait, \
state, NULL); \
goto __out; \
} \
break; \
} \
\
cmd; \
} \
finish_wait(&wq, &__wait); \
__out: __ret; \
})
#define __wait_event_interruptible(wq, condition) \
___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \
schedule())
/**
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible(wq, condition); \
__ret; \
})
wait_event_interruptible和wake_up_interruptible小例子:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
MODULE_LICENSE("Dual BSD/GPL");
unsigned int globalvar = 0;
wait_queue_head_t myqueue;
unsigned int flag = 0;
static ssize_t myread(struct file *file, char *buf, size_t size, loff_t *loff)
{
wait_event_interruptible(myqueue , flag != 0);
if(copy_to_user(buf, &globalvar, sizeof(int)))
{
printk("copy to user failed/n");
return -EFAULT;
}
flag = 0;
return sizeof(int);
}
static ssize_t mywrite(struct file *file, const char *buf, size_t size, loff_t *loff)
{
if(copy_from_user(&globalvar, buf, sizeof(int)))
{
printk("copy from user failed/n");
return -EFAULT ;
}
wake_up_interruptible(&myqueue);
flag = 1;
return sizeof(int);
}
static const struct file_operations fops = {
.read = myread,
.write = mywrite
};
static int __init mod_init(void)
{
int ret;
ret = register_chrdev(133 , "mychar", &fops);
if(ret < 0)
printk("<0>""register char dev failed/n");
init_waitqueue_head(&myqueue);
return 0;
}
static void __exit mod_exit(void)
{
unregister_chrdev(133, "mychar");
}
module_init(mod_init);
module_exit(mod_exit);
參考來源
http://blog.sina.com.cn/s/blog_4770ef020101h45d.html