精华内容
下载资源
问答
  • Linux阻塞控制 wait_eventwait_event_interruptible函数详解最近研究了一下linux驱动对进程的阻塞与非阻塞的控制,感觉linux对进程的控制真的是牛逼,各种进程的状态都会有相应的控制方案来解决,开始慢慢感受到...

    Linux阻塞控制 wait_event与wait_event_interruptible函数详解

    最近研究了一下linux驱动对进程的阻塞与非阻塞的控制,感觉linux对进程的控制真的是牛逼,各种进程的状态都会有相应的控制方案来解决,开始慢慢感受到linux的博大精深了。

    1、  引入阻塞的必要性

    刚开始学习阻塞时一直都会有疑惑,为什么需要引入阻塞,同样是等待信号,将当前线程休眠,那信号量与wait_event这样的阻塞有什么样的区别呢。

    down(struct semaphore * sem)

    wait_event_interruptible(wq, condition, ret)

    我自己总结了一下,主要是由如下几个区别和联系,

    a、  进程控制的思想一样,都是通过对信号的控制来实现不同进程之间的控制,区别在于互斥锁之类的控制是直接使用linux进行规范化的信号量sem来操作,而阻塞控制则是通过对自定义的标记符condition来进行控制。

    b、  休眠的机制是一样的,都是通过wait_queue来进行任务休眠。

    c、  具体实现机制的区别,互斥锁等是通过信号量来控制进程,而信号量是有限资源,从而导致拥有信号量的各个进程是存在竞争关系的;阻塞机制则是通过触发唤醒实现的,这个触发信号是无限的。各个进程不存在竞争关系,只有触发与被触发的关系,而被触发的各个进程之间是平行的。

    可以用比赛关系来形象表示这两者的区别:

    赛场上进行比赛,每个人必须拿到接力棒才能开始跑,跑的人跑完一圈之后,再将接力棒交给另外的人,另外的人才能开始跑。这是信号量的工作机制,必须拿到信号才能进行进程。而同时进行的进程是有限的。跑的人与没有跑的人之间是互斥的。

    进行比赛时,一堆人在准备跑等待发号施令,当鸣枪声想起时就开始跑,跑完之后再等待鸣枪声。这就是阻塞的工作机制,被触发的进程可以无限制,相互之间没有竞争关系,只有触发被触发关系。

    2、下面来分析wait_event_interruptible的源代码

    #definewait_event_interruptible(wq, condition)

    ({

    int __ret = 0;

    if (!(condition))

    //第一次执行,如果condition不满足,进入下一步,如果condition满足的话,函数不会进入休眠,直接执行过去,而不是进入休眠后再检测condition,然后再唤醒。

    __wait_event_interruptible(wq,condition, __ret);

    __ret;

    //宏函数返回值,最后一个式子

    })

    #define__wait_event_interruptible(wq, condition, ret)

    do {

    DEFINE_WAIT(__wait);

    for (;;) {

    prepare_to_wait(&wq, &__wait,TASK_INTERRUPTIBLE);

    //将当前进程加入到wq这一个等待序列当中,并将进程设置为INTERRUPTIBLE

    if (condition)

    break;

    //如果condition满足直接跳出操作,执行finish_wait,结束等待,而不会进行进程调度

    if (!signal_pending(current)) {

    //检测当前进程是否有信号处理,返回非0表示

    有信号处理,即这里是如果没有信号处理,则进入下一步,

    schedule();

    //进行进程调度,将当前进程从runqueue中删除,此时该进程在此处休眠,schedule不返回,不再往下执行;只有当wake_up函数将该进程的状态设为可运行时,该进程才能重新进入运行序列,schedule()顺利返回,继续往下执行

    continue; }

    //直接进入到for (;;)的下一个循环,检测condition是否满足要求,如果满足,跳出for循环,跳到finish_wait,如果不满足,则继续进行进行调度。

    ret = -ERESTARTSYS;

    break;

    }

    finish_wait(&wq, &__wait);

    //将当前进程从wq等待队列中删除

    } while (0)

    展开全文
  • static int key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { wait_event_interruptible(key_wait, !is_key_buf_empty()); g_key_value = get_key(); copy_to_user(buf, &g_...

    一、 poll()函数

    应用层使用select()和poll()系统函数查询是否可对设备进行无阻塞的访问时,会引发设备驱动中的poll()函数被执行。看一个例子:
    应用层代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <poll.h>
    
    /*
     * ./keyTest /dev/my_key0
     *
     */
    int main(int argc, char **argv)
    {
    	int fd;
    	int val;
    	struct pollfd fds[1];
    	int timeout_ms = 5000;
    	int ret;
    	
    	/* 1. 判断参数 */
    	if (argc != 2) 
    	{
    		printf("Usage: %s <dev>\n", argv[0]);
    		return -1;
    	}
    
    	/* 2. 打开文件 */
    	fd = open(argv[1], O_RDWR);
    	if (fd == -1)
    	{
    		printf("can not open file %s\n", argv[1]);
    		return -1;
    	}
    
    	fds[0].fd = fd;
    	fds[0].events = POLLIN;
    	
    
    	while (1)
    	{
    		/* 3. 读文件 */
    		ret = poll(fds, 1, timeout_ms);
    		if ((ret == 1) && (fds[0].revents & POLLIN))
    		{
    			read(fd, &val, 4);
    			printf("get button : 0x%x\r\n", val);
    		}
    		else
    		{
    			printf("timeout\r\n");
    		}
    	}
    	
    	close(fd);
    	
    	return 0;
    }
    

    当应用层执行到**ret = poll(fds, 1, timeout_ms)**这句时最终会调用对应驱动文件中的poll函数。
    by 面朝大海0902

    二、驱动文件中poll()函数及poll_wait()函数

    我们还是以一个例子说明下,驱动文件代码片段如下:

    static unsigned int key_drv_poll(struct file *fp, poll_table * wait)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &key_wait, wait);//非阻塞函数
    	
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static struct file_operations key_drv =
    {
    	.owner = THIS_MODULE,
    	.read  = key_drv_read,
    	.poll  = key_drv_poll,
    };
    

    这里file_operations结构体中的poll成员就是上面我们说的驱动文件的poll函数,poll函数一个核心就是**poll_wait()**函数,这个函数是一个非阻塞函数,这点非常重要,很多人看到函数里面有个wait关键字以为执行到这里会堵塞住,其实不对。

    static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
    {
    	if (p && p->_qproc && wait_address)
    		p->_qproc(filp, wait_address, p);
    }
    

    使用这个函数一般要配合等待队列使用,poll_wait()函数的作用是将对应的等待队列头添加到poll_table,有人会问如果驱动的poll()函数不调用poll_wait(),即屏蔽掉该行会怎么样?答案是应用层poll函数会一直休眠下去直到它超时,可以参考下面第四节实验验证部分。
    原因这里可以简单说下,以按键驱动为例,按键按下触发中断,按键值被更新,屏蔽掉poll_wait()后,应用进程还是一直在休眠状态无法立即从休眠状态变为可执行态并被调度执行,直到poll函数超时。
    by 面朝大海0902

    三、等待队列

    DECLARE_WAIT_QUEUE_HEAD() —创建等待队列头;
    wake_up_interruptible() —将等待队列中的进程变为可运行态,具体进程什么时候被执行,取决于调度程序;
    wait_event_interruptible(wq, condition) —使调用进程在等待队列上睡眠,直到满足给定condition条件为止;

    static DECLARE_WAIT_QUEUE_HEAD(key_wait);
    

    驱动程序开始我们会创建等待队列

    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    	int value;
    	struct gpio_key *ptr_gpio_key_temp = dev_id;
    	value = gpiod_get_value(ptr_gpio_key_temp->gpiod);
    	g_key_value = (ptr_gpio_key_temp->gpio << 8) | value;
    	printk(KERN_INFO "g_key_value is %d \r\n", g_key_value);
    	put_key(g_key_value);
    	wake_up_interruptible(&key_wait);
    	return IRQ_HANDLED;
    }
    

    当按键的GPIO被按下以后中断函数被执行,我们通过wake_up_interruptible()将等待队列中的进程变为可运行态,这样刚才调用poll_wait()函数其对应的应用进程才会被调度执行。

    static int key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	wait_event_interruptible(key_wait, !is_key_buf_empty());
    	g_key_value = get_key();
    	copy_to_user(buf, &g_key_value, 4);
    	return 4;
    }
    

    驱动read函数读取按键值,我们使用wait_event_interruptible()使进程在不满足条件condition时休眠
    by 面朝大海0902
    完整驱动demo我们贴出来,demo里面有2个key键,不同开发板key键的GPIO配置不相同(环形缓冲区部分与本文讨论的内容没有关系,参考了成熟代码)

    #include <linux/module.h>
    #include <linux/poll.h>
    
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/miscdevice.h>
    #include <linux/kernel.h>
    #include <linux/major.h>
    #include <linux/mutex.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h>
    #include <linux/stat.h>
    #include <linux/init.h>
    #include <linux/device.h>
    #include <linux/tty.h>
    #include <linux/kmod.h>
    #include <linux/gfp.h>
    #include <linux/gpio/consumer.h>
    #include <linux/platform_device.h>
    #include <linux/of_gpio.h>
    #include <linux/of_irq.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    #include <linux/slab.h>
    
    struct gpio_key{
    	int gpio;
    	struct gpio_desc *gpiod;
    	int flag;
    	int irq;
    };
    
    static struct gpio_key *ptr_gpio_key;
    
    static int major =0;
    static struct class *key_class;
    static int g_key_value = 0;
    
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static int g_keys[BUF_LEN];
    static int r, w;
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(int key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static int get_key(void)
    {
    	int key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    static DECLARE_WAIT_QUEUE_HEAD(key_wait);
    
    static int key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	wait_event_interruptible(key_wait, !is_key_buf_empty());
    	g_key_value = get_key();
    	copy_to_user(buf, &g_key_value, 4);
        printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	return 4;
    }
    
    
    static unsigned int key_drv_poll(struct file *fp, poll_table * wait)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &key_wait, wait);//非阻塞函数
    	
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static struct file_operations key_drv =
    {
    	.owner = THIS_MODULE,
    	.read  = key_drv_read,
    	.poll  = key_drv_poll,
    };
    
    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    	int value;
    	struct gpio_key *ptr_gpio_key_temp = dev_id;
    	value = gpiod_get_value(ptr_gpio_key_temp->gpiod);
    	g_key_value = (ptr_gpio_key_temp->gpio << 8) | value;
    	printk(KERN_INFO "g_key_value is %d \r\n", g_key_value);
    	put_key(g_key_value);
    	wake_up_interruptible(&key_wait);
    	return IRQ_HANDLED;
    }
    
    static int key_probe(struct platform_device *pdev)
    {
    	int count = 0;
    	int i=0;
    	enum of_gpio_flags flag;
    	struct device_node *node = pdev->dev.of_node;
    	
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	count = of_gpio_count(node);
    	ptr_gpio_key = kzalloc(sizeof(struct gpio_key)*count, GFP_KERNEL);
    	
    	for(i=0;i<count;i++)
    	{
    		ptr_gpio_key[i].gpio = of_get_gpio_flags(node, i, &flag);
    		if(ptr_gpio_key[i].gpio < 0)
    		{
    			printk(KERN_ERR "of_get_gpio_flags is err\r\n");
    		}
    		ptr_gpio_key[i].gpiod = gpio_to_desc(ptr_gpio_key[i].gpio);
    		ptr_gpio_key[i].flag = flag & OF_GPIO_ACTIVE_LOW;
    		ptr_gpio_key[i].irq = gpio_to_irq(ptr_gpio_key[i].gpio);
    		request_irq(ptr_gpio_key[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_key", &ptr_gpio_key[i]);
    	}
    	
    	major = register_chrdev(0, "my_keydrv", &key_drv);
    	key_class = class_create(THIS_MODULE, "my_key_class");
    	if(IS_ERR(key_class))
    	{
    		printk(KERN_ERR "class_create is err\r\n");
    	}
    	
    	device_create(key_class, NULL, MKDEV(major, 0), NULL, "my_key%d", 0);
    	
    	return 0;	
    }
    
    
    
    static int key_remove(struct platform_device *pdev)
    {
    	int count = 0;
    	int i = 0;
    	struct device_node *node = pdev->dev.of_node;
    
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	count = of_gpio_count(node);
    
    	device_destroy(key_class, MKDEV(major, 0));
    	class_destroy(key_class);
    	unregister_chrdev(major, "my_keydrv");
    	for(i=0;i<count;i++)
    	{
    		free_irq(ptr_gpio_key[i].irq, &ptr_gpio_key[i]);
    	}
    
    	kfree(ptr_gpio_key);
    	return 0;	
    }
    
    
    static const struct of_device_id my_key[] =
    {
    	{.compatible = "my,key_driver"},
    	{},
    };
    
    
    static struct platform_driver key_driver =
    {
    	.probe  = key_probe,
    	.remove = key_remove,
    	.driver = 
    	{
    		.name = "key_gpio",
    		.of_match_table = my_key,
    	},
    };
    
    
    static int __init my_key_init(void)
    {
    	int result;
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	result = platform_driver_register(&key_driver);
    	return result;
    }
    
    
    static void __exit my_key_exit(void)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	platform_driver_unregister(&key_driver);
    }
    
    module_init(my_key_init);
    module_exit(my_key_exit);
    
    MODULE_LICENSE("GPL");
    

    四、实验验证

    1、 正常驱动程序运行

    运行应用./keyTest /dev/my_key0,等待一会儿再按键

    [ 3818.372815] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 3823.375302] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    timeout
    [ 3823.383494] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    [ 3828.388671] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    timeout
    [ 3828.397540] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    [ 3830.476218] g_key_value is 33024
    [ 3830.479938] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 3830.488389] /home/book/code/test/mygpio-key.c key_drv_read line is 85
    get button : 0x8100
    [ 3830.496950] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    [ 3830.509048] g_key_value is 33025
    [ 3830.512819] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 3830.520937] /home/book/code/test/mygpio-key.c key_drv_read line is 85
    get button : 0x8101
    [ 3830.528997] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    

    可以看到不按键时poll函数5s超时,按键按下后先执行gpio_key_isr,然后应用层进程变为可运行态会被调度执行,poll函数返回值POLLIN,if语句成立,调用read函数,进而驱动的read函数被调用,同时wait_event_interruptible()函数condition条件满足,将key值返回给应用层,应用层一次调用poll函数,驱动层poll函数可能被调用2次(刚开始执行一次,超时时执行一次)。
    可以看下韦老师的分析:韦东山:Linux驱动基石之POLL机制

    2、 屏蔽poll_wait()函数

    屏蔽key_drv_poll()函数中的poll_wait(fp, &key_wait, wait)运行应用程序keyTest ,并按键

    static unsigned int key_drv_poll(struct file *fp, poll_table * wait)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	//poll_wait(fp, &key_wait, wait);//非阻塞函数
    	
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    

    打印如下:

    [ 4144.480320] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 4149.485443] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    timeout
    [ 4149.493622] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    [ 4151.599603] g_key_value is 33024
    [ 4151.726422] g_key_value is 33025
    [ 4154.494890] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 4154.501592] /home/book/code/test/mygpio-key.c key_drv_read line is 85
    get button : 0x8100
    [ 4154.515361] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    [ 4154.523727] /home/book/code/test/mygpio-key.c key_drv_read line is 85
    get button : 0x8101
    [ 4154.531437] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    

    可以看到按键按下后中断gpio_key_isr依然被执行,但是应用进程依然休眠,直到5s超时时poll函数返回POLLIN,if语句成立read函数才被执行,可以看到屏蔽poll_wait函数会导致应用进程无法第一时间被执行,屏蔽poll_wait函数后硬件中断到达后无法第一时间将应用进程变为可运行态,导致应用进程一直休眠直到poll函数超时。
    by 面朝大海0902

    3、屏蔽wake_up_interruptible()函数

    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    ... ...
    	put_key(key);
    	//wake_up_interruptible(&gpio_key_wait);
    	
    	return IRQ_HANDLED;
    }
    

    执行结果打印如下:

    [ 4921.589542] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 4926.593101] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    timeout
    [ 4926.605410] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    [ 4928.511399] g_key_value is 33024
    [ 4928.652796] g_key_value is 33025
    [ 4931.609713] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 4931.616786] /home/book/code/test/mygpio-key.c key_drv_read line is 85
    get button : 0x8100
    [ 4931.626061] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    [ 4931.633066] /home/book/code/test/mygpio-key.c key_drv_read line is 85
    get button : 0x8101
    [ 4931.641407] /home/book/code/test/mygpio-key.c key_drv_poll line is 92
    
    

    和情况2类似,应用程序无法第一时间得到调度。

    4、wait_event_interruptible()函数condition不满足

    将condition置为假,如下:

    static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    ...
    	wait_event_interruptible(gpio_key_wait, 0);
    ...
    }
    

    执行结果打印如下:

    [ 5850.349077] /home/book/code/test/mygpio-key.c key_drv_poll line is 93
    [ 5855.349645] /home/book/code/test/mygpio-key.c key_drv_poll line is 93
    timeout
    [ 5855.358149] /home/book/code/test/mygpio-key.c key_drv_poll line is 93
    
    [ 5857.324008] g_key_value is 33024
    [ 5857.327604] /home/book/code/test/mygpio-key.c key_drv_poll line is 93
    [ 5857.462123] g_key_value is 33025
    [ 5870.614619] g_key_value is 33024
    [ 5870.757192] g_key_value is 33025
    [ 5873.257836] g_key_value is 28160
    [ 5873.530629] g_key_value is 28161
    
    

    可以看到只要按键,应用进程执行到Read函数会一直被堵塞住,导致后面按键也没有用,仅打印中断函数执行的log。
    by 面朝大海0902
    按键程序我们也可以使用异步通知的方式进行,详见Linux异步通知—signal()、fcntl()函数介绍与使用

    展开全文
  • wait_eventwait_event_interruptible有什么区别? 最近在项目,被报了一个log,然后就思考到了这个问题: wait_event_interruptible将 当前进程的状态设置成TASK_INTERRUPTIBLEwait_event将 当前进程的状...

    你好!这里是风筝的博客,

    欢迎和我一起交流。


    wake_up与wake_up_interrupt有什么区别?
    wait_event与wait_event_interruptible有什么区别?
    最近在项目,被报了一个log,然后就思考到了这个问题:

    wait_event_interruptible将
    当前进程的状态设置成TASK_INTERRUPTIBLE。
    wait_event将
    当前进程的状态设置成TASK_UNINTERRUPTIBLE。
    它们都会被从runqueue队列中删除,不再参与调度,进入睡眠状态。

    如果要被wait_event_interruptible的当前进程有nonblocked pending signals, 那么会直接返回-ERESTARTSYS(i.e. -512),当前进程不会被wait_event_interruptible 和从runqueue队列中删除。

    两者当区别就在于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE。
    可中断的等待状态(TASK_INTERRUPTIBLE)和不可中断的等待状态(TASK_UNINTERRUPTIBLE):
    处于可中断等待态的进程可以被信号唤醒,如果收到信号,该进程就从等待状态进入可运行状态,并且加入到运行队列中,等待被调度;
    而处于不可中断等待态的进程是因为硬件环境不能满足而等待,例如等待特定的系统资源,它任何情况下都不能被打断,只能用特定的方式来唤醒它,例如唤醒函数wake_up()等。

    最常用发送信号的系统函数是kill, raise, alarm和setitimer以及sigqueue函数等,还包括一些非法运算等操作。

    除了wake_up,常见当还有complete,这两个又有啥区别呢?

    completion机制是两个进程间互相同步的工具,而wait_for_event则是让多个进程在一个等待队列上休眠等待某事件的机制。
    completion以一个completion结构体变量为核心,两个进程围绕该变量执行wait_for_completion和complete操作,以达到实现两个进程同步的目的。
    wait_event则是一个一个等待队列为核心,N个进程围绕该队列执行wait_event(将自己加入等待队列)和wake_up(唤醒队列所有等待进程检查唤醒条件是否满足)操作,以达到使进程在等待条件未满足时保持休眠的目的。


    参考:
    completion和wait_for_event的区别

    展开全文
  • wait_event_interruptible_locked() interface New wait_event_interruptible{,_exclusive}_locked{,_irq} macros added. They work just like versions without _locked* suffix but require the wait queue's ...

    wait_event_interruptible_locked() interface

    New wait_event_interruptible{,_exclusive}_locked{,_irq} macros added.
    They work just like versions without _locked* suffix but require the
    wait queue's lock to be held.  Also __wake_up_locked() is now exported
    as to pair it with the above macros.
    
    The use case of this new facility is when one uses wait queue's lock
    to  protect a data structure.  This may be advantageous if the
    structure needs to be protected by a spinlock anyway.  In particular,
    with additional spinlock the following code has to be used to wait
    for a condition:
    
    spin_lock(&data.lock);
    ...
    for (ret = 0; !ret && !(condition); ) {
    	spin_unlock(&data.lock);
    	ret = wait_event_interruptible(data.wqh, (condition));
    	spin_lock(&data.lock);
    }
    ...
    spin_unlock(&data.lock);
    
    This looks bizarre plus wait_event_interruptible() locks the wait
    queue's lock anyway so there is a unlock+lock sequence where it could
    be avoided.
    
    To avoid those problems and benefit from wait queue's lock, a code
    similar to the following should be used:
    
    /* Waiting */
    spin_lock(&data.wqh.lock);
    ...
    ret = wait_event_interruptible_locked(data.wqh, (condition));
    ...
    spin_unlock(&data.wqh.lock);
    
    /* Waiting exclusively */
    spin_lock(&data.whq.lock);
    ...
    ret = wait_event_interruptible_exclusive_locked(data.whq, (condition));
    ...
    spin_unlock(&data.whq.lock);
    
    /* Waking up */
    spin_lock(&data.wqh.lock);
    ...
    wake_up_locked(&data.wqh);
    ...
    spin_unlock(&data.wqh.lock);
    
    When spin_lock_irq() is used matching versions of macros need to be
    used (*_locked_irq()).

     看到wait_event_interruptible_locked这个api我内心是迷茫的,不知道这个玩意儿怎么用,搜了下看到了别人的解释如上。

    翻译下:

    因为自旋锁锁定期间不能进入睡眠,那么进入睡眠前就应该释放自旋锁,如果手动操作会比较繁琐,这个接口就是为了统一一下操作,他操作的时候 wait_queue_head_t自带的自旋锁lock,在进入休眠前释放这个锁,然后睡眠,醒了以后再获取到这个锁,这样就是在睡眠过程中自旋锁是释放的状态。

    注意,使用这个函数之前,这个自带的自旋锁应该是先获取到的。

    展开全文
  • wait_eventwait_event_interruptible有什么区别? 最近在项目,被报了一个log,然后就思考到了这个问题: wait_event_interruptible将当前进程的状态设置成TASK_INTERRUPTIBLEwait_event将当前进程的状态设置...
  • 内核中使用wait_event_interruptible和wake_up_interruptible接口函数,来实现内核两个进程之间的交互。 代码实现: /* 声明一个工作队列入等待*/ static DECLARE_WAIT_QUEUE_HEAD(my_wq); static volatile int ...
  • 休眠 所谓休眠就是让出CPU 然后并不返回 wait_event_interruptible(wq, condition) condition = 0 ///休眠 ...wait_event_interruptible()和wait_up_interruptible() wait_event_interruptible...
  • Linux驱动中的wait_event_interruptible()与wake_up_interruptible() DECLARE_WAIT_QUEUE_HEAD(wq)   生成一个等待队列头wait_queue_head_t,名字为wq. wait_event_interruptible(wq, condition):...
  • wait_event_interruptible 与 wake_up_interruptible 深度分析
  • wait_event_interruptible souece code #define __wait_event_interruptible(wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ \ for (;;) { \ prepare_to_wait(&wq, &...
  • wait_event_interruptible用途简单,让当前进程“睡觉”, 等待期望的资源。人如其名,函数名里带了interruptible, 说明进程被唤醒时,先别高兴太早。不一定是你期盼的资源到了, 可能是其他“杂事”需要你处理。...
  • wait_event_interruptible 使用方法

    千次阅读 2017-08-07 17:55:09
    1. 关于 wait_event_interruptible() 和 wake_up()的使用   读一下wait_event_interruptible()的源码,不难发现这个函数先将 当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(), 而schedule()会将...
  • 网上有关于此函数的分析,但大都是同一篇文章转载来转载去,没有进一步的分析。做个小结: 了解函数功能,除了直接看代码逻辑,最有效的当是注释内容...函数原型:wait_event_interruptible_timeout(wq, condition, ...
  • wait_event_interruptible_timeout函数分析

    千次阅读 2018-02-13 16:08:37
    在intel F10A进行DMA读写操作时,会首先调用queue_work函数将当前work压入工作队列中,然后调用wait_event_interruptible_timeout函数等待DMA读/写操作的完成,在调试的过程中偶尔会出现超时返回的情况。 下面结合...
  • rval = wait_event_interruptible_timeout(wait_queue, condition, 5s) ; printk( “ hello world, rval = %d\n”, rval ); rval返回0表示时间片流完,condition还没有满足 rval返回>0 表示时间片没流完,...
  •  interruptible_sleep_on ( wait_queue_head_t *q )  让进程进入 可中断 的睡眠,并把它放入等待队列 q.   等待队列中唤醒进程 wake_up :  wake_up ( wait_queue_t *q )  从等待队列 q 中...
  • 1.原型  #define wait_event_interruptible_timeout(wq_head, condition, timeout) \ ({ \ long __ret = timeout; ...
  • wait_event_interruptible(wq, condition),该函数修改task的状态为TASK_INTERRUPTIBLE,意味着该进程将不会继续运行直到被唤醒,然后被添加到等待队列wq中。 在wait_event_interruptible()中首先判断condition...
  • wait_event_interruptible(以及wait_event打头的其他变体)是Linux的wait queue机制提供的线程同步接口,它的定义如下 #define wait_event_interruptible(wq, condition) \ ({ \ int __ret = 0; \ might_sleep
  • wait_event_interruptible()

    千次阅读 2016-12-19 15:38:59
    转自http://blog.chinaunix.net/uid-29054367-id-3809059.html 点击(此处)折叠或打开 #define wait_event_interruptible(wq, condition) \ ({ \  in
  • 网上有关于此函数的分析,但大都是同一篇文章转载来转载...函数原型:wait_event_interruptible_timeout(wq, condition, timeout) * 函数作用:~睡眠~,直到condition为真,或timeout超时; * @wq: 要等待的等待队列 *
  • 1. 关于 wait_event_interruptible() 和 wake_up()的使用   读一下wait_event_interruptible()的源码,不难发现这个函数先将 当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(), 而schedule()会将...
  • 函数原型:wait_event_interruptible_timeout(wq, condition, timeout) * 函数作用:~睡眠~,直到condition为真,或timeout超时; * @wq: 要等待的等待队列 * @condition: 等待事件发生的条件(一个C表达式 ) ...
  • linux内核里的等待队列机制在做驱动开发时用的非常多,多用来实现... 睡眠方式:wait_event, wait_event_interruptible  唤醒方式:wake_up (唤醒时要检测条件是否为真,如果还为假则继续睡眠,唤醒前一定要把条件变
  • 很多博客都会说一堆这几个内核函数的理解定义等,烦的要死。这里直接上代码demo!...wait_queue_head_t memo_wqueue; #define g_thread_timeout 5000 #define THREAD_WAKEUP 0 /* 线程唤醒标志 */ #defi...
  • 进程挂起wait_event_interruptible

    千次阅读 2016-12-01 11:31:29
    在进程执行过程中,有时候需要等待某个条件满足而进行进程阻塞。...wait_event_interruptible()定义如下: #define wait_event_interruptible(wq, condition) \ ({ \ int _ret = 0; \ if(!condition) \
  • 1. 关于 wait_event_interruptible() 和 wake_up()的使用   读一下wait_event_interruptible()的源码,不难发现这个函数先将 当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(), 而schedule()会...
  • 最近做一个驱动,在等待FPGA结果的时候调用wait_event_interruptible,期望能进入睡眠状态,并且在需要的时候可以使用ctrl+c杀死进程,但是在使用过程中发现wait_event_interruptible一直返回-ERESTARTSYS(-512)值...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,479
精华内容 3,391
关键字:

wait_event_interruptible