5 c语言调用Linux的sleepy函数,Linux设备驱动程序学习( 三 )


;
(&);
/*常用的做法是放一个在循环的顶部,来实现休眠 。*//* (2)添加等待队列入口到队列,并设置进程状态:*/
void ( *queue,*wait, int state);
/*queue 和 wait 分别地是等待队列头和进程入口 。state 是进程的新状态:(可中断休眠,推荐)或(不可中断休眠,不推荐) 。*/
/* (3)在检查确认仍然需要休眠之后调用 */
();
/* (4) 返回,就到了清理时间:*/
void ( *queue,*wait);
认真地看简单休眠中的 (queue, ) 和ible(queue, ) 底层源码会发现,其实他们只是手工休眠中的函数的组合 。所以怕麻烦的话还是用比较好 。
独占等待
当一个进程调用在等待队列上,所有的在这个队列上等待的进程被置为可运行的 。这在许多情况下是正确的做法 。但有时,可能只有一个被唤醒的进程将成功获得需要的资源,而其余的将再次休眠 。这时如果等待队列中的进程数目大,这可能严重降低系统性能 。为此,内核开发者增加了一个“独占等待”选项 。它与一个正常的睡眠有 2 个重要的不同:
(1)当等待队列入口设置了标志,它被添加到等待队列的尾部;否则,添加到头部 。
(2)当被在一个等待队列上调用, 它在唤醒第一个有标志的进程后停止唤醒.但内核仍然每次唤醒所有的非独占等待 。
采用独占等待要满足 2 个条件:
(1)希望对资源进行有效竞争;
(2)当资源可用时,唤醒一个进程就足够来完全消耗资源 。
使一个进程进入独占等待,可调用:
void usive( *queue,*wait, int state);
注意:无法使用和它的变体来进行独占等待.
唤醒的相关函数
很少会需要调用e 之外的唤醒函数,但为完整起见,这里是整个集合:
( *queue);
e( *queue);
/* 唤醒队列中的每个非独占等待进程和一个独占等待进程 。e 同样, 除了它跳过处于不可中断休眠的进程 。它们在返回之前, 使一个或多个进程被唤醒、被调度(如果它们被从一个原子上下文调用, 这就不会发生).*/( *queue, int nr);
e_nr( *queue, int nr);
/*这些函数类似 , 除了它们能够唤醒多达 nr 个独占等待者, 而不只是一个. 注意传递 0 被解释为请求所有的互斥等待者都被唤醒*/
( *queue);
e_all( *queue);
/*这种唤醒所有的进程, 不管它们是否进行独占等待(可中断的类型仍然跳过在做不可中断等待的进程)*/( *queue);
/*一个被唤醒的进程可能抢占当前进程, 并且在返回之前被调度到处理器 。但是, 如果你需要不要被调度出处理器时,可以使用 e 的"同步"变体. 这个函数最常用在调用者首先要完成剩下的少量工作,且不希望被调度出处理器时 。*/
poll 和
当应用程序需要进行对多文件读写时,若某个文件没有准备好,则系统会处于读写阻塞的状态,并影响了其他文件的读写 。为了避免这种情况,在必须使用多输入输出流又不想阻塞在它们任何一个上的应用程序常将非阻塞 I/O和 poll( V)、(BSD Unix)、 epoll(.5.45开始)系统调用配合使用 。当poll函数返回时,会给出一个文件是否可读写的标志,应用程序根据不同的标志读写相应的文件,实现非阻塞的读写 。这些系统调用功能相同: 允许进程来决定它是否可读或写一个或多个文件而不阻塞 。这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写 。这些调用都需要来自设备驱动中poll 方法的支持,poll返回不同的标志,告诉主进程文件是否可以读写,其原型(定义在 ):
int (*poll) ( file *filp,*wait);
实现这个设备方法分两步:
1. 在一个或多个可指示查询状态变化的等待队列上调用 . 如果没有文件描述符可用来执行 I/O, 内核使这个进程在等待队列上等待所有的传递给系统调用的文件描述符.驱动通过调用函数 增加一个等待队列到结构,原型: