【问题标题】:What does ERESTARTSYS used while writing linux driver?ERESTARTSYS 在编写 linux 驱动程序时使用了什么?
【发布时间】:2012-03-06 01:24:52
【问题描述】:

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

全局变量:

wait_queue_head_t my_wait_q_head;
int read_avail = 0;


设备初始化():

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

【问题讨论】:

    标签: c linux-kernel linux-device-driver


    【解决方案1】:

    -ERESTARTSYS 与可重启系统调用的概念有关。可重新启动的系统调用是一种可以在发生中断时由内核透明地重新执行的系统调用。

    例如,在系统调用中休眠的用户空间进程可以获取信号,执行处理程序,然后当处理程序返回时,它似乎回到内核并继续在原始系统调用上休眠。

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

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

    如果您返回-ERESTARTSYS,则表示您的系统调用是可重新启动的。 ERESTARTSYS 代码不一定会在用户空间中看到。它要么被转换为-1 return 和errno 设置为EINTR (然后,显然,在用户空间中看到),或者它被转换为系统调用重启行为,这意味着你的系统调用再次被调用相同的参数(对部分用户空间进程不采取任何行动:内核通过将信息存储在特殊的重启块中来做到这一点)。

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

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

    【讨论】:

    • @Noge:要查看差异,请在调用read() 和调用write() 之前向进程发送一个信号。
    • 拜托,我有同样的问题,我想测试我的驱动程序是否真的对未知信号做出正确反应(我在互联网上发现,这可能是 pthread 库 RT 信号)。什么样的信号,我如何发送来测试这个?我尝试了kill -N 使用许多不同的 N 值,但是:或者它被完全忽略,或者进程在没有进入中断的情况下被删除。更准确:我看是否输入了中断,我在read() -ERESTARTSYS中收到,立即返回,但是进程被取消了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多