读书笔记(4)

8 阻塞和非阻塞

1.阻塞

         阻塞即当资源不可获取的时候,进程进入休眠,将资源礼让给其他进程,进程要阻塞到资源可以获取。

         如果是费阻塞的形式的话,可以借助信号(sigaction)以异步方式访问串口来提高CPU的利用率。

         使用等待队列来实现阻塞进程的唤醒(wait queue):

         定义队列头:wait_queue_head_t  my_queue;                  init_waitqueue_head(& my_queue)             DECLARE_WAIT_QUEUE_HEAD(name)

         定义队列:DECLARE_WAITQUEUE(name.task)

         添加删除队列 add_wait_queue(队列头,队列);   remove_wait_queue()

         等待事件  wait_event(queue,condition)——P163

          schedule() 告诉内核调度别的进程执行,放弃CPU

          list_empty()===>return head->next==head

          唤醒队列 wake_up(wait_queue_head_t * queue)唤醒以queue作为等待队列头的所有等待队列中所有属于该等待队列头的等待队列对应进程

          在等待队列上睡眠sleep_on(wait_queue_head_t *q) 将目前的进程职位TASK_UNINTERRUPTIBLE,直到资源可以换取,q引导的等待队列被唤醒

          其中,wake_up与sleep_on,wait_event成对使用。

          如果,进程状态是TASK_INTERRUPTIBLE的,那么唤醒他的有可能是信号,所以在之后要做一个signal_pending(current)的判断

2.轮询

           使用select和poll费阻塞访问设备-P172

            select()监视读,写和异常处理的文件描述符集合,其中numfds的值为需要检查的文件描述符加一

           配合着用的海曙还有 FD_ZERO(),FD_SET(),FD_CLR().FD_ISSET()

           POLL函数

           poll(struct file * filp ,struct poll_table* wait) 第一个参数为file结构体指针,第二个参数为轮询表指针,对可能引起设备未见状态变化的等待队列调用poll_wait()函数,将对应的等待队列添到poll_table.——P173

           驱动函数poll应该返回设备资源的可获取状态,即POLLIN,POLLOUT,POLLPRI, POLLERR, POLLNVAL. poll本身不会阻塞,它会阻塞的等待文件描述符集合中的至少一个可访问或超时。


9.异步通知和异步I/O

        异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问。这样无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似中断的异步通知所代替。

        信号是软件层次上的一种对中断机制的模拟。阻塞I/O意味着移植等待设备可访问后再访问。非阻塞I/O中使用poll()意味着查询设备是否可访问,而异步通知则是意味着通知自身可访问,实现了异步I/O、

          LINUX的信号在P178有介绍

         signal(SIGINT,sigterm_handler)第一个参数指定信号的值,第二个参数制定对前面信号值的处理函数。

         sigaction(int signum, const struct sigaction * act, struct sigaction * oldaction) 用于改变接收到特定信号后的行为。

         fcntl的用法在帖子里其他地方有介绍,先将本进程设置为STDIN_FILENO的拥有者,然后再修改FASYNC标志。最后就是连接信号的处理函数了。

         对驱动程序来说,对应的关系在P181有,则设备驱动中异步通知的编程主要用到一个数据结构和两个函数。数据结构为fasync_struct,而fasync()的实现只需要简单地将该函数的三个参数和这个结构体传入fasync_helper()。最后在其他位置释放信号,kill_fasync()

          异步I/O,在LINUX中最常用的输入/输出模型是同步I/O,当请求发出后,应用程序就会阻塞,直到请求满足为止。

          AIO基本思想是允许进程发起很多I/O操作,而不用阻塞或等待任何操作完成,稍后活在接受到I/O操作完成的通知时,进程再检索I/O操作的结果。通过aiocb结构体进行区分到底是哪个传输操作完成了。这个结构体包括传输的所有信息,以及为数据准备的用户缓冲区等等。

         一些函数如下:aio_read()          aio_write()       aio_error()   aio_return()  aio_suspend()   aio_cancel()  lio_listio()   ——P188

          应用程序进行异步读操作的步骤如下:首先打开文件,准备aiocb结构体,调用aio_read(&my_aiocb)进行异步读请求,当aio_error(&my_aiocb)判断后,一直等待满足条件,结束后通过aio_return(&my_aiocb)获得返回值。

         (1) 使用信号作为AIO的通知:

         (2) 使用回调函数作为AIO的通知—— 188


 

           

你可能感兴趣的:(arm-linux驱动研究,读书,struct,数据结构,signal,linux,file)