分类: 嵌入式
2015-06-01 19:04:03
字符驱动中阻塞与非阻塞方式
15年5月6日09:42:42
阻塞操作:是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,直到等待的条件被满足。
非阻塞操作:设备在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。
简单来说,阻塞操作就是如果想去读一个按键值,当前没有按键按下的话,就一直等待,直到有按键按下才返回。而非阻塞操作就是 当前没有按键按下的话,就返回,返回一个错误或其他。
怎么分辨是阻塞还是非阻塞:
在应用程序的open函数的标记位中,传入一个参数,如果传入O_NONBLOCK的话,就是非阻塞操作,如果不传入这个参数,默认就是阻塞操作。
fd = open( “...”, O_RDWR | O_NONBLOCK);
同样,我们的驱动程序中需要对这个标记位进行处理,才能实现阻塞与非阻塞操作。这个标记位在file结构体中的 f_flags中,所以判断一个open函数中是否传入了 O_NONBLOCK参数,使用 if (file->f_flags & O_NONBLOCK) 这个语句。
代码如下(其他代码同为sixth_drv.c):
69 static int sixth_drv_open(struct inode *inode, struct file *file)
70 {
71 #if 0
72 if (!atomic_dec_and_test(&canopen))
73 {
74 atomic_inc(&canopen);
75 return -EBUSY;
76 }
77 #endif
78
79 if (file->f_flags & O_NONBLOCK) //判断是不是非阻塞操作
80 {
81 if (down_trylock(&button_lock)) /*非阻塞操作,立即判断能不能获得*/
/*button_lock这个信号量,如果不能获得,就返回。这时候需要使用 down_trylock。*/
82 return -EBUSY;
83 }
84 else //阻塞操作
85 {
86 down(&button_lock);
87 }
88 request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
89 request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
90 request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
91 request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
92 return 0;
93 }
94
94
95 ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos){
96
97 if(size != 1)
98 return -EINVAL;
99
100 if (file->f_flags & O_NONBLOCK)
101 {
102 if (!ev_press) //如果为非阻塞的话,立即判断有没有按键按下。
103 return -EAGAIN; //如果没有按键按下的话,立即返回-EAGAIN。
104 }
105 else
106 {
107 wait_event_interruptible(button_waitq, ev_press);
108 }
109 copy_to_user(buf, &key_val, 1);
110
111 ev_press = 0;
112
113 return 1;
114 }
115
测试程序(非阻塞方式)代码:
10
11 int fd;
12
13 void my_signal_fun(int signum)
14 {
15 unsigned char key_val;
16 read(fd, &key_val, 1);
17 printf("key_val: 0x%x\n", key_val);
18 }
19
20 int main (int argc, char **argv)
21 {
22 unsigned char key_val;
23 int ret;
24 int Oflags;
25
26 //signal(SIGIO, my_signal_fun);
27
28 fd = open("/dev/buttons",O_RDWR | O_NONBLOCK); //阻塞与非阻塞的区别。
29
30 if (fd < 0)
31 {
32 printf("cannot open!\n");
33 return -1;
34 }
35 //fcntl(fd, F_SETOWN, getpid());
36 //Oflags = fcntl(fd, F_GETFL);
37 //fcntl(fd, F_SETFL, Oflags | FASYNC);
38
39 while (1)
40 {
41 ret = read(fd, &key_val, 1);
42 printf("key_val: 0x%x\n, ret = %d\n", key_val, ret);
43 sleep(5);
44 }
45 return 0;
46 }
先测试阻塞方式:
刚开始的时候,没有注释掉sleep这一行,就出现了下图所示的结果: