Когда неблокируемый ввод-вывод для stdout включен, правильно ли для ОС включать его и для stdin?

Я заметил неожиданное поведение как в OS X, так и в Linux. Включение неблокирующего ввода / вывода (используя O_NONBLOCK) для стандартного вывода включает его и для стандартного ввода!

Правильно ли работают эти ОС? Если так, это поведение определяется POSIX? Пожалуйста, укажите мне соответствующую документацию, если это так.

Вот пример программы, которую я использовал для проверки этого:

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main (int argc, char *argv[]) {
  int flags = fcntl(STDOUT_FILENO, F_GETFL);
  if (argc > 1 && strcmp(argv[1], "1") == 0) {
    fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK);
  }
  printf("stdout O_NONBLOCK is: %d\n", fcntl(STDOUT_FILENO, F_GETFL) & O_NONBLOCK);
  printf("stdin O_NONBLOCK is: %d\n", fcntl(STDIN_FILENO, F_GETFL) & O_NONBLOCK);
  return 0;
}

На OS X:

$ clang -o fd-test fd-test.c
$ ./fd-test
stdout O_NONBLOCK is: 0
stdin O_NONBLOCK is: 0
$ ./fd-test 1
stdout O_NONBLOCK is: 4
stdin O_NONBLOCK is: 4

В Linux:

$ gcc -o fd-test fd-test.c
$ ./fd-test
stdout O_NONBLOCK is: 0
stdin O_NONBLOCK is: 0
$ ./fd-test 1
stdout O_NONBLOCK is: 2048
stdin O_NONBLOCK is: 2048

1 ответ

Решение

Когда процесс запускается из оболочки, stdin, stdout а также stderr указать на то же описание файла. Это описание файла помечено как O_NONBLOCK По вашему fcntl(1) вызов и, следовательно, как ожидается, оба файловых дескриптора помечены как O_NONBLOCK,

Если вы действительно хотите записать в один и тот же файл два файловых дескриптора, но хотите, чтобы один был помечен как O_NONBLOCKнеобходимо создать новое описание файла для того же файла. Если вы знаете имя файла, о котором идет речь, вы можете добиться этого, просто позвонив open() с желаемым именем файла и флагами. В некоторых операционных системах вы можете найти имя файла с помощью API, специфичного для платформы, например /proc/fd виртуальная файловая система (многие Unix, включая Linux) или fd2path() функция из плана 9. Обратитесь к этому вопросу для получения более подробной информации.

Обратите внимание, что просто звонить open("/dev/fd/0", ...) может работать некорректно, так как возвращает верный указатель на одно и то же описание файла на некоторых платформах.

Другие вопросы по тегам