一、阻塞和非阻塞
所谓阻塞,就是等待某件事情发生。比如调用 read 读取按键时,如果没有按键数据则 read 函数不会返回,它会让线程休眠等待。
使用 poll 时,如果传入的超时时间不为 0,这种访问方法也是阻塞的。
APP 调用 open 函数时,传入 O_NONBLOCK,就表示要使用非阻塞方式;默认是阻塞方式。
注意:对于普通文件、块设备文件,O_NONBLOCK 不起作用。
注意:对于字符设备文件,O_NONBLOCK 起作用的前提是驱动程序针对 O_NONBLOCK 做了处理。
在 open 之后,也可以通过 fcntl 修改为阻塞或非阻塞。
1、应用层
1、open时设置
int fd = open(“/dev/xxx”, O_RDWR | O_NONBLOCK); /* 非阻塞方式 */
int fd = open(“/dev/xxx”, O_RDWR ); /* 阻塞方式 */
2、open之后设置
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* 非阻塞方式 */
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); /* 阻塞方式 */
2、驱动层
以drv_read为例:
static ssize_t drv_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
{
if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
}
在内核中会有一个 struct file 结构体对应这个驱动,这个结构体中有 f_flags,就是打开文件时的标记位;可以设置 f_flasgs 的 O_NONBLOCK 位,表示非阻塞;也可以清除这个位表示阻塞。
二、中断的线程化
对于中断处理,还有另一种方法:threaded irq,线程化的中断处理。中断的处理仍然可以认为分为上
半部、下半部。上半部用来处理紧急的事情,下半部用一个内核线程来处理,这个内核线程专用于这个中断。
1、创建线程化中断 request_threaded_irq
int request_threaded_irq(unsigned int irq,
irq_handler_t handler,
irq_handler_t thread_fn,
unsigned long irqflags,
const char *devname,
void *dev_id);
thread_fn :创建内核线程去处理的函数
① 上半部函数如果不提供:
内核会提供默认的上半部处理函数:irq_default_primary_handler,它是直接返回 IRQ_WAKE_THREAD。
② 上半部函数如果提供的话:
返回值必须是:IRQ_WAKE_THREAD。
在 thread_fn 中,如果中断被正确处理了,应该返回 IRQ_HANDLED。
2、卸载中断 free_irq
void free_irq(unsigned int irq, void *dev_id)