linux 内核阻塞式io,linux内核之阻塞 IO(1)

大家都知道访问方式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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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

{

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

{

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命令执行的窗口看到效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值