Строки 57–67 обрабатывают определения, создавая соответствующим образом safe_read()
safe_write()
(см. ниже safe_write.c
).Строки 77–84 указывают на разновидность осложнений, возникающих при чтении. Здесь один особый вариант Unix не может обработать значения, превышающие INT_MAX
INT_MAX
, и сохраняют его кратным 8192. Последняя операция служит эффективности дисковых операций: выполнение ввода/вывода с кратным основному размеру дискового блока объемом данных более эффективно, чем со случайными размерами данных. Как отмечено в комментарии, код сохраняет семантику read()
и write()
, где возвращенное число байтов может быть меньше затребованного.Обратите внимание, что параметр count
INT_MAX
, поскольку count представляет тип size_t
, который является беззнаковым (unsigned). INT_MAX
является чистым int
, который на всех современных системах является знаковым.Строки 86–90 представляют действительный цикл, повторно осуществляющий операцию, пока она завершается ошибкой EINTR
IS_EINTR()
не показан, но он обрабатывает случай в системах, на которых EINTR
не определен. (Должен быть по крайней мере один такой случай, иначе код не будет возиться с установкой макроса; возможно, это было сделано для эмуляции Unix или POSIX в не-Unix системе.) Вот safe_write.c
:1 /* Интерфейс write для повторного запуска после прерываний.
2 Copyright (С) 2002 Free Software Foundation, Inc.
/* ...куча шаблонного материала опущена... */
17
18 #define SAFE_WRITE
19 #include "safe-read.с"
В строке 18 #define
SAFE_WRITE
; это связано со строками 57–60 в safe_read.с
.10.4.4.2. Только GLIBC: TEMP_FAILURE_RETRY()
Файл
#include
long int TEMP_FAILURE_RETRY(expression);
Вот определение макроса:
/* Оценить EXPRESSION и повторять, пока оно возвращает -1 с 'errno',
установленным в EINTR. */
# define TEMP_FAILURE_RETRY(expression) \
(__extension__ \
({ long int __result; \
do __result = (long int)(expression); \
while (__result == -1L && errno == EINTR); \
__result; }))
Макрос использует расширение GCC к языку С (как обозначено ключевым словом __extension__
Используя этот макрос, мы могли бы переписать safe_read()
size_t safe_read(int fd, void const *buf, size_t count) {
ssize_t result;
/* Ограничить count, как в ранее приведенном комментарии. */
if (count > INT_MAX)
count = INT_MAX & ~8191;
result = TEMP_FAILURE_RETRY(read(fd, buf, count));
return (size_t)result;
}
10.4.5. Состояния гонок и sig_atomic_t
Пока обработка одного сигнала за раз выглядит просто: установка обработчика сигнала в main()
SIG_IGN
) в качестве первого действия обработчика.Но что произойдет, если возникнут
Или предположим, что вы используете bsd_signal()