Linux系统中的IO模型
1.1 linux系统中的IO模型的种类
(1)非阻塞IO模型
(2)阻塞IO模型
(3)IO多路复用
(4)异步通知
1.2 非阻塞IO模型
非阻塞IO模型:当应用程序通过非阻塞的方式打开文件的时候,通过read读取
数据的时候,不管数据是否准备好,都要立即返回。
fd = open("/dev/mycdev0",O_RDWR|O_NONBLOCK);
read(fd,buf,sizeof(buf));
--------------------------------------------------------
driver_read(struct file *file,,,)
{
if(file->f_flags &O_NONBLOCK){
}
}
1.3 阻塞IO模型
1.3.1 阻塞IO模型的实现流程
阻塞IO模型:应用层以阻塞的方式打开设备文件,然后调用read函数读取硬件的数据。
如果硬件的数据没有准备好,需要让进程进入到休眠的状态。当硬件的数据准备好的
时候产生中断,在中断的处理函数中唤醒休眠的进程即可。
1.3.2阻塞IO模型函数调用流程
fd = open("/dev/mycdev0",O_RDWR);
read(fd,buf,sizeof(buf));
--------------------------------------------------------
driver_read(struct file *file,,,)
{
if(file->f_flags &O_NONBLOCK){
}else{
}
}
中断的处理函数:
唤醒休眠的进程
1.3.3阻塞IO模型的API
1.定义等待队列头
wait_queue_head_t wq;
2.初始化等待队列头
init_waitqueue_head(&wq);
3.调用对应的函数完成阻塞(定义等待队列项,将等待队列项放到队列的队尾,进程休眠)
wait_event(wq, condition)
wait_event_interruptible(wq, condition)
注:condition代表的是数据是否准备好的标志,如果condition为真代表数据准备好了
进程不需要休眠,如果condition为假代表数据没有准备好进程需要进入休眠的状态。
4.唤醒休眠的进程
condition=1;
wake_up(&wq);
wake_up_interruptible(&wq);
注:上述的两个函数唤醒的是等待队列,队列中的进程是否真的被唤醒取决于
condition的真假,如果condition为真,进程就准备被唤醒了,如果condition
为假进程没有被唤醒,进程继续休眠。
1.3.4阻塞IO模型的实例
mycdev.c
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define CNAME "mycdev"
struct cdev* cdev;
unsigned int major = 511;
unsigned int minor = 0;
const int count = 3;
struct class* cls;
struct device* dev;
char kbuf[128] = { 0 };
wait_queue_head_t wq;
int condition = 0;
int mycdev_open(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file* file,
char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (file->f_flags & O_NONBLOCK) {
return -EINVAL;
} else {
ret = wait_event_interruptible(wq, condition);
if (ret) {
printk("receive signal.....\n");
return ret;
}
}
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret) {
printk("copy data to user error\n");
return -EIO;
}
condition=0;
return size;
}
ssize_t mycdev_write(struct file* file,
const char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret) {
printk("copy data form user error\n");
return -EIO;
}
condition = 1;
wake_up_interruptible(&wq);
return size;
}
int mycdev_close(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
const struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.release = mycdev_close,
};
static int __init mycdev_init(void)
{
int ret, i;
dev_t devno;
cdev = cdev_alloc();
if (cdev == NULL) {
printk("cdev alloc memory error\n");
ret = -ENOMEM;
goto ERR1;
}
cdev_init(cdev, &fops);
if (major > 0) {
ret = register_chrdev_region(MKDEV(major, minor), count, CNAME);
if (ret) {
printk("static:request device number error\n");
goto ERR2;
}
} else {
ret = alloc_chrdev_region(&devno, 0, count, CNAME);
if (ret) {
printk("dynamic:request device number error\n");
goto ERR2;
}
major = MAJOR(devno);
minor = MINOR(devno);
}
ret = cdev_add(cdev, MKDEV(major, minor), count);
if (ret) {
printk("register char device driver error\n");
goto ERR3;
}
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls)) {
printk("class create error\n");
ret = PTR_ERR(cls);
goto ERR4;
}
for (i = 0; i < count; i++) {
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
if (IS_ERR(dev)) {
printk("device create error\n");
ret = PTR_ERR(dev);
goto ERR5;
}
}
init_waitqueue_head(&wq);
return 0;
ERR5:
for (--i; i >= 0; i--) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(MKDEV(major, minor), count);
ERR2:
kfree(cdev);
ERR1:
return ret;
}
static void __exit mycdev_exit(void)
{
int i;
for (i = 0; i < count; i++) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), count);
kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
test.c
#include <head.h>
char buf[128] = "i am test block IO mode....";
int main(int argc, const char* argv[])
{
int fd;
pid_t pid;
if ((fd = open("/dev/mycdev0", O_RDWR)) == -1)
PRINT_ERR("open error");
pid = fork();
if (pid == -1) {
PRINT_ERR("fork error");
} else if (pid == 0) {
while (1) {
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf));
printf("buf = %s\n", buf);
}
} else {
while(1){
sleep(3);
write(fd,buf,sizeof(buf));
}
wait(NULL);
}
close(fd);
return 0;
}
1.3.5 阻塞实现的流程
#define wait_event_interruptible(wq_head, condition)
({
int __ret = 0;
if (!(condition))
__ret = __wait_event_interruptible(wq_head, condition);
__ret;
})
#define __wait_event_interruptible(wq_head, condition)
___wait_event(wq_head, condition, TASK_INTERRUPTIBLE, 0, 0, schedule())
#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd)
({
struct wait_queue_entry __wq_entry;
long __ret = ret;
init_wait_entry(&__wq_entry,0);
for (;;) {
long __int = prepare_to_wait_event(&wq_head, &__wq_entry, TASK_INTERRUPTIBLE);
if (condition)
break;
if (signal_pending_state(state, current)) {
list_del_init(&wq_entry->entry);
__ret = -ERESTARTSYS;;
goto __out;
}
schedule();
}
finish_wait(&wq_head, &__wq_entry);
__out: __ret;
})
1.4 IO多路复用的IO模型
1.4.1 IO多路复用的实现的流程
IO多路复用:在同一个进程中想同时监听多个硬件的数据,此时就需要使用IO多路复用
的机制。将需要监听的文件描述符放在需要监听文件描述符的表中,通过select/poll/epoll
完成监听,如果所有的硬件的数据都没有准备好此时进程休眠。当有硬件的数据准备好的时候
会产生硬件的中断,在中断的处理函数中唤醒休眠的进程,当进程被唤醒之后从准备好的文件
描述符表中找出准备好的文件描述符,从里面读取数据即可。
1.4.2 IO多路复用接口调用流程
user:
fd1 = open("/dev/mycdev0",O_RDWR);
fd2 = open("/dev/input/mouse0",O_RDWR);
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd1,&rfds);
FD_SET(fd2,&rfds)
select(maxfd+1,&rfds,NULL,NULL,NULL)
if(FD_ISSET(fd1,&rfds)){
read(fd1,buf1,sizeof(buf1));
}
if(FD_ISSET(fd2,&rfds)){
read(fd2,buf2,sizeof(buf2));
}
----------------------------------------------
kernel:fops:
grep ".poll =" * -nR
__poll_t (*poll) (struct file *file, struct poll_table_struct *wait);
{
1.定义返回值的变量__poll_t mask = 0;
2.调用poll_wait(是和阻塞相关的函数)
poll_wait(file, 等待队列头, wait);
3.判断数据是否准备好了
if(condition){
mask |= EPOLLIN;
}
4.返回mask
return mask;
}
1.4.3 IO多路复用实例
test.c
#include <head.h>
#include <sys/select.h>
char buf[128] = "i am test block IO mode....";
int main(int argc, const char* argv[])
{
int fd1, fd2, ret;
fd_set rfds;
if ((fd1 = open("/dev/mycdev0", O_RDWR)) == -1)
PRINT_ERR("open error");
if ((fd2 = open("/dev/input/mouse0", O_RDWR)) == -1)
PRINT_ERR("open error");
while (1) {
FD_ZERO(&rfds);
FD_SET(fd1, &rfds);
FD_SET(fd2, &rfds);
ret = select(fd2 + 1, &rfds, NULL, NULL, NULL);
if (ret == -1)
PRINT_ERR("select error");
if (FD_ISSET(fd1, &rfds)) {
memset(buf, 0, sizeof(buf));
read(fd1, buf, sizeof(buf));
printf("mycdev0:%s\n", buf);
}
if (FD_ISSET(fd2, &rfds)) {
memset(buf, 0, sizeof(buf));
read(fd2, buf, sizeof(buf));
printf("mouse0:%s\n", buf);
}
}
close(fd1);
return 0;
}
mycdev.c
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#define CNAME "mycdev"
struct cdev* cdev;
unsigned int major = 511;
unsigned int minor = 0;
const int count = 3;
struct class* cls;
struct device* dev;
char kbuf[128] = { 0 };
wait_queue_head_t wq;
int condition = 0;
int mycdev_open(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file* file,
char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret) {
printk("copy data to user error\n");
return -EIO;
}
condition=0;
return size;
}
ssize_t mycdev_write(struct file* file,
const char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret) {
printk("copy data form user error\n");
return -EIO;
}
condition = 1;
wake_up_interruptible(&wq);
return size;
}
__poll_t mycdev_poll(struct file *file, struct poll_table_struct *wait)
{
__poll_t mask = 0;
poll_wait(file, &wq_head, wait);
if (condition) {
mask |= EPOLLIN;
}
return mask;
}
int mycdev_close(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
const struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.poll = mycdev_poll,
.release = mycdev_close,
};
static int __init mycdev_init(void)
{
int ret, i;
dev_t devno;
cdev = cdev_alloc();
if (cdev == NULL) {
printk("cdev alloc memory error\n");
ret = -ENOMEM;
goto ERR1;
}
cdev_init(cdev, &fops);
if (major > 0) {
ret = register_chrdev_region(MKDEV(major, minor), count, CNAME);
if (ret) {
printk("static:request device number error\n");
goto ERR2;
}
} else {
ret = alloc_chrdev_region(&devno, 0, count, CNAME);
if (ret) {
printk("dynamic:request device number error\n");
goto ERR2;
}
major = MAJOR(devno);
minor = MINOR(devno);
}
ret = cdev_add(cdev, MKDEV(major, minor), count);
if (ret) {
printk("register char device driver error\n");
goto ERR3;
}
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls)) {
printk("class create error\n");
ret = PTR_ERR(cls);
goto ERR4;
}
for (i = 0; i < count; i++) {
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
if (IS_ERR(dev)) {
printk("device create error\n");
ret = PTR_ERR(dev);
goto ERR5;
}
}
init_waitqueue_head(&wq);
return 0;
ERR5:
for (--i; i >= 0; i--) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(MKDEV(major, minor), count);
ERR2:
kfree(cdev);
ERR1:
return ret;
}
static void __exit mycdev_exit(void)
{
int i;
for (i = 0; i < count; i++) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), count);
kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
1.5 sys_select执行流程总结
US:
select(maxfd+1,&rfds,NULL,NULL,NULL);
---------------------------------------------------------------
VFS(虚拟文件系统): sys_select
1.校验最大文件描述符
2.分配6张表的内存(前三张表用来存储用户的文件描述符,后三张表存储准备好的文件描述符)
3.将用户空间表拷贝到内存空间
4.遍历文件描述符
mask = fd_set->fd->fd_array[fd]->file->f_op->poll(file,wait);
如果所有的文件描述符对应驱动返回的mask都是0,说明所有的硬件的数据
都没有准备好
5.进程休眠 (schedule相关的函数)
6.如果进程被唤醒(数据准备好,超时时间到,收到了信号),再次遍历
文件描述符,找出数据准备好的文件描述符(如果mask不为0,说明数据就准备好了)
mask = fd_set->fd->fd_array[fd]->file->f_op->poll(file,wait);
将准备好的文件描述符放到准备好的文件描述符的表中
7.将准备好的文件描述符拷贝到用户空间
---------------------------------------------------------------
驱动层:
__poll_t mycdev_poll(struct file* file, struct poll_table_struct* wait)
{
__poll_t mask = 0;
poll_wait(file, &wq, wait);
if (condition)
mask |= EPOLLIN;
return mask;
}
1.6 select/poll/epoll有什么区别?
select:表
? 1.最多只能监听1024个文件描述
? 2.用户空间的表会被清空,需要反复构造文件描述符的表,需要反复从用户空间向内核空间拷贝表效率低
? 3.当select进程休眠被唤醒之后,需要再次编译文件描述符的表,找出准备好的文件描述符,效率比较低。
poll:结构体数组
? 1.poll监听的文件描述符没有个数限制
? 2.poll的表不会被清空,不需要反复拷贝文件描述符,效率比较高。
? 3.当poll进程休眠被唤醒之后,需要再次编译文件描述符的表,找出准备好的文件描述符,效率比较低。
epoll:红黑树
? 1.epoll监听的文件描述符没有个数限制
? 2.epoll的表不会被清空,不需要反复拷贝文件描述符,效率比较高。
? 3.当epoll进程休眠被唤醒之后,能直接拿到准备好的文件描述符,不需要遍历,效率高。
1.7 epoll的使用
#include <sys/epoll.h>
int epoll_create(int size);
功能:创建epoll
参数:
@size:参数已经被忽略了,只需要填写大于0的值即可
返回值:成功返回epfd,失败返回-1置位错误码
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:关于epoll的控制操作
参数:
@epfd:epoll的文件描述符
@op:控制方式
EPOLL_CTL_ADD:添加
EPOLL_CTL_MOD:修改
EPOLL_CTL_DEL:删除
@fd:被操作的文件描述符
@event:(事件)结构体指针
typedef union epoll_data {
void *ptr;
int fd; <====一般填写这个成员
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events;
epoll_data_t data;
};
返回值:成功返回0,失败返回-1置位错误码
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
功能:阻塞等待文件描述符就绪
参数:
@epfd:epoll的文件描述符
@events:准备好的事件的结构体地址
@maxevents:返回的最大的文件描述符的个数
@timeout:超时
>0 :毫秒级别的超时时间
=0 :立即返回
=-1:不关心超时时间
返回值:
成功返回准备好的文件描述符的个数
返回0代表超时时间到了
失败返回-1置位错误码
代码实现
#include <head.h>
#include <sys/epoll.h>
int main(int argc, const char* argv[])
{
int epfd, fd, ret;
struct epoll_event event;
struct epoll_event revents[10];
char buf[128] = {0};
if ((epfd = epoll_create(10)) == -1)
PRINT_ERR("epoll create error");
for (int i = 1; i < argc; i++) {
if ((fd = open(argv[i], O_RDWR)) == -1)
PRINT_ERR("open error");
event.events = EPOLLIN;
event.data.fd = fd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event))
PRINT_ERR("epoll ctl error");
}
while (1) {
if ((ret = epoll_wait(epfd, revents, 10, -1)) == -1)
PRINT_ERR("epoll wait error");
for (int i = 0; i < ret; i++) {
if(revents[i].events & EPOLLIN){
memset(buf,0,sizeof(buf));
read(revents[i].data.fd,buf,sizeof(buf));
printf("fd = %d,data = %s\n",revents[i].data.fd,buf);
}
}
}
return 0;
}
1.8 异步通知IO模型
1.8.1 异步通知IO模型实现思想
异步通知IO模型:应用程序在使用异步通知IO模型的时候需要使用signal(SIGIO,handler)
为SIGIO信号绑定一个信号处理函数。应用程序就可以执行任意自己想要执行的代码。当
硬件的数据准备号之后会产生中断,在中断的处理函数中给这个进程发送信号。当进程
收到信号后执行信号处理函数即可。(信号驱动IO)
异步修饰的是通知而不是IO模型
1.8.2 异步通知IO模型实现流程
us:
void handle(int signo)
{
}
signal(SIGIO,handle);
unsigned int flags=fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,flags | FASYNC);
fcntl(fd,F_SETOWN,getpid());
---------------------------------------------------------
VFS: sys_fcntl
SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
sys_fcntl(unsigned int fd,unsigned int cmd,unsigned long arg)
err = do_fcntl(fd, cmd, arg, f.file);
switch (cmd) {
case F_GETFL:
err = filp->f_flags;
break;
case F_SETFL:
err = setfl(fd, filp, arg);
arg = filp->f_flags | FASYNC;
if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) {
error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
}
break;
}
---------------------------------------------------------
ks:fops:
struct fasync_struct *fapp;
int (*fasync) (int fd, struct file *filp, int on)
{
return fasync_helper(fd,filep,on,&fapp);
}
void kill_fasync(&fapp, SIGIO, POLL_IN);
1.8.3 异步通知IO模型的实例
mycdev.c
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#define CNAME "mycdev"
struct cdev* cdev;
unsigned int major = 511;
unsigned int minor = 0;
const int count = 3;
struct class* cls;
struct device* dev;
char kbuf[128] = { 0 };
struct fasync_struct *fapp;
int mycdev_open(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file* file,
char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret) {
printk("copy data to user error\n");
return -EIO;
}
return size;
}
ssize_t mycdev_write(struct file* file,
const char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret) {
printk("copy data form user error\n");
return -EIO;
}
kill_fasync(&fapp,SIGIO,POLL_IN);
return size;
}
int mycdev_fasync(int fd, struct file *filp, int on)
{
return fasync_helper(fd,filp,on,&fapp);
}
int mycdev_close(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
const struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.fasync = mycdev_fasync,
.release = mycdev_close,
};
static int __init mycdev_init(void)
{
int ret, i;
dev_t devno;
cdev = cdev_alloc();
if (cdev == NULL) {
printk("cdev alloc memory error\n");
ret = -ENOMEM;
goto ERR1;
}
cdev_init(cdev, &fops);
if (major > 0) {
ret = register_chrdev_region(MKDEV(major, minor), count, CNAME);
if (ret) {
printk("static:request device number error\n");
goto ERR2;
}
} else {
ret = alloc_chrdev_region(&devno, 0, count, CNAME);
if (ret) {
printk("dynamic:request device number error\n");
goto ERR2;
}
major = MAJOR(devno);
minor = MINOR(devno);
}
ret = cdev_add(cdev, MKDEV(major, minor), count);
if (ret) {
printk("register char device driver error\n");
goto ERR3;
}
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls)) {
printk("class create error\n");
ret = PTR_ERR(cls);
goto ERR4;
}
for (i = 0; i < count; i++) {
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
if (IS_ERR(dev)) {
printk("device create error\n");
ret = PTR_ERR(dev);
goto ERR5;
}
}
return 0;
ERR5:
for (--i; i >= 0; i--) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(MKDEV(major, minor), count);
ERR2:
kfree(cdev);
ERR1:
return ret;
}
static void __exit mycdev_exit(void)
{
int i;
for (i = 0; i < count; i++) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), count);
kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
test.c
#include <head.h>
#include <signal.h>
int fd;
char buf[128] = { 0 };
void handle(int signo)
{
if (signo == SIGIO) {
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf));
printf("buf = %s\n", buf);
}
}
int main(int argc, const char* argv[])
{
if ((fd = open("/dev/mycdev0", O_RDWR)) == -1)
PRINT_ERR("open error");
if ((SIG_ERR == signal(SIGIO, handle)))
PRINT_ERR("signal error");
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
fcntl(fd, F_SETOWN, getpid());
while (1);
close(fd);
return 0;
}
|