Linux下的I/O模型
Linux下数据的读取主要有两步:等待数据到来和把数据从内核层拷贝到应用层。
I/O模型分为同步I/O和异步I/O,同步I/O包括阻塞I/O、非阻塞I/O、I/O复用和信号驱动I/O。
阻塞I/O指系统调用发起直到数据拷贝到应用层才返回。非阻塞I/O指如果需要等待数据,则返回一个错误,但是从内核到应用的拷贝仍需要等待。I/O复用会先阻塞在select上,有数据可读了再去读,这个时候一定有数据,所以只会等待内核到应用的拷贝。信号驱动I/O指有数据了驱动会通过SIGIO信号通知进程,然后进程调用系统调用去读数据,依然会等待内核到应用的拷贝。异步I/O也是采用信号通知,他是整个拷贝全部完成后通知。
阻塞I/O和非阻塞I/O的驱动实现
int read()
{
down_interruptible(sem);
while(rp==wp){ 无数据
up(sem);
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN; 非阻塞I/O
wait_event_interruptible();
down_interruptible(sem);
}
copy_to_user(count);
up(sem);
return count;
}
I/O复用的驱动实现,主要是用poll_wait向poll_table里添加等待队列,然后返回哪个操作可以执行的位掩码。
异步I/O在驱动的fasync方法中调用fasync_helper(&dev->async_queue),当一个打开文件的FASYNC标志被修改时,从相关的进程列表中增加或删除文件,在数据到达时,使用kill_fasync通知所有的相关进程,kill_fasync(&dev->async_queue,SIGIO,POLL_IN)。注意在驱动的close方法中也要调用fasync方法,以便从活动的异步读取进程列表中删除该文件。