linux内核之阻塞 IO(1)
大家都知道IO分为阻塞和非阻塞,
大家都知道访问方式IO分为阻塞和非阻塞两种:
阻塞:就是当IO资源不可访问时挂起到等待队列上休眠让出cpu,直到可操作时再唤醒进行操作
非阻塞:就是不停的访问直到有资源可操作
在linux应用程序open接口上就为我们提供了阻塞,非阻塞等操作选项,如果不知道 man open 下就出来了
(linux下常用的函数接口都可以通过man来查询 甚至man ascii可以查询ASCII表哦)
O_NONBLOCK or O_NDELAY 这两个宏就为非组赛访问,默认为阻塞访问
open(“/dev/xxxx”,O_RDWR);//阻塞
open("/dev/xxxx",O_RDWR|O_NONBLOCK );//非阻塞
linux下阻塞访问又分为
简单休眠和高级休眠
简单休眠就是 直接使用linux为我们实现的等待队列实现休眠常用的函数如下:
wait_event(queue,condition);
wait_event_interruptible(queue,condition);
wait_event_timeout(queue,condition);
wait_event_timeout__interruptible(queue,condition);
queue 是等待队列的头,condition 表示条件保持为真之前进程会保持休眠
静态初始化等待队列头
DECLARE_WAIT_QUEUE(name);
动态方法:
wait_head_queue_t my_queue;
init_waitqueue_head(&my_queue);
唤醒的函数:
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
注意哦:wake_up唤醒队列上的所有休眠进程,造成狼群争抢资源的现象,后面的高级休眠中独占等待就不会造成这种现象;wake_up_interruptible只会唤醒那些执行可中断休眠的进程
例子程序参考(ldd3 (scull)):
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/device.h>
#define FIFO_SIZE 1024
struct wq_fifo_node
{
struct cdev mycdev;
unsigned int current_len;
unsigned char *fifo;
struct semaphore sem_t;
unsigned int rt;
unsigned int wt;
wait_queue_head_t w_wait;
wait_queue_head_t r_wait;
};
static dev_t dev_num;
static struct class *wq_class;
static struct device *wq_device;
static struct wq_fifo_node *wq_fifo;
static int wq_open(struct inode *inode, struct file *file)
{
//struct wq_fifo_node *mywq = container_of(inode->i_cdev,struct wq_fifo_node,mycdev);
//file->private_data = wq_fifo;
/*down(&wq_fifo->sem_t);
wq_fifo->fifo = kmalloc(FIFO_SIZE*sizeof(unsigned char),GFP_KERNEL);
wq_fifo->rt = 0;
wq_fifo->wt = 0;
up(&wq_fifo->sem_t);*/
printk("file is open\n");
return 0;
}
static ssize_t wq_write(struct file *file,const char __user *user_buf,size_t count, loff_t *ppos)
{
int ret;
int i,index;
//struct wq_fifo_node *wq_fifo = file->private_data;
unsigned char *tmp_buf = kmalloc(count,GFP_KERNEL);
printk("__FUNCTION__ %s __LINE__ %d\n",__FUNCTION__,__LINE__);
down(&(wq_fifo->sem_t));
if(((wq_fifo->wt+1) % FIFO_SIZE )== wq_fifo->rt)
{
if(file->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out1;//非阻塞IO直接返回
}
up(&(wq_fifo->sem_t));//在进入休眠前释放锁
//阻塞IO
wait_event_interruptible((wq_fifo->w_wait),((wq_fifo->wt+1)%FIFO_SIZE != wq_fifo->rt));
down(&(wq_fifo->sem_t));//休眠唤醒后重新或得锁
}
if(((wq_fifo->rt-wq_fifo->wt+FIFO_SIZE)-1)%FIFO_SIZE>= count)
{
copy_from_user(tmp_buf,user_buf,count);
for(i =0;i<count;i++)
{
wq_fifo->fifo[wq_fifo->wt] = tmp_buf[i];
wq_fifo->wt = (wq_fifo->wt+1)%FIFO_SIZE;
}
ret = count;
kfree(tmp_buf);
}
else
{
ret = ((wq_fifo->wt-wq_fifo->rt+FIFO_SIZE)-1)%FIFO_SIZE;
copy_from_user(tmp_buf,user_buf,ret);
for(i =0;i<ret;i++)
{
wq_fifo->fifo[wq_fifo->wt] = tmp_buf[i];
wq_fifo->wt = (wq_fifo->wt+1)%FIFO_SIZE;
}
kfree(tmp_buf);
}
wake_up_interruptible(&(wq_fifo->r_wait));
printk("__LINE__ %d wq_fifo->rt = %d wq_fifo->wt = %d\n",__LINE__,wq_fifo->rt,wq_fifo->wt);
out1:
up(&(wq_fifo->sem_t));
return ret;
}
static ssize_t wq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
int ret;
int i;
printk("__FUNCTION__ %s __LINE__ %d\n",__FUNCTION__,__LINE__);
printk("read size %d\n",size);
unsigned char *tmp_buf = kmalloc(size,GFP_KERNEL);
//struct wq_fifo_node *wq_fifo = file->private_data;
printk("__LINE__ %d wq_fifo->rt = %d wq_fifo->wt = %d\n",__LINE__,wq_fifo->rt,wq_fifo->wt);
down(&(wq_fifo->sem_t));
if(wq_fifo->wt == wq_fifo->rt)
{
if(file->f_flags&O_NONBLOCK)
{
ret = -EAGAIN;
goto out1;
}
up(&(wq_fifo->sem_t));
wait_event_interruptible((wq_fifo->r_wait),wq_fifo->wt != wq_fifo->rt);
down(&(wq_fifo->sem_t));
printk("__FUNCTION__ %s __LINE__ %d\n",__FUNCTION__,__LINE__);
printk("__LINE__ %d wq_fifo->rt = %d wq_fifo->wt = %d\n",__LINE__,wq_fifo->rt,wq_fifo->wt);
}
if((wq_fifo->wt-wq_fifo->rt+FIFO_SIZE)%FIFO_SIZE>= size)
{
for(i = 0;i < size;i++)
{
tmp_buf[i] = wq_fifo->fifo[wq_fifo->rt];
wq_fifo->rt = (wq_fifo->rt+1)%FIFO_SIZE;
}
ret = size;
copy_to_user(buf,tmp_buf,ret);
}
else
{
ret = (wq_fifo->wt-wq_fifo->rt+FIFO_SIZE)%FIFO_SIZE;
printk("__FUNCTION__ %s __LINE__ %d\n",__FUNCTION__,__LINE__);
printk("__LINE__ %d wq_fifo->rt = %d wq_fifo->wt = %d\n",__LINE__,wq_fifo->rt,wq_fifo->wt);
for(i = 0;i < ret;i++)
{
tmp_buf[i] = wq_fifo->fifo[wq_fifo->rt];
wq_fifo->rt = (wq_fifo->rt+1)%FIFO_SIZE;
}
printk("__FUNCTION__ %s __LINE__ %d\n",__FUNCTION__,__LINE__);
copy_to_user(buf,tmp_buf,ret);
kfree(tmp_buf);
}
wake_up_interruptible(&(wq_fifo->w_wait));
out1:
up(&(wq_fifo->sem_t));
return ret;
}
static int wq_release(struct inode *inode, struct file *file)
{
// struct wq_fifo_node *wq_fifo = file->private_data;
//kfree(wq_fifo->fifo);
//wq_fifo->fifo = NULL;
printk("file is close!\n");
return 0;
}
static struct file_operations f_ops = {
.owner = THIS_MODULE,
.open = wq_open,
.read = wq_read,
.write = wq_write,
.release = wq_release,
};
static void setup_cdev(struct wq_fifo_node *wq)
{
int err;
//cdev = cdev_alloc();
cdev_init(&(wq->mycdev),&f_ops);
wq->mycdev.owner = THIS_MODULE;
wq->mycdev.ops = &f_ops;
err = cdev_add(&(wq->mycdev),dev_num,1);
if(err)
{
printk("cdev add_error!!\n");
}
}
static int __init waitqueue_init()
{
printk(KERN_ALERT "%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
wq_fifo = kmalloc(sizeof(struct wq_fifo_node),GFP_KERNEL);
wq_fifo->fifo = kmalloc(FIFO_SIZE*sizeof(unsigned char),GFP_KERNEL);
wq_fifo->rt = 0;
wq_fifo->wt = 0;
init_waitqueue_head(&(wq_fifo->r_wait));
init_waitqueue_head(&(wq_fifo->w_wait));
init_MUTEX(&(wq_fifo->sem_t));
alloc_chrdev_region(&dev_num,0,1,"work_queue");//动态申请设备号可用 cat /proc/devices查看
setup_cdev(wq_fifo);
wq_class = class_create(THIS_MODULE,"wq_class");
wq_device = device_create(wq_class,NULL,dev_num,NULL,"wq_device");//创建设备节点在dev下等同于命令mknode
printk(KERN_ALERT "%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
return 0;
}
static void __exit waitqueue_exit()
{
//if(wq_fifo->fifo == NULL)
kfree(wq_fifo->fifo);
cdev_del(&(wq_fifo->mycdev));
kfree(wq_fifo->fifo);
device_del(wq_device);
class_unregister(wq_class);
}
module_init(waitqueue_init);
module_exit(waitqueue_exit);
MODULE_AUTHOR("liwenzou");
MODULE_LICENSE("GPL");
效果:先在一个终端窗口输入:cat /dev/wq_device
在启动一个终端窗口:echo "gfdagfd">/dev/wq_device,就可以在刚才的cat命令执行的窗口看到效果
更多推荐
所有评论(0)