2016年10月26日 星期三

Linux kernel - wait_event_interruptible 用法

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

沒有留言:

張貼留言