-ERESTARTSYS связан с концепцией перезапускаемого системного вызова. Перезапускаемый системный вызов - это тот, который может быть прозрачно повторно выполнен ядром, когда есть некоторое прерывание.
Например, процесс пользовательского пространства, который спит в системном вызове, может получить сигнал, выполнить обработчик, а затем, когда обработчик возвращается, он возвращается в ядро и продолжает спать в исходном системном вызове.
Используя флаг POSIX sigaction
API SA_RESTART
, процессы могут организовать поведение перезапуска, связанное с сигналами.
В ядре Linux, когда драйвер или другой модуль, блокирующий в контексте системного вызова, обнаруживает, что задача была разбужена из-за сигнала, он может вернуть -EINTR. Но -EINTR будет пузыриться в пространстве пользователя и заставит системный вызов вернуть -1 с errno, установленным в EINTR.
Если вместо этого вы возвращаете -ERESTARTSYS, это означает, что ваш системный вызов перезапускается. Код ERESTARTSYS не обязательно будет виден в пространстве пользователя. Он либо переводится в значение возврата -1, а errno устанавливается в EINTR (тогда, очевидно, он виден в пространстве пользователя), либо переводится в поведение перезапуска системного вызова, что означает, что ваш системный вызов снова вызывается с теми же аргументами (посредством никаких действий со стороны пользовательского пространства: ядро делает это, сохраняя информацию в специальном блоке перезапуска).
Обратите внимание на очевидную проблему с «одинаковыми аргументами» в предыдущем абзаце: некоторые системные вызовы не могут быть перезапущены с теми же параметрами, потому что они не являются идемпотентными! Например, предположим, что есть звонок в режиме сна, такой как nanosleep, на 5,3 секунды. Он прерывается через 5 секунд. Если он перезапустится наивно, он будет спать еще 5,3 секунды. Он должен передать новые параметры перезапущенному вызову в спящий режим только на оставшиеся 0,3 секунды; т.е. изменить содержимое блока перезапуска. Есть способ сделать это: вы вводите разные аргументы в блок перезапуска задачи и используете возвращаемое значение -ERESTART_RESTARTBLOCK.
Чтобы ответить на второй вопрос: в чем разница? Почему бы просто не написать процедуру чтения без проверки возвращаемого значения и возврата -ERESTARTSYS? Ну, потому что это неправильно в случае, если пробуждение происходит из-за сигнала! Вы хотите, чтобы чтение возвращало 0 байтов при каждом поступлении сигнала? Это может быть неправильно истолковано пользовательским пространством как конец данных. Такая проблема не будет обнаруживаться в тестовых случаях, которые не используют сигналы.