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