检测带有 O_NONBLOCK 的文件描述符在 FFI 场景中是否仍然有效

Detect if a file descriptor with O_NONBLOCK is still valid in a FFI scenario

如果我有一个使用 open (2) 打开的文件描述符,随后使用 FFI(外部函数接口)使用 fcntl (2) 设置为 O_NONBLOCK

这意味着几乎每次调用 read (2) 都会 return -1,errno 设置为 EAGAIN,这意味着这次没有可用数据。

遗憾的是,我正在使用的 FFI 无法访问 errno 变量,因此我无法确定 -1 值是 returned 是因为没有数据还是因为文件句柄不是不再有效。

所以我试图以某种方式确定文件描述符是否仍然有效,而无需读取 errno。我 already tried all the answers with fcntl from this question,但它们不起作用,而且从不 return -1.

也许这是因为我正在读取设备文件:/dev/input/js0?

我可以调用另一个函数来告诉我文件描述符是否无效吗? (在上面的问题中有人提到poll,但我不确定这是什么意思。)

我正在使用 Squeak FFI,不允许添加任何自定义 C 包装器。我正在尝试访问游戏手柄并从中读取按钮信息,这是一项可选任务。

我用 fcntl 尝试的 Smalltalk 源代码:

fcntl 的 FFI(在 Class Gamepad 中定义):

manipulateFileHandle: fileHandle command: command
    < cdecl: long 'fcntl' ( long long ) module: 'libc.so.6' >
    ^ self externalCallFailed

然后在另一种方法中,我称之为:

| handleTest |
handleTest := Gamepad manipulateFileHandle: externalFileHandle command: 1.
Transcript show: handleTest; cr.

command1 是F_GETFD,读取文件描述符标志。但是 handleTest 永远不会是 -1,即使在拔下游戏手柄后也是如此。

在 GNU/Linux 系统上,libc 包含函数 __errno_location(),它 return 是 errno 变量的地址。您的 FFI 应该能够调用该函数,然后取消引用表示 int *.

的地址

在 GCC 发明线程局部变量的语法之前,允许多线程代码安全操作 errno 的技术是将其定义为:

#define errno (*__errno_location ())

该函数将return一个线程本地地址。在您的 Linux 系统上,如果您在使用 errno 的 C 代码上使用 gcc -E,您将看到扩展。

As explained by Barmar, the fcntl() techniques work. The reason it never returned -1 was because you were still holding a valid file descriptor. A file descriptor does not become invalid until it is closed.