在编写linux驱动程序时,ERESTARTSYS使用了什么?

我正在学习用于编写linux设备驱动程序的阻塞I / O函数,我想知道ERESTARTSYS的用法是ERESTARTSYS 。 考虑以下:

全局变量:

 wait_queue_head_t my_wait_q_head; int read_avail = 0; 

device_init():

init_waitqueue_head(&my_wait_q_head);

device_read():

 printk("I'm inside driver read!\n"); wait_event_interruptible(&my_wait_q_head, read_avail != 0); printk("I'm awaken!\n"); 

device_write():

 read_avail = 1; wake_up_interruptible(&my_wait_q_head); 

当我从用户空间调用read() ,命令提示符挂起,直到我按预期调用write()printk消息也相应地出现在dmesg 。 但是,我看到一些像这样编写的驱动程序:

另一个版本的device_read():

 printk("I'm inside driver read!\n"); if(wait_event_interruptible(&my_wait_q_head, read_avail != 0)) {return -ERESTARTSYS;} printk("I'm awaken!\n"); 

我在用户空间中使用相同的方法测试了第二个版本的device_read() ,结果完全相同,那么,ERESTARTSYS的用途是什么?

p / s:我已经阅读了这本书上的Linux设备驱动程序,但是我没有得到它,有人可以举例来说明吗?:

一旦我们通过那个电话,有些东西唤醒了我们,但我们不知道是什么。 一种可能性是该过程接收到信号。 包含wait_event_interruptible调用的if语句将检查此情况。 这个陈述确保了对信号的适当和预期的反应,这可能是唤醒过程的原因(因为我们处于可中断的睡眠状态)。 如果信号已到达并且尚未被进程阻止,则正确的行为是让内核的上层处理事件。 为此,驱动程序将-ERESTARTSYS返回给调用者; 此值由虚拟文件系统(VFS)层在内部使用,该层重新启动系统调用或将-EINTR返回到用户空间。 我们使用相同类型的检查来处理每个读写实现的信号处理。

资料来源: http : //www.makelinux.net/ldd3/chp-6-sect-2

-ERESTARTSYS连接到可重新启动的系统调用的概念。 可重新启动的系统调用是在内存中断时内核可以透明地重新执行的调用。

例如,在系统调用中hibernate的用户空间进程可以获得信号,执行处理程序,然后当处理程序返回时,它似乎返回到内核并在原始系统调用上保持hibernate状态。

使用POSIX sigaction API的SA_RESTART标志,进程可以安排与信号关联的重启行为。

在Linux内核中,当在系统调用的上下文中阻塞的驱动程序或其他模块检测到某个任务因信号而被唤醒时,它可以返回-EINTR。 但是-EINTR将冒泡到用户空间并导致系统调用返回-1,并将errno设置为EINTR。

如果您返回-ERESTARTSYS,则表示您的系统调用可以重新启动。 ERESTARTSYS代码不一定会出现在用户空间中。 它被转换为-1返回并且errno设置为EINTR(显然,在用户空间中可见),或者它被转换为系统调用重启行为,这意味着使用相同的参数再次调用您的系统调用(通过对部分用户空间进程没有任何操作:内核通过在特殊的重启块中存储信息来完成此操作。

请注意前一段中“相同参数”的明显问题:某些系统调用无法使用相同的参数重新启动,因为它们不是幂等的! 例如,假设有一个像nanosleep一样的睡眠呼叫,持续5.3秒。 它会在5秒后中断。 如果天真地重新开始,它将再睡5.3秒。 它必须将新参数传递给重新启动的调用才能hibernate0.3秒; 即改变重启块的内容。 有一种方法可以做到这一点:将不同的参数填充到任务的重启块中,并使用-ERESTART_RESTARTBLOCK返回值。

解决第二个问题:有什么区别? 为什么不在不检查返回值的情况下编写读取例程并返回-ERESTARTSYS? 好吧,因为在唤醒是由信号引起的情况下这是不正确的! 您是否希望读取在信号到达时返回0字节读取? 这可能会被用户空间误解为数据末尾。 在不使用信号的测试用例中,这种问题不会出现。