При каких обстоятельствах команда read() syscall возвращает 0?

Я просматриваю read syscall в Unix, который (по крайней мере, в Linux) имеет эту подпись: [1]

ssize_t read(int fd, void* buf, size_t count);

Предположим, что вызов преуспевает (т.е. Отрицательные значения возврата) и что count > 0 (т.е. Буфер фактически может хранить ненулевое количество байтов). При каких обстоятельствах будет read() return 0? Я могу думать о следующем:

  • Когда fd ссылается на обычный файл, и конец файла достигнут.
  • Когда fd относится к принимающему концу трубы, гнезда или FIFO, конец отправки был закрыт, а собственный буфер/внутренний/внутренний порт FIFO был исчерпан.
  • Когда fd ссылается на подчиненную сторону терминального устройства, которое находится в ICANON а Ctrl-D отправляется на главную сторону, в то время как буфер строки пуст.

Мне любопытно, есть ли другие ситуации, о которых я не знаю, где read() вернется с результатом 0. Мне особенно интересно (по причинам) в ситуациях, подобных последнему в списке выше, где read() возвращает 0 один раз, но последующие вызовы read() на том же FD могут возвращать ненулевой результат. Если ответ относится только к определенному вкусу Unix, мне все равно интересно его услышать.

[1] Я знаю, что эта подпись предназначена для оболочки libc, а не для самонастройки, но это не важно сейчас.

Ответы

Ответ 1

  • Если физическая файловая система не поддерживает простые чтения из каталогов, read() вернет 0, если она используется для каталога. Вместо этого пользователи должны использовать Opendir() и readdir().
  • Если ни один процесс не имеет открытого канала для записи, read() возвращает 0, чтобы указать конец файла.
  • Если соединение отключено в потоковом сокете, но данных нет, функция read() возвращает 0 байтов как EOF.

Ответ 2

Обычно возвращаемое значение 0 всегда означает конец файла. Однако, если вы укажете 0 как количество прочитанных байтов, оно всегда будет возвращать 0 если не будет обнаружена ошибка.

Терминальные устройства - особый случай. Если терминал находится в режиме приготовления, введите Control-d, чтобы драйвер устройства возвращался из любого ожидающего read() сразу с тем, что находится в буфере редактирования ввода, вместо того, чтобы ждать ввода пользователем новой строки. Если буфер пуст, это приводит к чтению с нулевой длиной. Таким образом, ввод символа EOF в начале строки автоматически обрабатывается приложениями EOF.