堵塞 / 非堵塞 IO
IO:是指对于内存的读写操作,很多时候读跟写存在互斥性不能同时进行,亦或者没法多个线程实现同时读写
堵塞:对应线程获取不到资源则被挂起,优势让出 CPU 资源
非堵塞:一直轮循等待
堵塞方式打开文件: fd = open("xx", O_RDWR);
非堵塞方式打开文件: fd = open("xx", O_RDWR | O_NONBLOCK);
堵塞IO
1. 等待队列
1.1 等待队列头
在驱动中使用等待队列,必须创建一个等待队列头,使用 wait_queue_head_t 表示 (include/linux/wait.h)
函数 | 描述 |
---|---|
void init_waitqueue_head(wait_queue_head_t *q); | 初始化等待队列头 |
DECLARE_WAIT_QUEUE_HEAD() | 一次性完成定义和初始化 |
1.2 等待队列项
每个设备的进程都是一个队列项,当设备不可用的时候需要将它们的等待队列项加入到等待队列里
DECLARE_WAITQUEUE(name, tsk); 完成定义和初始化一个等待队列项
1.3 添加/移除等待队列头
函数 | 描述 |
---|---|
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) | 等待队列添加 |
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) | 等待队列移除 |
void wake_up(wait_queue_head_t *q) | 唤醒进程 TASK_INTERRUPTIBLE 和 TASK_UNINTERRUPTIBLE |
void wake_up_interruptible(wait_queue_head_t *q) | 只能唤醒 TASK_INTERRUPTIBLE 进程 |
void wait_event(wq, condition) | 等待 wq 为等待队列头的等待队列被唤醒,前提满足 condition 为true,否则一直堵塞(状态:TASK_UNINTERRUPTIBLE) |
int wait_event_timeout(wq, condition, timeout) | 可以添加超时时间,返回0:false && 超时; 返回1:true 条件满足 |
void wait_event_interruptible(wq, condition) | 将状态设置为 TASK_INTERRUPTIBLE 可以被信号打断状态 |
int wait_event_interruptible_timeout(wq, condition, timeout) | 同上面类似 |
非堵塞 IO
2. 轮询
程序可用通过 poll / epoll / select 来查询设备是否可以操作
2.1 select(单个线程中默认能够监视最多 1024 个,可以通过修改内核增大,但会降低效率)
函数 | 描述 |
---|---|
void FD_ZERO(fd_set* set) | 将所有 fd_set 变量所有位清零 |
void FD_SET(int fd, fd_set* set) | 将某个位置 1 |
void FD_CLR(int fd, fd_set* set) | 置0 |
int FD_ISSET(int fd, fd_set* set) | 可以判断进行操作 |
EG
int ret, fd;
fd_set readfds;
struct timeval timeout;
fd = open("xxx", O_RDWR | O_NONBLOCK);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
//超时
timeout.tv_sec = 0;
timeout.tv_usec = 500000; //500ms
ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
switch(ret) {
case 0:
printf("timeout \n"); break;
case -1:
printf("error \n"); break;
default:
if (FD_ISSET(fd, &readfds)) {
//使用 read 读数据
}
break;
}
2.2 poll 函数(与 select 效果相似,但是没有最大文件描述符数量限制)
void poll_wait(struct file* filp, wait_queue_head_t* wait_address, poll_table* p); //将 应用程序加入到 poll_table 中
POLLIN 有数据可读
POLLPRI 有紧急数据需要读取
POLLOUT 可以写数据
POLLERR 指定文件描述符发送错误
POLLHUP 制定文件描述符挂起
POLLNVAL 无效请求
POLLRDNORM 等同于 POLLIN
int ret, fd;
struct pollfd fds;
fd = open(filename, O_RDWR | O_NONBLOCK);
fds.fd = fd;
fds.events = POLLIN;
ret = poll(&fds, 1, 500);
if (ret) {
//读取设备
} else if (ret == 0) {
//超时
} else if (ret < 0) {
//错误
}
2.3 epoll 为处理大并发,网络编程常用 epoll
int epoll_create(0); //创建一个 epoll 句柄
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout); //等待事件发生
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //向 epoll 加入监视文件描述符及监视事件
op: 操作设置
EPOLL_CTL_ADD 添加
EPOLL_CTL_MOD 修改
EPOLL_CTL_DEL 删除
events:
EPOLLIN 有数据可读
EPOLLOUT 写数据
EPOLLPRI 有紧急数据需要读取
EPOLLERR 指定文件描述符发生错误
EPOLLHUP 指定的文件描述符挂起
EPOLLET 设置 epoll 为边沿触发,默认为水平触发
EPOLLONESHOT 一次性的监视
程序讲解
堵塞 IO
DECLARE_WAITQUEUE(wait, current);
if (atomic_read(&dev->releasekey) == 0) {
add_wait_queue(&dev->r_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE); //设置任务状态
schedule(); //进程调度,令进程进度进入休眠
if (signal_pending(current)) { //若由信号唤醒则报错
ret = -ERESTARTSYS;
goto wait_error;
}
}
remove_wait_queue(&dev->r_wait, &wait); //移除队列
wait_error:
set_current_state(TASK_RUNNING); //运行状态
remove_wait_queue(&dev->r_wait, &wait);//从队列去除
return ret;
非堵塞 IO
if (filp->f_flags & O_NONBLOCK) {
if (atomic_read(&dev->releasekey) == 0)
return -EAGAIN; //没按下则返回重试值
} else {
ret = wait_event_interruptible(dev->r_wait, atomic_read(&dev->releasekey));
if (ret) {
goto wait_error;
}
}
//由应用程序调用 select 或 poll 时调用, 调用 poll_wait 将等待队列加入到 poll_table 中
unsigned int imx6uirq_poll(struct file *filp, struct poll_table_struct* wait)
{
unsigned int mask = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev*) filp->private_data;
poll_wait(filp, &dev->r_wait, wait);
if (atomic_read(&dev->releasekey)) {
mask = POLLIN | POLLRDNORM;
}
return mask;
}
堵塞IO 例程
//堵塞方式IO
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME "blockio"
#define KEY0VLAUE 0x01 //按键值
#define INVAKEY 0xFF //无效按键值
#define KEY_NUM 1
//中断 IO 描述结构体
struct irq_keydesc {
int gpio;
int irqnum;
unsigned char value;
char name[10];
irqreturn_t (*handler)(int, void*);
};
struct imx6uirq_dev {
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;
atomic_t keyvalue;
atomic_t releasekey;
struct timer_list timer;
struct irq_keydesc irqkeydesc [KEY_NUM];
unsigned char curkeynum;
wait_queue_head_t r_wait; //读等待队列头
};
struct imx6uirq_dev imx6uirq;
static irqreturn_t key0_handler(int irq, void* dev_id)
{
struct imx6uirq_dev *dev = (struct imx6uirq_dev *) dev_id;
dev->curkeynum = 0;
dev->timer.data = (volatile long) dev_id;
//10ms 并激活定时器
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10));
return IRQ_RETVAL(IRQ_HANDLED);
}
void timer_function(unsigned long arg)
{
unsigned char value;
unsigned char num;
struct irq_keydesc *keydesc;
struct imx6uirq_dev *dev = (struct imx6uirq_dev*) arg;
num = dev->curkeynum;
keydesc = &dev->irqkeydesc[num];
value = gpio_get_value(keydesc->gpio);
if (0 == value) {
atomic_set(&dev->keyvalue, keydesc->value);
} else {
atomic_set(&dev->keyvalue, 0x80 | keydesc->value);
atomic_set(&dev->releasekey, 1);
}
//唤醒进程
if (atomic_read(&dev->releasekey)) {
wake_up_interruptible(&dev->r_wait);
}
}
static int keyio_init(void)
{
unsigned char i = 0;
char name[10];
int ret = 0;
imx6uirq.nd = of_find_node_by_path("/key");
if (NULL == imx6uirq.nd) {
return -EINVAL;
}
for (i = 0; i < KEY_NUM; i++) {
imx6uirq.irqkeydesc[i].gpio = of_get_named_gpio(imx6uirq.nd, "key-gpio", i);
if (imx6uirq.irqkeydesc[i].gpio < 0) {
printk("can't get key %d \n", i);
}
}
for (i = 0; i < KEY_NUM; i++) {
memset(imx6uirq.irqkeydesc[i].name, 0, sizeof (name));
sprintf(imx6uirq.irqkeydesc[i].name, "KEY%d", i);
gpio_request(imx6uirq.irqkeydesc[i].gpio, name); //向内核申请 GPIO
gpio_direction_input(imx6uirq.irqkeydesc[i].gpio);
imx6uirq.irqkeydesc[i].irqnum = irq_of_parse_and_map(imx6uirq.nd, i); //获取中断号
#if 0
imx6uirq.irqkeydesc[i].irqnum = gpio_to_irq(imx6uirq.irqkeydesc[i].gpio);
#endif
printk("key%d: gpio = %d, irqnum = %d \n", i, imx6uirq.irqkeydesc[i].gpio,
imx6uirq.irqkeydesc[i].irqnum);
}
//申请中断
imx6uirq.irqkeydesc[0].handler = key0_handler;
imx6uirq.irqkeydesc[0].value = KEY0VLAUE;
for (i = 0; i < KEY_NUM; i++) {
ret = request_irq(imx6uirq.irqkeydesc[i].irqnum,
imx6uirq.irqkeydesc[i].handler,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
imx6uirq.irqkeydesc[i].name, &imx6uirq);
if (0 > ret) {
printk("irq %d request failed! \n", imx6uirq.irqkeydesc[i].irqnum);
return -EFAULT;
}
}
//创建定时器
init_timer(&imx6uirq.timer);
imx6uirq.timer.function = timer_function;
//初始化队列头
init_waitqueue_head(&imx6uirq.r_wait);
return 0;
}
static int imx6uirq_open(struct inode *inode, struct file *filp)
{
filp->private_data = &imx6uirq;
return 0;
}
static ssize_t imx6uirq_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char keyvalue = 0, releasekey = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data;
#if 0
ret = wait_event_interruptible(dev->r_wait, atomic_read(&dev->releasekey));
if (ret) {
goto wait_error;
}
#endif
DECLARE_WAITQUEUE(wait, current);
if (atomic_read(&dev->releasekey) == 0) {
add_wait_queue(&dev->r_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE); //设置任务状态
schedule(); //进行一次进程调度,令进程进入休眠
if (signal_pending(current)) { //判断是否因为信号而被唤醒,是则报错
ret = -ERESTARTSYS;
goto wait_error;
}
}
remove_wait_queue(&dev->r_wait, &wait);
keyvalue = atomic_read(&dev->keyvalue);
releasekey = atomic_read(&dev->releasekey);
if (releasekey) {
if (keyvalue & 0x80) {
keyvalue &= ~0x80;
ret = copy_to_user(buf, &keyvalue, sizeof (keyvalue));
} else {
goto data_error;
}
atomic_set(&dev->releasekey, 0); //清除按键标志
} else {
goto data_error;
}
return 0;
wait_error:
set_current_state(TASK_RUNNING); //运行状态
remove_wait_queue(&dev->r_wait, &wait);//从队列去除
return ret;
data_error:
return -EINVAL;
}
static struct file_operations imx6uirq_fops = {
.owner = THIS_MODULE,
.open = imx6uirq_open,
.read = imx6uirq_read,
};
static int __init imx6uirq_init(void)
{
if (imx6uirq.major) {
imx6uirq.devid = MKDEV(imx6uirq.major, 0);
register_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT, IMX6UIRQ_NAME);
} else {
alloc_chrdev_region(&imx6uirq.devid, 0, IMX6UIRQ_CNT, IMX6UIRQ_NAME);
imx6uirq.major = MAJOR(imx6uirq.devid);
imx6uirq.minor = MINOR(imx6uirq.devid);
}
//注册字符设备
cdev_init(&imx6uirq.cdev, &imx6uirq_fops);
cdev_add(&imx6uirq.cdev, imx6uirq.devid, IMX6UIRQ_CNT);
imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.class)) {
return PTR_ERR(imx6uirq.class);
}
imx6uirq.device = device_create(imx6uirq.class, NULL,
imx6uirq.devid, NULL, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.device)) {
return PTR_ERR(imx6uirq.device);
}
//初始化按键
atomic_set(&imx6uirq.keyvalue, INVAKEY);
atomic_set(&imx6uirq.releasekey, 0);
keyio_init();
return 0;
}
static void __exit imx6uirq_exit(void)
{
unsigned int i = 0;
del_timer_sync(&imx6uirq.timer);
for (i = 0; i < KEY_NUM; i++) {
free_irq(imx6uirq.irqkeydesc[i].irqnum, &imx6uirq);
}
cdev_del(&imx6uirq.cdev);
unregister_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT);
device_destroy(imx6uirq.class, imx6uirq.devid);
class_destroy(imx6uirq.class);
}
module_init(imx6uirq_init);
module_exit(imx6uirq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zzz");
//APP 堵塞读 IO
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/ioctl.h>
int main(int argc, char* argv[])
{
int fd, ret = 0;
char* filename;
unsigned char data;
if (argc != 2) {
printf("Error Usage! \n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if (fd < 0) {
printf("file %s open failed ! \n", argv[1]);
return -1;
}
while(1) {
ret = read(fd, &data, sizeof (data));
if (0 > ret) {
//数据异常
} else {
if (data)
printf("key value = %#X \n", data);
}
}
ret = close(fd);
if (ret < 0) {
printf("file %s close failed !\n", argv[1]);
return -1;
}
return 0;
}
非堵塞IO 例程
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME "noblockio"
#define KEY0VLAUE 0x01 //按键值
#define INVAKEY 0xFF //无效按键值
#define KEY_NUM 1
//中断 IO 描述结构体
struct irq_keydesc {
int gpio;
int irqnum;
unsigned char value;
char name[10];
irqreturn_t (*handler)(int, void*);
};
struct imx6uirq_dev {
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;
atomic_t keyvalue;
atomic_t releasekey;
struct timer_list timer;
struct irq_keydesc irqkeydesc [KEY_NUM];
unsigned char curkeynum;
wait_queue_head_t r_wait; //读等待队列头
};
struct imx6uirq_dev imx6uirq;
static irqreturn_t key0_handler(int irq, void* dev_id)
{
struct imx6uirq_dev *dev = (struct imx6uirq_dev *) dev_id;
dev->curkeynum = 0;
dev->timer.data = (volatile long) dev_id;
//10ms 并激活定时器
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10));
return IRQ_RETVAL(IRQ_HANDLED);
}
void timer_function(unsigned long arg)
{
unsigned char value;
unsigned char num;
struct irq_keydesc *keydesc;
struct imx6uirq_dev *dev = (struct imx6uirq_dev*) arg;
num = dev->curkeynum;
keydesc = &dev->irqkeydesc[num];
value = gpio_get_value(keydesc->gpio);
if (0 == value) {
atomic_set(&dev->keyvalue, keydesc->value);
} else {
atomic_set(&dev->keyvalue, 0x80 | keydesc->value);
atomic_set(&dev->releasekey, 1);
}
//唤醒进程
if (atomic_read(&dev->releasekey)) {
wake_up_interruptible(&dev->r_wait);
}
}
static int keyio_init(void)
{
unsigned char i = 0;
char name[10];
int ret = 0;
imx6uirq.nd = of_find_node_by_path("/key");
if (NULL == imx6uirq.nd) {
return -EINVAL;
}
for (i = 0; i < KEY_NUM; i++) {
imx6uirq.irqkeydesc[i].gpio = of_get_named_gpio(imx6uirq.nd, "key-gpio", i);
if (imx6uirq.irqkeydesc[i].gpio < 0) {
printk("can't get key %d \n", i);
}
}
for (i = 0; i < KEY_NUM; i++) {
memset(imx6uirq.irqkeydesc[i].name, 0, sizeof (name));
sprintf(imx6uirq.irqkeydesc[i].name, "KEY%d", i);
gpio_request(imx6uirq.irqkeydesc[i].gpio, name); //向内核申请 GPIO
gpio_direction_input(imx6uirq.irqkeydesc[i].gpio);
imx6uirq.irqkeydesc[i].irqnum = irq_of_parse_and_map(imx6uirq.nd, i); //获取中断号
#if 0
imx6uirq.irqkeydesc[i].irqnum = gpio_to_irq(imx6uirq.irqkeydesc[i].gpio);
#endif
printk("key%d: gpio = %d, irqnum = %d \n", i, imx6uirq.irqkeydesc[i].gpio,
imx6uirq.irqkeydesc[i].irqnum);
}
//申请中断
imx6uirq.irqkeydesc[0].handler = key0_handler;
imx6uirq.irqkeydesc[0].value = KEY0VLAUE;
for (i = 0; i < KEY_NUM; i++) {
ret = request_irq(imx6uirq.irqkeydesc[i].irqnum,
imx6uirq.irqkeydesc[i].handler,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
imx6uirq.irqkeydesc[i].name, &imx6uirq);
if (0 > ret) {
printk("irq %d request failed! \n", imx6uirq.irqkeydesc[i].irqnum);
return -EFAULT;
}
}
//创建定时器
init_timer(&imx6uirq.timer);
imx6uirq.timer.function = timer_function;
//初始化队列头
init_waitqueue_head(&imx6uirq.r_wait);
return 0;
}
static int imx6uirq_open(struct inode *inode, struct file *filp)
{
filp->private_data = &imx6uirq;
return 0;
}
static ssize_t imx6uirq_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char keyvalue = 0, releasekey = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data;
if (filp->f_flags & O_NONBLOCK) {
if (atomic_read(&dev->releasekey) == 0)
return -EAGAIN;
} else {
ret = wait_event_interruptible(dev->r_wait, atomic_read(&dev->releasekey));
if (ret) {
goto wait_error;
}
}
keyvalue = atomic_read(&dev->keyvalue);
releasekey = atomic_read(&dev->releasekey);
if (releasekey) {
if (keyvalue & 0x80) {
keyvalue &= ~0x80;
ret = copy_to_user(buf, &keyvalue, sizeof (keyvalue));
} else {
goto data_error;
}
atomic_set(&dev->releasekey, 0); //清除按键标志
} else {
goto data_error;
}
return 0;
wait_error:
return ret;
data_error:
return -EINVAL;
}
unsigned int imx6uirq_poll(struct file *filp, struct poll_table_struct* wait)
{
unsigned int mask = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev*) filp->private_data;
poll_wait(filp, &dev->r_wait, wait);
if (atomic_read(&dev->releasekey)) {
mask = POLLIN | POLLRDNORM;
}
return mask;
}
static struct file_operations imx6uirq_fops = {
.owner = THIS_MODULE,
.open = imx6uirq_open,
.read = imx6uirq_read,
.poll = imx6uirq_poll,
};
static int __init imx6uirq_init(void)
{
if (imx6uirq.major) {
imx6uirq.devid = MKDEV(imx6uirq.major, 0);
register_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT, IMX6UIRQ_NAME);
} else {
alloc_chrdev_region(&imx6uirq.devid, 0, IMX6UIRQ_CNT, IMX6UIRQ_NAME);
imx6uirq.major = MAJOR(imx6uirq.devid);
imx6uirq.minor = MINOR(imx6uirq.devid);
}
//注册字符设备
cdev_init(&imx6uirq.cdev, &imx6uirq_fops);
cdev_add(&imx6uirq.cdev, imx6uirq.devid, IMX6UIRQ_CNT);
imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.class)) {
return PTR_ERR(imx6uirq.class);
}
imx6uirq.device = device_create(imx6uirq.class, NULL,
imx6uirq.devid, NULL, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.device)) {
return PTR_ERR(imx6uirq.device);
}
//初始化按键
atomic_set(&imx6uirq.keyvalue, INVAKEY);
atomic_set(&imx6uirq.releasekey, 0);
keyio_init();
return 0;
}
static void __exit imx6uirq_exit(void)
{
unsigned int i = 0;
del_timer_sync(&imx6uirq.timer);
for (i = 0; i < KEY_NUM; i++) {
free_irq(imx6uirq.irqkeydesc[i].irqnum, &imx6uirq);
}
cdev_del(&imx6uirq.cdev);
unregister_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT);
device_destroy(imx6uirq.class, imx6uirq.devid);
class_destroy(imx6uirq.class);
}
module_init(imx6uirq_init);
module_exit(imx6uirq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zzz");
//非堵塞IO APP
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
int main(int argc, char* argv[])
{
int fd, ret = 0;
char* filename;
struct pollfd fds;
fd_set readfds;
struct timeval timeout;
unsigned char data;
if (argc != 2) {
printf("Error Usage! \n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR | O_NONBLOCK);
if (fd < 0) {
printf("file %s open failed ! \n", argv[1]);
return -1;
}
#if 0
fds.fd = fd;
fds.events = POLLIN;
while( 1) {
ret = poll(&fds, 1, 500);
if (ret) {
ret = read(fd, &data, sizeof(data));
if (ret < 0) {
//读取错误
} else {
if (data)
printf("key value = %d \n", data);
}
} else if (ret == 0) {
//超时
} else if (ret < 0) {
//错误
}
}
#endif
while (1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
ret = select(fd+1, &readfds, NULL, NULL, &timeout);
switch (ret) {
case 0: //超时
break;
case -1:
//错误
break;
default:
//读取错误
if (FD_ISSET(fd, &readfds)) {
ret = read(fd, &data, sizeof (data));
if (ret < 0) {
//读取错误
} else {
if (data)
printf("key value = %d \n", data);
}
}
break;
}
}
ret = close(fd);
if (ret < 0) {
printf("file %s close failed !\n", argv[1]);
return -1;
}
return 0;
}
编译方式
KERNELDIR := /home/xza/workspace/01_linux_kernel/test/imx_4.1.15_2.0.0_ga_rc3/
CURRENT_PATH := $(shell pwd)
obj-m := blockio.o
build: kernel_modules
kernel_modules:
$(MAKE) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- EXTRA_CFLAGS=-fno-pic -C $(KERNELDIR) M=`pwd` modules
clean:
$(MAKE) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNELDIR) M=`pwd` clean
驱动:make
APP: arm-linux-gnueabihf-gcc blockio_app.c -o blockio
测试: ./blockio /dev/imx6uirq & 查看 top 可以看到 CPU 占用率很低