Как ядро ​​отслеживает, какие процессы получают данные из прерывания?

В вытесняющем ядре (скажем, Linux), скажем, процесс A делает вызов getc на stdin, поэтому он блокируется в ожидании символа. Я чувствую, что у меня есть фундаментальное непонимание того, как ядро ​​​​узнает, что нужно разбудить процесс A в этот момент и доставить данные после их получения.

Насколько я понимаю, этот процесс может быть переведен в приостановленное состояние, пока планировщик планирует запуск других процессов/потоков, или он будет вытеснен. Когда происходит нажатие клавиши, посредством опроса/прерываний, в зависимости от реализации, ОС запускает драйвер устройства, который декодирует нажатую клавишу. Однако возможно (и вероятно), что мой процесс A в настоящее время не запущен. На данный момент я сбит с толку тем, как мой процесс, который был заблокирован в ожидании ввода-вывода, теперь ставится в очередь для повторного запуска, особенно как он знает, какой процесс ожидает чего. Похоже, что драйверы устройств содержат некоторую форму очереди ожидания.

Точно так же, и я не уверен, что это точно связано с вышеизложенным, но если окно моего браузера, например, находится в фокусе, кажется, что оно получает нажатия клавиш, но не другие окна. Есть ли у каждого окна/процесса возможность «прослушивать» события клавиатуры, даже если они не в фокусе, но только не для удобства пользователя?

Поэтому мне любопытно, как ядра (или как некоторые из них) отслеживают, какие процессы ожидают каких событий, и когда эти события приходят, как они определяют, какие процессы планировать для запуска?


person rb612    schedule 31.05.2020    source источник


Ответы (1)


события, которые ожидают процессы, являются абстрактными программными событиями, такими как определенная очередь не пуста, а не конкретными аппаратными событиями, такими как прерывание 4635.

Некоторая конфигурация (возможно, руководствуясь описанием оборудования, таким как дерево устройств) идентифицирует прерывание 4635 как сигнал от данного последовательного устройства с заданным адресом. Драйвер последовательного устройства настраивается таким образом, чтобы иметь доступ к регистрам устройства этого последовательного порта, и прикрепляет свой обработчик прерывания к заданному идентификатору прерывания (4635).

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

Это примерно описывает ситуацию с использованием условных переменных в качестве механизма сигнализации между прерываниями и процессами, как это было установлено в ядрах UNIX-y 44 года назад. Другие подходы включают освобождение семафора для каждого символа в очереди; или отвечая сообщениями для каждого персонажа. Существует множество форм синхронизации, которые можно использовать.

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

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

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

person mevets    schedule 31.05.2020
comment
Спасибо! Это полезно. Значит ли это, что только один процесс может использовать данный символ, или это взаимное исключение зависит от реализации (т. е. драйвер может доставить один и тот же символ нескольким ожидающим процессам?) - person rb612; 01.06.2020
comment
Для этого существует множество стратегий, опять же реализуемых слоями абстракций в различных операционных системах. Кульминация сеансов и управление заданиями в операционных системах, производных от UNIX, отвечает на этот вопрос таким образом, что для понимания требуются всего месяцы усилий :) - person mevets; 01.06.2020
comment
Короче говоря, водитель ставит его в очередь. Менеджер очереди решает, какой «сеанс» должен его получить, и процесс, принадлежащий этому сеансу, получает его. Итак, еще один уровень абстракции. Если вы поэкспериментируете с процессом, который устанавливает свой stdin в необработанный режим, fork()s, то и родительский, и дочерний read(2) с 0, и printf(%d: got %c\n, getpid(), c) ; вы можете увидеть, как это работает из первых рук. - person mevets; 01.06.2020