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

时间:2022-11-01 00:03:06

According to man ioctl, opening file descriptors with open may cause unwanted side-effects. The manual also states that opening with O_NONBLOCK solves those unwanted issues but I can't seem to find what's the reason for that, nor what are the actual side-effects. Can someone shed light into that? With ioctl is it always possible and equivalent* to open file descriptors with O_NONBLOCK?

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

NOTES (from man ioctl)

注释(来自man ioctl)

In order to use this call, one needs an open file descriptor. Often the open(2) call has unwanted side effects, that can be avoided under Linux by giving it the O_NONBLOCK flag.

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

(* I am aware of what O_NONBLOCK implies, but I don't know if that affects ioctl calls the same way it affects other syscalls. My program, which uses ioctl to write and read from an SPI bus, works perfectly with that flag enabled.)

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

2 个解决方案

#1


6  

The obvious place to look for the answer would be the open(2) man page, which, under the heading for O_NONBLOCK, says:

寻找答案的显而易见的地方是open(2)手册页,它在O_NONBLOCK的标题下说:

When possible, the file is opened in nonblocking mode. Neither the open() nor any subsequent operations on the file descriptor which is returned will cause the calling process to wait.

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

[...]

For the handling of FIFOs (named pipes), see also fifo(7). For a discussion of the effect of O_NONBLOCK in conjunction with mandatory file locks and with file leases, see fcntl(2).

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

OK, that wasn't very informative, but let's follow the links and see what the manual pages for fifo(7) and fcntl(2) say:

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

Normally, opening the FIFO blocks until the other end is opened also.

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

A process can open a FIFO in nonblocking mode. In this case, opening for read-only will succeed even if no-one has opened on the write side yet and opening for write-only will fail with ENXIO (no such device or address) unless the other end has already been opened.

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

Under Linux, opening a FIFO for read and write will succeed both in blocking and nonblocking mode. POSIX leaves this behavior undefined.

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

So here's at least one "unwanted side effect": even just trying to open a FIFO may block, unless you pass O_NONBLOCK to the open() call (and open it for reading).

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

What about fcntl, then? As the open(2) man page notes, the sections to look under are those title "Mandatory locking" and "File leases". It seems to me that mandatory locks, in this case, are a red herring, though — they only cause blocking when one tries to actually read from or write to the file:

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

If a process tries to perform an incompatible access (e.g., read(2) or write(2)) on a file region that has an incompatible mandatory lock, then the result depends upon whether the O_NONBLOCK flag is enabled for its open file description. If the O_NONBLOCK flag is not enabled, then the system call is blocked until the lock is removed or converted to a mode that is compatible with the access.

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

What about leases, then?

那么租约怎么样?

When a process (the "lease breaker") performs an open(2) or truncate(2) that conflicts with a lease established via F_SETLEASE, the system call is blocked by the kernel and the kernel notifies the lease holder by sending it a signal (SIGIO by default). [...]

当进程(“租用断路器”)执行open(2)或truncate(2)与通过F_SETLEASE建立的租约冲突时,系统调用被内核阻止,内核通过发送信号通知租约持有者(SIGIO默认情况下)。 [...]

Once the lease has been voluntarily or forcibly removed or downgraded, and assuming the lease breaker has not unblocked its system call, the kernel permits the lease breaker's system call to proceed.

一旦租约被自愿或强行拆除或降级,并且假设租赁断路器未解锁其系统呼叫,内核允许租用断路器的系统呼叫继续进行。

[...] If the lease breaker specifies the O_NONBLOCK flag when calling open(2), then the call immediately fails with the error EWOULDBLOCK, but the other steps still occur as described above.

[...]如果租用断路器在调用open(2)时指定O_NONBLOCK标志,则调用会立即失败并出现错误EWOULDBLOCK,但其他步骤仍然如上所述发生。

OK, so that's another unwanted side effect: if the file you're trying to open has a lease on it, the open() call may block until the lease holder has released the lease.

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

In both cases, the "unwanted side effect" avoided by passing O_NONBLOCK to open() is, unsurprisingly, the open() call itself blocking until some other process has done something. If there are any other kinds of side effects that the man page you cite refers to, I'm not aware of them.

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

#2


1  

From Linux System Programming, 2nd Edition, by R. Love (emphasis mine):

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

O_NONBLOCK If possible, the file will be opened in nonblocking mode. Neither the open() call, nor any other operation will cause the process to block (sleep) on the I/O. This behaviour may be defined only for FIFOs.

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

Sometimes, programmers do not want a call to read() to block when there is no data available. Instead, they prefer that the call return immediately, indicating that no data is available. This is called nonblocking I/O; it allows applications to perform I/O, potentially on multiple files, without ever blocking, and thus missing data available in another file.

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

Consequently, an additional errno value is worth checking: EAGAIN.

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

See this thread on the kernel mailing list.

在内核邮件列表中查看此主题。

#1


6  

The obvious place to look for the answer would be the open(2) man page, which, under the heading for O_NONBLOCK, says:

寻找答案的显而易见的地方是open(2)手册页,它在O_NONBLOCK的标题下说:

When possible, the file is opened in nonblocking mode. Neither the open() nor any subsequent operations on the file descriptor which is returned will cause the calling process to wait.

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

[...]

For the handling of FIFOs (named pipes), see also fifo(7). For a discussion of the effect of O_NONBLOCK in conjunction with mandatory file locks and with file leases, see fcntl(2).

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

OK, that wasn't very informative, but let's follow the links and see what the manual pages for fifo(7) and fcntl(2) say:

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

Normally, opening the FIFO blocks until the other end is opened also.

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

A process can open a FIFO in nonblocking mode. In this case, opening for read-only will succeed even if no-one has opened on the write side yet and opening for write-only will fail with ENXIO (no such device or address) unless the other end has already been opened.

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

Under Linux, opening a FIFO for read and write will succeed both in blocking and nonblocking mode. POSIX leaves this behavior undefined.

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

So here's at least one "unwanted side effect": even just trying to open a FIFO may block, unless you pass O_NONBLOCK to the open() call (and open it for reading).

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

What about fcntl, then? As the open(2) man page notes, the sections to look under are those title "Mandatory locking" and "File leases". It seems to me that mandatory locks, in this case, are a red herring, though — they only cause blocking when one tries to actually read from or write to the file:

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

If a process tries to perform an incompatible access (e.g., read(2) or write(2)) on a file region that has an incompatible mandatory lock, then the result depends upon whether the O_NONBLOCK flag is enabled for its open file description. If the O_NONBLOCK flag is not enabled, then the system call is blocked until the lock is removed or converted to a mode that is compatible with the access.

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

What about leases, then?

那么租约怎么样?

When a process (the "lease breaker") performs an open(2) or truncate(2) that conflicts with a lease established via F_SETLEASE, the system call is blocked by the kernel and the kernel notifies the lease holder by sending it a signal (SIGIO by default). [...]

当进程(“租用断路器”)执行open(2)或truncate(2)与通过F_SETLEASE建立的租约冲突时,系统调用被内核阻止,内核通过发送信号通知租约持有者(SIGIO默认情况下)。 [...]

Once the lease has been voluntarily or forcibly removed or downgraded, and assuming the lease breaker has not unblocked its system call, the kernel permits the lease breaker's system call to proceed.

一旦租约被自愿或强行拆除或降级,并且假设租赁断路器未解锁其系统呼叫,内核允许租用断路器的系统呼叫继续进行。

[...] If the lease breaker specifies the O_NONBLOCK flag when calling open(2), then the call immediately fails with the error EWOULDBLOCK, but the other steps still occur as described above.

[...]如果租用断路器在调用open(2)时指定O_NONBLOCK标志,则调用会立即失败并出现错误EWOULDBLOCK,但其他步骤仍然如上所述发生。

OK, so that's another unwanted side effect: if the file you're trying to open has a lease on it, the open() call may block until the lease holder has released the lease.

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

In both cases, the "unwanted side effect" avoided by passing O_NONBLOCK to open() is, unsurprisingly, the open() call itself blocking until some other process has done something. If there are any other kinds of side effects that the man page you cite refers to, I'm not aware of them.

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

#2


1  

From Linux System Programming, 2nd Edition, by R. Love (emphasis mine):

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

O_NONBLOCK If possible, the file will be opened in nonblocking mode. Neither the open() call, nor any other operation will cause the process to block (sleep) on the I/O. This behaviour may be defined only for FIFOs.

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

Sometimes, programmers do not want a call to read() to block when there is no data available. Instead, they prefer that the call return immediately, indicating that no data is available. This is called nonblocking I/O; it allows applications to perform I/O, potentially on multiple files, without ever blocking, and thus missing data available in another file.

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

Consequently, an additional errno value is worth checking: EAGAIN.

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

See this thread on the kernel mailing list.

在内核邮件列表中查看此主题。