简单来说,在内核中使用delay函数,如果调用schedule_timeout有可能被signal打断,导致delay的时间小于预期,而mdelay可以确保等待的时间大于等于参数设置的时间,在一些hardware驱动当中使用的delay,安全起见,一般推荐使用mdelay或者usleep_range函数。
至于里面的原理,引用公司某大牛的解释:
schedule_timeout会做两件事
1. 设置timer
2. Schedule
他不会把当前的进程的状态由TASK_RUNNING变为TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE或者TASK_KILLABLE
所以在__schedule()中,不会把这个task从runqueue中移出去。那么当系统进行调度的时候这个进程仍然会被调度进来。
所以推荐调用
Schedule_timeout_interruptible
Schedule_timeout_uninterruptible
Schedule_timeout_killable
这几个函数都会在调用schedule_timeout之前调用set_current_state,来把进程的状态设置为非TASK_RUNNING得状态。
其中msleep就是调用schedule_timeout_uninterruptible。
Unterruptible就是不能被signal打断,任何signal都不行,包括优先级最高的不可忽略的SIG_KILL。
这也就是为什么我们会ps的时候看见进程状态是”D”。之所以这么做是由于一些系统的io不能接受打扰。唯一能唤醒io等待进程的就是别人wakeup他。
VPU的驱动就是这种情况,会在release的时候等待硬件不再busy,然后关clock。如果不用uninterruptible,而用interruptible,
那么用户kill VPU的进程,尽管我们在release的时候用了schedule(schedule_timeout会调用schedule),但是schedule会立刻返回,因为其中有判断:如果是非uninterruptible并且有signal pending,那么task的状态会被设置为TASK_RUNNING,并且立刻返回,不会做context switch. 所以这儿必须要schedule_timeout_uninterruptible。
系统也提供了新的状态TASK_KILLABLE。这个和TASK_UNINTERRUPTIBLE的区别就是这个进程能被SIG_KILL的signale唤醒。在文件系统中用的可能比较多。大家可能会碰到使用这种TASK_KILLABLE的情况。