[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作【转】
本文转载自:http://7071976.blog.51cto.com/7061976/1392082
《[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作》涉及内核驱动函数二个,内核结构体零个,分析了内核驱动函数二个;可参考的相关应用程序模板或内核驱动模板二个,可参考的相关应用程序模板或内核驱动一个
一、概念:Poll是非阻塞IO----轮询操作
非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞.
Tip:select()和poll(),epoll查询是否可对设备进行无阻塞的访问,这几个系统调用最终又会引发设备驱动中的poll()函数被执行
PS:看到这感觉晕了,暂且不理会
二、使用场景:
它们常常用在必须使用多输入输出流的应用程序(如调用read,write字符设备驱动文件/dev/****)。因为这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写.
三、相关函数
1、内核函数
内核驱动函数一)a)poll()函数原型:
1
|
unsigned int (*poll) ( struct file *filp, poll_table *wait); |
作用:调用poll_wait(),将可能引起设备文件状态变化的等待队列头添加到poll_table.
返回值:返回是否能对设备进行无阻塞读写访问的掩码
放回值mask常量及函数
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
内核驱动函数二)b)poll_wait()函数原型:
1
|
void poll_wait( struct file *filp, wait_queue_head_t *queue, poll_table *wait); |
作用:将可能引起设备文件状态变化的等待队列头添加到poll_table
2、应用程序poll
函数
1
|
int poll( struct pollfd *fds, nfds_t nfds, int timeout) |
a) 参数:
fds 指向 struct pollfd 数组
nfds 指定 pollfd 数组元素的个数,也就是要监测几个 pollfd
timeout 时间参数,单位ms,1000ms=1s
Tip:fds可以是很多个文件(如网卡,按键),poll可以论寻fds[n]
b)结构体pollfd
struct pollfd {
int fd;
short events;
short revents;
};
3、总结:从应用程序的调用来看,并不需要理会内核函数中的参数poll_table *wait是什么,只需要调用poll_wait()
四、使用模板
模板一)a)内核程序模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
static DECLARE_WAIT_QUEUE_HEAD(waitq); //定义结构体名称为waitq poll( struct file *file, poll_table *wait){ //返回mask unsigned int mask = 0; poll_wait(file, &waitq, wait); if (...) //可读 { mask |= POLLIN | POLLRDNORM; //标识数据可获得 } if (...) //可写 { mask |= POLLOUT | POLLRDNORM; //标识数据可写入 } return mask; } |
模板二)b)测试程序模板
1
2
3
4
|
struct pollfd fds[n]; fds[0].fd = fd; fds[0].events = POLLIN; poll(fds, n, 5000); |
c)再次理解下面几句
fds 指向 struct pollfd 数组
nfds 指定 pollfd 数组元素的个数,也就是要监测几个 pollfd
timeout 时间参数,单位ms,1000ms=1s
Tip:fds可以是很多个文件(如网卡,按键),poll可以论寻fds[n]
实例一)五、案例jz2440中断非阻塞驱动实例
1、 非阻塞内核按键驱动。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
//“irq_drv”,"irq_","irq" #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/poll.h> #include <linux/delay.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //定义结构体名称为button_waitq static struct class *irq_class; static struct class_device *irq_class_dev; static int ev_press = 0; static unsigned char key_val; struct pin_desc{ unsigned int pin; unsigned int key_val; }; struct pin_desc pins_desc[3] = { {S3C2410_GPF0, 0x01}, {S3C2410_GPF2, 0x02}, {S3C2410_GPG3, 0x03}, }; static irqreturn_t irq_handle( int irq, void *dev__id){ //printk("irq = %d\n", irq); int pinval; struct pin_desc *pindesc = ( struct pin_desc *)dev__id; pinval = s3c2410_gpio_getpin(pindesc->pin); if (!pinval){ //按下 key_val = pindesc->key_val; } else { //松开 key_val = 0x80 | pindesc->key_val; } ev_press = 1; wake_up_interruptible(&button_waitq); return IRQ_RETVAL(IRQ_HANDLED); //warn:返回IRQ_HANDLED } static unsigned irq_drv_poll( struct file *file, poll_table *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq, wait); // 不会立即休眠 if (ev_press) mask |= POLLIN | POLLRDNORM; return mask; } static int irq_drv_open( struct inode *inode, struct file *file) { printk( "irq_dev read\n" ); // request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char * devname, void * dev_id); dev_id随意 request_irq(IRQ_EINT0, irq_handle, IRQ_TYPE_EDGE_BOTH, "s2" , &pins_desc[0]); request_irq(IRQ_EINT2, irq_handle, IRQ_TYPE_EDGE_BOTH, "s3" , &pins_desc[1]); request_irq(IRQ_EINT11, irq_handle, IRQ_TYPE_EDGE_BOTH, "s4" , &pins_desc[2]); return 0; } static ssize_t irq_drv_read ( struct file *file, char __user *buf, size_t count, loff_t *ppos){ if (count != 1) return -EINVAL; wait_event_interruptible(button_waitq, ev_press); //ev_press标志(if!(ev_press)),那么一直休眠 copy_to_user(buf, &key_val, 1); //一个 char 0xff ev_press = 0; return 1; //warn :return the size of val } static ssize_t irq_drv_write( struct file *file, const char __user *buf, size_t count, loff_t * ppos) { printk( "irq_dev write\n" ); return 0; } static ssize_t irq_drv_release( struct inode *inode, struct file *file){ free_irq(IRQ_EINT0, &pins_desc[0]); free_irq(IRQ_EINT2, &pins_desc[1]); free_irq(IRQ_EINT11, &pins_desc[2]); return 0; } static struct file_operations irq_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = irq_drv_open, .write = irq_drv_write, .read = irq_drv_read, .release = irq_drv_release, .poll = irq_drv_poll, }; int major; static int irq_drv_init( void ) { major = register_chrdev(0, "irq_drv" , &irq_drv_fops); // 注册, 告诉内核 if (major < 0) { printk( " can't register major number\n" ); return major; } irq_class = class_create(THIS_MODULE, "irq_drv" ); if (IS_ERR(irq_class)) return PTR_ERR(irq_class); irq_class_dev = class_device_create(irq_class, NULL, MKDEV(major, 0), NULL, "irq" ); /* /dev/xyz */ if (IS_ERR(irq_class_dev)) return PTR_ERR(irq_class_dev); return 0; } static void irq_drv_exit( void ) { unregister_chrdev(major, "irq_drv" ); // 卸载 class_device_unregister(irq_class_dev); class_destroy(irq_class); } module_init(irq_drv_init); module_exit(irq_drv_exit); MODULE_LICENSE( "GPL" ); |
2、测试应用程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <poll.h> /* irq */ int main( int argc, char **argv) { int fd; unsigned char key_val; int cnt = 0; int ret; struct pollfd fds[1]; fd = open( "/dev/irq" , O_RDWR); if (fd < 0) { printf ( "can't open!\n" ); exit (1); } fds[0].fd = fd; fds[0].events = POLLIN; while (1) { ret = poll(fds, 1, 5000); if (ret == 0){ printf ( "time out!\n" ); } else { read(fd, &key_val, 1); printf ( "key_Vals = 0x%x\n" , key_val); } } return 0; } Makefile #myirq.bin objs := $(patsubst %c, %o, $(shell ls *.c)) myarmgcc := /workspacearm/armlinuxgcc2626/bin/arm-linux-gcc myirq.bin:$(objs) $(myarmgcc) -o $@ $^ cp *.bin /opt/fsmini/ %.o:%.c $(myarmgcc) -c -o $@ $< clean: rm -f *.bin *.o |
[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作【转】的更多相关文章
- arm驱动linux异步通知与异步IO【转】
转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO> ...
- 嵌入式Linux内核开发工程师必须掌握的三十道题
如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师. 1. Linux中主要有哪几种内核锁?(进程同步与互斥) (1)自旋锁:非睡眠锁 (2)信号量: ...
- 嵌入式系统Linux内核开发工程师必须掌握的三十道题(转)
嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)
IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...
- 🍛 餐厅吃饭版理解 IO 模型:阻塞 / 非阻塞 / IO 复用 / 信号驱动 / 异步
IO 概念 一个基本的 IO,它会涉及到两个系统对象,一个是调用这个 IO 的进程对象,另一个就是系统内核 (kernel).当一个 read 操作发生时,它会经历两个阶段: 通过 read 系统调用 ...
- 编码风格——linux内核开发的coding style
总结linux内核开发的coding style, 便于以后写代码时参考. 下面只是罗列一些规则, 具体说明可以参考: 内核源码(Documentation/CodingStyle) 01 - 缩进 ...
- 如何参与Linux内核开发(转)
本文来源于linux内核代码的Document文件夹下的Hoto文件.Chinese translated version of Documentation/HOWTO If you have any ...
- 如何参与linux 内核开发
如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者. 英文版维护者: Gre ...
- Linux内核开发进阶书籍推荐(不适合初学者)
Linux内核开发进阶书籍推荐(不适合初学者) 很早之前就想写一篇文章总结一下Linux Kernel开发的相关资料,项目的原因,再加上家里的一些事情,一直没能找到闲暇,今天终于有些时间,希望可以完成 ...
随机推荐
- POJ2096 Collecting Bugs(概率DP,求期望)
Collecting Bugs Ivan is fond of collecting. Unlike other people who collect post stamps, coins or ot ...
- Spoj-NETADMIN Smart Network Administrator
The citizens of a small village are tired of being the only inhabitants around without a connection ...
- charts 画饼图
统计某一天某类物体的百分比 新知识点:aggregate https://blog.csdn.net/congcong68/article/details/51619882 主要的 $group $m ...
- android系统编译打开系统蓝牙
在项目配置文件ProjectConfig.mk中开启蓝牙以后,但是设置菜单中并没有出现蓝牙选项,最后发现是因为ProjectConfig.mk同级目录下没有蓝牙配置文件android.hardware ...
- android开发里跳过的坑——TimePickerDialog onTimeSet不回调
在android6.0.1上测试发现TimePickerDialog的onTimeSet和DatePickerDialog的onDateSet不回调,查看SDK源码发现,TimePickerDialo ...
- 牛客练习赛1 矩阵 字符串二维hash+二分
题目 https://ac.nowcoder.com/acm/contest/2?&headNav=www#question 解析 我们对矩阵进行二维hash,所以每个子矩阵都有一个额hash ...
- GRYZY #13. 拼不出的数
拼不出的数 lost.in/.out/.cpp [问题描述] 3 个元素的集合 {5, 1, 2} 的所有子集的和分别是 0, 1, 2, 3, 5, 6, 7, 8.发 现最小的不能由该集合子集拼出 ...
- luogu P2912 [USACO08OCT]牧场散步Pasture Walking
题目描述 The N cows (2 <= N <= 1,000) conveniently numbered 1..N are grazing among the N pastures ...
- Codeforces 375 D Tree and Queries
Discription You have a rooted tree consisting of n vertices. Each vertex of the tree has some color. ...
- android 4.4以上能够实现的沉浸式状态栏效果
仅仅有android4.4以及以上的版本号才支持状态栏沉浸效果 先把程序执行在4.4下面的手机上,看下效果: 在4.4以上的效果: watermark/2/text/aHR0cDovL2Jsb2cuY ...