Сколько раз имеет смысл повторять попытки для оболочек системных вызовов, которые повторяют попытку EINTR?

Часто системные вызовы, такие как write(2), read(2), close(2) и т. д., терпят неудачу из-за того, что они прерываются сигналом со значением errnoEINTR (скажем, размер окна терминала изменился и был получен SIGWINCH), что является временной ошибкой и должно быть повторено, и код часто использует оболочки вокруг этих системных вызовов, которые повторяют попытку EINTR (и часто EAGAIN или ENOBUFS).

Но можно застрять в теоретической ситуации, когда код просто продолжает бесконечно зацикливаться EINTR либо из-за получения непрерывных сигналов, либо из-за того, что системный вызов был перехвачен специальной реализацией этого системного вызова, которая просто возвращает EINTR.

В таких случаях в библиотечном коде сколько раз имеет смысл повторить системный вызов?

Я никогда не видел, чтобы кто-нибудь вводил ограничение повторных попыток для чего-то подобного. Нет оснований полагать, что прерывания будут повторяться. Это не похоже на ошибку доступа к удаленному ресурсу, где есть большая вероятность, что проблема окажется постоянной.

Barmar 22.06.2024 17:28

Отсутствие повторной попытки не остановит поток сигналов. /// Не думайте об этом как о повторной попытке, думайте об этом как о возобновлении ожидания, которое выполнял ваш блокирующий вызов. Это то, что вы бы сделали, если бы не получили сигнал.

ikegami 22.06.2024 20:54

Да, это «возможно», но не «вероятно». Скажем, если бы вы создали интервальный таймер (см., например, man 2 timer_create) с интервалом повторения в пару наносекунд, вы, скорее всего, могли бы столкнуться с чем-то подобным, что вы описываете. Хотя это скорее результат ошибки проектирования программы, чем то, чего вы обычно ожидаете.

David C. Rankin 22.06.2024 20:57

@ikegami Достаточно справедливо, но будет ли вероятность того, что библиотечный код выйдет из строя, скажем, после 40-100 итераций или будет продолжать цикл бесконечно?

Harith 23.06.2024 15:08
would it be apt for library code to fail after say 40-100 iterations было бы кстати. Просто делайте это, не работайте проактивно: если у вас возникнет проблема с 40 итерациями, вы сделаете 100. Нет особых причин беспокоиться об этом.
KamilCuk 23.06.2024 15:50

Опять же, он не терпит неудачу, он ждет. Что бы read делал без сигнала? Жди вечность. Так почему же вы думаете, что нужно делать что-то другое, если поступает сигнал??? Цель EINTR — дать обработчикам сигналов возможность работать, когда в противном случае вызов был бы заблокирован.

ikegami 23.06.2024 17:11
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сколько раз имеет смысл повторять попытки для оболочек системных вызовов, которые повторяют попытку EINTR?

От нуля до бесконечности.

Стандартная библиотека Glibc используется на миллиардах устройств по всему миру. Вызов printf("Hello world\n"); приведет к вызову функции _IO_new_file_write, которая выглядит следующим образом:

ssize_t
_IO_new_file_write (FILE *f, const void *data, ssize_t n)
{
  ssize_t to_do = n;
  while (to_do > 0)
    {
      ssize_t count = (__builtin_expect (f->_flags2
                                         & _IO_FLAGS2_NOTCANCEL, 0)
               ? __write_nocancel (f->_fileno, data, to_do)
               : __write (f->_fileno, data, to_do));
      if (count < 0)
    {
      f->_flags |= _IO_ERR_SEEN;
      break;
    }
      to_do -= count;
      data = (void *) ((char *) data + count);
    }
  n -= to_do;
  if (f->_offset >= 0)
    f->_offset += n;
  return n;
}

Как вы можете, while (to_do > 0) функция будет выполнять цикл бесконечно много раз, пока данные не будут записаны, игнорируя любой EINTR сигнал и даже не проверяя его.

Поскольку это программное обеспечение используется буквально почти на каждом Linux-устройстве по всему миру, можно с уверенностью сказать, что бесконечное количество циклов вполне допустимо.

Теперь вы, возможно, работаете с нестандартной реализацией записи. Например, на встроенном устройстве программист может реализовать свою собственную реализацию write, например _write_r при использовании стандартной библиотеки Newlib C. Если такой программист устанавливает errno = EINTR и бесконечно возвращает 0 из своей write функции, я бы сказал, что это его дело. Но если вы чувствуете, что хотите обнаружить такие ситуации, вперед. Я не чувствую необходимости это делать.

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

Re «Как вы можете, while (to_do > 0) функция будет выполнять цикл бесконечно много раз, пока данные не будут записаны, игнорируя любой сигнал EINTR и даже не проверяя его.», Разве она не завершается через break при получении EINTR или любой другой ошибки?

ikegami 23.06.2024 17:17

Другие вопросы по теме

Как я могу распечатать или суммировать один шестнадцатеричный код большего размера в bash
Как объединить каждые три строки в одну строку из командной строки?
Как мне выйти из вложенных оболочек в командной строке, не закрывая/выходя из терминала случайно?
Назначьте максимальный размер дискового пространства с помощью скрипта оболочки
Как можно извлечь одну строку данных из файла и другого процесса в каждой этой строке?
Очереди сообщений IPC не работают должным образом
Как разветвить процесс на другой виртуальный терминал
Сценарий оболочки – как отображать имена переменных и их значения в цикле
Почему Listen() (до вызова Accept()) достаточно, чтобы приложение завершило трехстороннее рукопожатие?
Попытка передать «указатель на структуру данных» обработчику сигнала с помощью функции sigqueue из одного процесса в другой, используя структуру siginfo_t