gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 16:23:23 25 4
gpt4 key购买 nike

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

全局变量:

wait_queue_head_t my_wait_q_head;
int read_avail = 0;


设备初始化():

init_waitqueue_head(&my_wait_q_head);


设备读取():

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 Device Driver 这本书,但我不明白,有人可以举个例子来详细说明吗?:

Once we get past that call, something has woken us up, but we do not know what. One possibility is that the process received a signal. The if statement that contains the wait_event_interruptible call checks for this case. This statement ensures the proper and expected reaction to signals, which could have been responsible for waking up the process (since we were in an interruptible sleep). If a signal has arrived and it has not been blocked by the process, the proper behavior is to let upper layers of the kernel handle the event. To this end, the driver returns -ERESTARTSYS to the caller; this value is used internally by the virtual filesystem (VFS) layer, which either restarts the system call or returns -EINTR to user space. We use the same type of check to deal with signal handling for every read and write implementation.

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

最佳答案

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

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

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

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

如果您返回 -ERESTARTSYS,这意味着您的系统调用是可重启的。 ERESTARTSYS 代码不一定会在用户空间中看到。它要么被转换为 -1 返回值并且 errno 设置为 EINTR(然后,显然,在用户空间中看到),要么被转换进入系统调用重启行为,这意味着您的系统调用将使用相同的参数再次调用(不对部分用户空间进程执行任何操作:内核通过将信息存储在一个特殊的重启 block 中来执行此操作)。

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

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

关于c - ERESTARTSYS 在编写 linux 驱动程序时使用了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9576604/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com