Прерывание системных вызовов, когда сигнал пойман

Одна большая разница - то, что интеграция X11 немного отличается. Приложение X11 не будет взгляды, хорошие на Mac, необходимо вручную запустить XServer, который это не дало слишком большой любви. Кроме этого я думаю, что это - микроядро Маха с сетевым стеком FreeBSD, и пространство пользователя похоже на Linux.

31
12.07.2011, 00:12
2 ответа

Сводка: Вы корректны, что получение сигнала не прозрачно, ни один в случае, если я (прерванный не считав что-либо), ни в случае, если ii (прервал после частичного чтения). Сделать иначе в случае, если я потребовал бы коренных изменений внесения и к архитектуре операционной системы и к архитектуре приложений.

Представление реализации ОС

Рассмотрите то, что происходит, если системный вызов прерван сигналом. Обработчик сигналов выполнит код непривилегированного режима. Но syscall обработчик является кодом ядра и не доверяет никакому коду непривилегированного режима. Поэтому давайте исследуем выбор для syscall обработчика:

  • Завершите системный вызов; отчет, сколько было сделано к пользовательскому коду. Это до кода приложения для перезапуска системного вызова в некотором роде при желании. Это - то, как Unix работает.
  • Сохраните состояние системного вызова и позвольте пользовательскому коду возобновлять вызов. Это проблематично по нескольким причинам:
    • В то время как пользовательский код работает, что-то, могло оказаться, делало недействительным сохраненное состояние. Например, при чтении из файла, файл мог бы быть усеченным. Таким образом, для кода ядра была бы нужна большая логика для обработки этих случаев.
    • Сохраненному состоянию нельзя позволить сохранить блокировку, потому что нет никакой гарантии, что пользовательский код будет когда-либо возобновлять syscall, и затем блокировка была бы сохранена навсегда.
    • Ядро должно выставить новые интерфейсы, чтобы возобновить или отменить продолжающийся syscalls, в дополнение к нормальному интерфейсу для запуска syscall. Это - большая сложность для редкого случая.
    • Сохраненное состояние должно было бы использовать ресурсы (память, по крайней мере); те ресурсы должны были бы быть выделены и сохранены ядром, но рассчитать против выделения процесса. Это не непреодолимо, но это - сложность.
      • Обратите внимание, что обработчик сигналов мог бы сделать системные вызовы, которые сами прерваны; таким образом, у Вас не может только быть статического выделения ресурса, которое покрывает весь возможный syscalls.
      • И что, если ресурсы не могут быть выделены? Затем syscall должен был бы перестать работать так или иначе. Что означает, что приложение должно было бы иметь код для обработки этого случая, таким образом, этот дизайн не упростит код приложения.
  • Останьтесь происходящими (но приостановленный), создайте новый поток для обработчика сигналов. Это, снова, проблематично:
    • Ранние реализации Unix имели единственный поток для каждого процесса.
    • Обработчик сигналов рискнул бы переступать на обуви syscall. Это - проблема так или иначе, но в текущем дизайне Unix, она содержится.
    • Ресурсы должны были бы быть выделены для нового потока; посмотрите выше.

Основное различие для прерывания - то, что коду прерывания доверяют и высоко ограничивают. Обычно не позволяется выделить ресурсы, или работать навсегда, или взять блокировки и не выпустить их или сделать любой другой вид противных вещей; так как обработчик прерываний записан самим реализатором ОС, он знает, что он ничего не сделает плохо. С другой стороны, код приложения может сделать что-либо.

Представление проектирования приложений

Когда приложение прервано посреди системного вызова, syscall должен продолжиться к завершению? Не всегда. Например, рассмотрите программу как оболочка, это читает строку из терминала и пользовательские нажатия Ctrl+C, инициирование SIGINT. Чтение не должно завершаться, это - то, о чем сигнал - все. Обратите внимание, что этот пример показывает что read syscall должен быть прерываемым, даже если никакой байт еще не был считан.

Таким образом, должен быть путь к приложению, чтобы сказать ядру отменять системный вызов. При дизайне Unix, который происходит автоматически: сигнал делает возврат syscall. Другие проекты потребовали бы, чтобы путь к приложению возобновил или отменил syscall на своем досуге.

read системный вызов является способом, которым это - потому что это - примитив, который имеет смысл, учитывая общий дизайн операционной системы. То, что это означает, примерно, “читайте так, как Вы можете, до предела (размер буфера), но останавливаться, если что-то еще происходит”. На самом деле считать полный буфер включает выполнение read в цикле, пока не было считано как можно больше байтов; это - высокоуровневая функция, fread(3). В отличие от этого, read(2) который является системным вызовом, fread библиотечная функция, реализованная в пространстве пользователя сверху read. Это подходит для приложения, которое читает для файла или умирает, пробуя; это не подходит для интерпретатора командной строки или для сетевой программы, которая должна отрегулировать соединения чисто, ни для сетевой программы, которая имеет параллельные соединения и не использует потоки.

Пример чтения в цикле обеспечивается в Системном Программировании Linux Robert Love:

ssize_t ret;
while (len != 0 && (ret = read (fd, buf, len)) != 0) {
  if (ret == -1) {
    if (errno == EINTR)
      continue;
    perror ("read");
    break;
  }
  len -= ret;
  buf += ret;
}

Это заботится о case i и case ii и еще много.

30
27.01.2020, 19:38
  • 1
    Спасибо очень Gilles для очень краткого и четкого ответа, который подтверждает подобные представления, выдвинутые в статье о принципах проектирования UNIX. Кажется очень убедительным мне, что syscall поведение прерывания имеет отношение к философии дизайна UNIX, а не техническим ограничениям или препятствиям –  darbehdar 12.07.2011, 08:32
  • 2
    @darbehdar Это - все три: принципы проектирования Unix (здесь главным образом, который процессам меньше доверяют, чем ядро и могут выполнить произвольный код, также который обрабатывает и потоки, не создаются неявно), технические ограничения (на выделениях ресурса), и проектирование приложений (существуют случаи, когда сигнал должен отменить syscall). –  Gilles 'SO- stop being evil' 12.07.2011, 10:11

Отвечать на вопрос A:

Да, доставка и обработка сигнала не совсем очевидны для read().

read() выполнение на полпути может занимать некоторые ресурсы, в то время как оно прервано сигналом. И обработчик сигналов сигнала может назвать другого read() (или любой другой асинхронный сигнал безопасный syscalls) также. Так read() прерванный сигналом должен быть остановлен сначала для высвобождения средств, которые он использует, иначе read() названный от обработчика сигналов получит доступ к тем же ресурсам и вызовет повторно используемые проблемы.

Поскольку системные вызовы кроме read() мог быть назван от обработчика сигналов, и они могут также занять идентичный набор ресурсов как read() делает. Для предотвращения повторно используемых проблем выше самый простой, самый безопасный дизайн должен остановить прерванное read() каждый раз, когда сигнал происходит во время своего выполнения.

2
27.01.2020, 19:38

Теги

Похожие вопросы