赞
踩
(本章基于:Linux-3.13.0-32)
当一个设备无法立即满足用户的读写请求时应当阻塞该用户程序。例如在socket网络编程时,使用read在一个已经建立好的socket连接上读取对方发送的数据,但此时对方什么都没有发送,这时程序默认进入阻塞状态(即睡眠),等待接收到对方发送的有效数据时再唤醒该程序继续运行。在Linux内核模块中我们使用等待队列实现这种阻塞功能。
1、定义等待队列
<linux/wait.h>
wait_queue_head_t my_queue;
2、初始化等待队列
init_waitqueue_head(&my_queue);
3、定义+初始化宏
DECLARE_WAIT_QUEUE_HEAD(my_queue);
4、进入等待队列,睡眠
wait_queue(queue, condition);
当condition为真是立即返回,否则让程序进入TASK_UNINTERRUPTIBLE(不可中断)模式的睡眠,并挂在queue参数所指向的等待队列上;
wait_event_interruptible(queue, condition);
功能同上,区别在于会让程序进入TASK_INTERRUPTIBLE(可中断)模式的睡眠;
wait_event_killable(queue, condition);
功能同上,区别在于会让程序进入TASK_KILLABLE(只响应致命信号)模式的睡眠;
5、从等待队列中唤醒程序
wake_up(wait_queue_t *q);
从等待队列中唤醒所有进程;
wake_up_interruptible(wait_queue_t *q);
从等待队列中唤醒所有状态为TASK_INTERRUPTIABLE的进程
(注意:当进程被唤醒时会再次检查condition,若为真则立即返回,否则再次睡眠!)
例:
在本例中使用一个定时器以1s为周期递加资源source,一次read操作将source减一,当source为0时read操作被阻塞;
内核层:
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/miscdevice.h>
- #include <linux/fs.h>
- #include <linux/wait.h>
- #include <linux/sched.h>
- #include <linux/timer.h>
-
- #define TIMER_INTERVAL (1 * HZ)
-
- DECLARE_WAIT_QUEUE_HEAD(WQ);
- static struct timer_list timer;
- unsigned int source = 0;
-
- void
- timer_function(unsigned long arg)
- {
- source ++;
- wake_up(&WQ);
-
- mod_timer((struct timer_list*)arg, jiffies + TIMER_INTERVAL);
- }
-
- int my_open(struct inode *inode, struct file *file)
- {
- printk(KERN_INFO "This is miscdevice open\n");
- return 0;
- }
-
- int my_close(struct inode *inode, struct file *file)
- {
- printk(KERN_INFO "This is miscdevice close\n");
- return 0;
- }
-
- ssize_t
- my_read(struct file *file, char __user *user, size_t size, loff_t *loff)
- {
- printk(KERN_INFO "read start\n");
- wait_event_interruptible(WQ, source);
- source --;
- printk(KERN_INFO "read end\n");
- return 0;
- }
-
- const struct file_operations my_fops = {
- .open = my_open,
- .release = my_close,
- .read = my_read,
- };
-
- struct miscdevice my_misc = {
- .minor = 201,
- .name = "stone",
- .fops = &my_fops,
- };
-
- static __init int hello_init(void)
- {
- init_timer(&timer);
- timer.expires = jiffies + TIMER_INTERVAL;
- timer.function = timer_function;
- timer.data = (unsigned long)&timer;
- add_timer(&timer);
-
- misc_register(&my_misc);
-
- printk(KERN_ALERT "helloworld!\n");
- return 0;
- }
-
- static __exit void hello_exit(void)
- {
- misc_deregister(&my_misc);
- printk(KERN_ALERT "helloworld exit!\n");
- }
-
- module_init(hello_init);
- module_exit(hello_exit);
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Stone");
应用层:
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-
- int
- main(void)
- {
- int fd;
-
- fd = open("/dev/stone", O_RDWR);
- if(fd < 0) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- while(1) {
- read(fd, NULL, 0);
- printf("read success!\n");
- }
- close(fd);
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。