在ioctl中打开有什么不良副作用?

时间:2016-12-02 20:12:54

标签: c linux unix posix ioctl

根据man ioctl,使用open打开文件描述符可能会导致不必要的副作用。该手册还指出,O_NONBLOCK开头可以解决这些不必要的问题,但我似乎无法找到原因,也不知道实际的副作用是什么。有人可以解释一下吗?使用ioctl是否始终可以使用O_NONBLOCK打开文件描述符?

  

注意(来自man ioctl

     

为了使用此调用,需要一个打开的文件描述符。通常,open(2)调用会产生不必要的副作用,这是可以避免的   在Linux下通过给它O_NONBLOCK标志。

(*我知道O_NONBLOCK意味着什么,但我不知道这是否会影响ioctl调用它影响其他系统调用的方式。我的程序使用ioctl从SPI总线写入和读取,与启用该标志完美配合。)

2 个答案:

答案 0 :(得分:6)

查找答案的显而易见的地方是open(2)手册页,该页面位于O_NONBLOCK的标题下,表示:

  

如果可能,文件以非阻塞模式打开。     open()和文件上的任何后续操作都没有     返回的描述符将导致调用进程     等待。

     

[...]

     

有关处理FIFO(命名管道)的信息,另请参阅fifo(7)。     有关O_NONBLOCK结合的影响的讨论     有强制文件锁和文件租约,请参阅fcntl(2)

好的,这不是很有用,但让我们按照链接查看fifo(7)和fcntl(2)的手册页说:

  

通常,打开FIFO块直到另一端打开。

     

进程可以在非阻塞模式下打开FIFO。在这种情况下,打开     即使没有人在写入时打开,只读也会成功     对于只写而且只写开放将因ENXIO而失败(没有这样的     设备或地址),除非另一端已经打开。

     

在Linux下,打开FIFO进行读写将同时成功     阻塞和非阻塞模式。 POSIX将此行为保留为未定义。

所以这里至少有一个“不必要的副作用”:即使只是尝试打开FIFO也可能会阻止,除非你将O_NONBLOCK传递给open()来电(并打开它进行阅读)。

那么fcntl怎么样?正如open(2)手册页所述,要查看的部分是“强制锁定”和“文件租约”。它似乎对我来说,在这种情况下,强制锁是一个红色的鲱鱼 - 它们只会在试图实际读取或写入文件时导致阻塞:

  

如果进程尝试执行不兼容的操作     访问(例如,read(2)或write(2))在具有的文件区域上     不兼容的强制锁,那么结果取决于是否     O_NONBLOCK标志已启用其打开的文件描述。如果     O_NONBLOCK标志未启用,则系统调用将被阻止,直到     锁被删除或转换为兼容的模式     访问。

那么租约怎么样?

  

当一个进程(“租约破坏者”)执行open(2)或     truncate(2)与通过F_SETLEASE建立的租约冲突,     系统调用被内核阻止,内核通知     租赁持有人发送信号(默认为SIGIO)。 [...]

     

一旦租约被自愿或强行拆除或     降级,并假设租赁破坏者没有解除阻止     系统调用,内核允许租用断路器的系统调用     继续进行。

     

[...]如果     租约破坏者在调用open(2)时指定O_NONBLOCK标志,     然后调用立即失败,错误EWOULDBLOCK,但是     其他步骤仍然如上所述。

好的,这是另一个不必要的副作用:如果您尝试打开的文件有租约,open()调用可能会阻止,直到租约持有人已经释放租约。

在这两种情况下,将O_NONBLOCK传递给open()避免了“不必要的副作用”,不出所料,open()调用本身就会阻塞,直到某些其他进程完成某些操作。如果您引用的手册页中有任何其他种副作用,我不知道它们。

答案 1 :(得分:1)

来自 Linux系统编程,第2版,来自R. Love(强调我的):

  

O_NONBLOCK   如果可能,该文件将以非阻塞模式打开。 都不是   open()调用,   或任何其他操作将导致进程阻塞(休眠)I / O.   这个   行为可能只为FIFO定义。

     

有时,程序员不希望调用read()来阻塞   没有数据   可用。相反,他们更喜欢呼叫立即返回,   表明没有数据   是可用的。这称为非阻塞I / O;它允许应用程序   可能会执行I / O.   在多个文件上,没有阻塞,因此缺少可用的数据   另一个文件。

     

因此,额外的errno值值得检查:EAGAIN。

请参阅内核邮件列表中的this thread