一、ioctl
- ioctl系统调用可以实现用户空间的各种需求,比如报告错误信息,改变波特率,执行自破坏等
- 用户空间的ioctl(int fd, unsigned long cmd, …)后面的三个点表示的是可变参数目的参数表。这些点并不是数目不定的一串参数,而只是一个可选参数。另外这些点只是为了在编译时防止编译器进行类型检查。第三个参数的具体形式依赖于要完成的控制命令,也就是第二个参数。某些控制命令不需要参数,某些需要一个整型参数,而某些只需要一个指针参数。由于…躲过了编译器,所以如果ioctl传递了一个非法参数,编译器是无法报警的,这样,相关联的程序错误就很难发现。所以内核的ioctl使用swtich语句来解决这个问题,区分命令的类型。
二、阻塞I/O
1.概述
- 对于用户来说,调用read/write函数进行读写,而如果数据不可用时或者输出缓冲区已满,而调用进程通常不会关心这类问题,程序员只会简单调用read,write,然后等待必要的工作结束后返回调用。因此,在这种情况下,我们的驱动程序应该(默认)阻塞该进程,将其置入休眠状态直到请求可继续。
2.休眠介绍
-
进程休眠的三条规则
1.永远不要在原子上下文中进入休眠。原子上下文指的是下面这种状态:在执行多个步骤时,不能有任何的并发访问,也即独占cpu,完成整个过程。所以休眠不能使用在拥有spinlock,seqlock或者RCU锁时休眠,即使禁止了中断,也不能休眠。拥有信号量的进程可以休眠,会导致其他等待该信号量的进程也会休眠,所以需保证拥有信号量而休眠的代码必须短,并且还要确保拥有信号量并不会阻塞最终会唤醒我们自己的那个进程。
2.当我们被唤醒时,永远无法知道休眠了多久,或休眠期间发生了什么事情,也不知道是否还有其他进程在同一事件上休眠,这个进程可能会在我们之前被唤醒并将我们等待的资源拿走。所以我们对唤醒之后的状态也不能做任何假定,必须检查以确保我们等待的条件真正为真。
3.除非我们知道会有其他进程在其他地方唤醒我们,否则进程不能休眠。完成唤醒任务的那个进程必须能找到我们的进程,这样才能唤醒休眠的进程,所以能够找到休眠的进程意味着,需要维护一个称为等待队列的数据结构,等待队列就是一个进程链表,其中包含了等待某个特定事件的所有进程。(可能很多等待队列,每个等待队列内的所有进程等待的事件都是一样的,但是不能的等待队列等待的事件不一样)
3.简单休眠
-
等待休眠的函数如下:
wait_event(queue, condition)
wait_event_interruptible()
wait_event_timeout()
wait_event_interruptible_timeout()
queue是等待队列头,condition是一个条件表达式。这个函数会在进程休眠前后都要对condition求值。即在进程最后进入真正休眠的时候会再此检查此条件是否为真,如果为假ÿ