«Медленное устройство» является в сущности терминалом или почти всяким другим устройством, кроме обычного файла. В этом случае read()
могла завершиться с ошибкой EINTR
, read()
возвратилась бы нормально.
Системный вызов был бы запущен повторно В этом случае read()
вернулась бы нормально; возвращенное значение могло быть либо числом запрошенных байтов, либо числом действительно прочитанных байтов (как в случае чтения вблизи конца файла).
Поведение BSD несомненно полезно; вы всегда можете сказать, сколько данных было прочитано.
Поведение POSIX сходно, но не идентично первоначальному поведению BSD. POSIX указывает, что read()
[108] завершается с ошибкой EINTR
лишь в случае появления сигнала до начала перемещения данных. Хотя POSIX ничего не говорит о «медленных устройствах», на практике это условие проявляется именно на них.
В противном случае, если сигнал прерывает частично выполненную read()
, возвращенное значение является числом уже прочитанных байтов. По этой причине (а также для возможности обработки коротких файлов) всегда следует проверять возвращаемое read()
значение и никогда не предполагать, что прочитано все запрошенное количество байтов. (Функция POSIX API sigaction()
, описанная позже, позволяет при желании получить поведение повторно вызываемых системных вызовов BSD.)
10.4.4.1. Пример: GNU Coreutils safe_read()
и safe_write()
Для обработки случая EINTR в традиционных системах GNU Coreutils использует две функции, safe_read()
и safe_write()
. Код несколько запутан из-за того, что один и тот же файл за счет включения #include и макросов реализует обе функции. Из файла lib/safe-read.c
в дистрибутиве Coreutils:
1 /* Интерфейс read и write для .повторных запусков после прерываний.
2 Copyright (С) 1993, 1994, 1998, 2002 Free Software Foundation, Inc.
/* ... куча шаблонного материала опущена... */
56
57 #ifdef SAFE_WRITE
58 # include "safe-write.h"
59 # define safe_rw safe_write /* Создание safe_write() */
60 # define rw write /* Использование системного вызова write() */
61 #else
62 # include "safe-read.h"
63 # define safe_rw safe_read /* Создание safe_read() */
64 # define rw read /* Использование системного вызова read() */
65 # undef const
66 # define const /* пусто */
67 #endif
68
69 /* Прочесть (записать) вплоть до COUNT байтов в BUF из(в) дескриптора FD, повторно запуская вызов при
70 прерывании. Вернуть число действительно прочитанных (записанных) байтов, 0 для EOF
71 или в случае ошибки SAFE_READ_ERROR(SAFE_WRITE_ERROR). */
72 size_t
73 safe_rw(int fd, void const *buf, size_t count)
74 {
75 ssize_t result;
76
77 /* POSIX ограничивает COUNT значением SSIZE_MAX, но мы еще больше ограничиваем его, требуя,
78 чтобы COUNT <= INT_MAX, для избежания ошибки в Tru64 5.1.
79 При уменьшении COUNT сохраняйте указатель файла выровненным по размеру блока.
80 Обратите внимание, что read (write) может быть успешным в любом случае, даже если прочитано (записано)
81 менее COUNT байтов, поэтому вызывающий должен быть готов обработать
82 частичные результаты. */
83 if (count > INT_MAX)
84 count = INT_MAX & -8191;
85
86 do
87 {
88 result = rw(fd, buf, count);
89 }
90 while (result < 0 && IS_EINTR(errno));
91
92 return (size_t) result;
93 }