linux阻塞原理,关于Linux设备访问机制——阻塞,非阻塞io,异步通知

对于字符型驱动中经常会碰到应用程序和底层硬件数据交换的问题,常用的做法有:

1.阻塞:

通过读写函数中内嵌阻塞代码(信号量,等待队列)来实现不满足条件时的睡眠,等到满足条件了应用程序从睡眠中唤醒,继续下面的操作。

关于信号量和等待队列可以参考以前的ppt和之前的文章。

2.非阻塞:

非阻塞就是应用程序即使得不到硬件数据也不会睡眠,而是直接返回。当然真实的操作不会就这样返回推出了,而是先通过轮询的方式,也就是上一篇文章的select,(虽然这里说是非阻塞,但是select本身就有点阻塞的味道,如果加入的文件描述符都不满足,select会休眠,一旦下层驱动有变化则会通知select再次调用poll函数,这其实是一种改良的轮询,非常好的一种机制),通过select来实现轮询的方式,只要select能通过则表明可以进行读或者写了。

3.异步IO

一旦实现异步IO,底层的一旦有数据变化,就会像产生一个中断一样通知上层应用.异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序就根本不需要查询设备状态(非常像中断吧!)

1.2之前都有提到怎么写,所以这里不多说了,谈一下怎么用异步io。

(1)首先在结构体中添加异步结构体指针:

struct fifodev

{

unsigned char buf[MAX_FIFO_BUF];   //按键缓冲区

unsigned int current_len;

wait_queue_head_t r_wait;            //等待队列

wait_queue_head_t w_wait;

struct cdev cdev;

……

struct fasync_struct *async_queue;

} ;

(2)驱动设备的fasync()函数

static int sep4020_fifo_fasync(int fd, struct file *flip, int mode)

{

return fasync_helper(fd, flip, mode, &fifo_dev->async_queue);

}

(3)在相应的资源可以获得的地方添加释放sigio信号,比如在中断,读函数,写函数中,这里举例写函数中:

static ssize_t sep4020_fifo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)

{……

wake_up_interruptible(&fifo_dev->r_wait);

if(fifo_dev->async_queue)

kill_fasync(&fifo_dev->async_queu,SIGIO, POLL_IN);//这里是写函数释放,当然是表示可以读了,同理在读中释放就要用poll_out了

out:

return ret;

}

(4)在文件关闭时,将文件从异步通知队列中删除。

static int sep4020_fifo_release(struct inode *inode, struct file *filp)

{

//调用之前写的fasync函数

sep4020_fifo_fasync(-1,flip, 0);

return 0;

}

/****************************************************************************/

下面是应用程序需要做的工作:

#include ……

void input_handler(int signum)

{

相应的处理,比如说程序中异步读通知的话,这里就可以实现读的操作

}

main()

{

int fd, oflags;

fd = open("dev/fifo, O_RDWR, S_IRUSR | S_IWUSR");

if(fd == -1)

{

printf("wrong\r\n");

exit(-1);

}

signal(SIGIO,input_handler);//让input_handler()处理SIGIO信号

fcntl(fd, F_SETOWN, getpid());//第二个参数的定义是设置异步io所有权,所以这句话的意思是设置本进程为fd文件的所有者

oflags = fcntl(fd, F_GETFL);//获得文件状态标志

fcntl(fd, F_SETFL, oflags | FASYNC);//用户程序必须对访问的设备文件设置FASYNC标志。F_SETFL命令表示设置文件状态标志位.

while(1)

{

sleep(100);

}

}

以下是网上摘录的:

驱动程序的实现需要:

当用户程序操作时,从内核驱动的角度来看:

(1)当用户程序调用F_SETOWN命令时(通过fnctl系统调用),所设置的值保存在了驱动程序中的filp->f_owner结构体。

(2)当用户程序调用F_SETFL命令设置FASYNC标志时,驱动中的fasync方法相应的被调用。fasync方法的实现样例如下:

static int scull_p_fasync(int fd, struct file *filp, int mode)

{

struct scull_pipe *dev = filp->private_data;

return fasync_helper(fd, filp, mode, &dev->async_queue);//

}

(3)当设备驱动准备好访问数据后,向所有注册异步通知的进程发送SIGIO信号。它的实现样例如下:

if (dev->async_queue)

kill_fasync(&dev->async_queue, SIGIO, POLL_IN);//POLL_IN指设备此时准备好供用户可读的数据;如果要对设备可写,这里应该用POLL_OUT

(4)当设备文件被关闭时,应当将设备文件从内核维护的活动异步读列表中删掉。它的实现样例如下:

/* remove this filp from the asynchronously notified filp's */

scull_p_fasync(-1, filp, 0);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值