Что происходит, когда код ядра прерывается?

#linux-kernel #critical-section #interrupt

#linux-ядро #критический раздел #прерывание

Вопрос:

Я читаю концепции операционной системы (Silberschatz, Galvin, Gagne), 6-е издание, глава 20. Я понимаю, что код ядра Linux не является вытесняемым (до версии 2.6). Но это может быть прервано аппаратными прерываниями. Что произойдет, если ядро находилось в середине критической секции, и произошло прерывание, и оно тоже выполнило критическую секцию?

Из того, что я прочитал в книге:

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

Хорошо, эта схема используется, когда ISR имеет критическую секцию. Но это только отключит дальнейшие прерывания. Как насчет кода ядра, который был прерван этим прерыванием в первую очередь?

Ответ №1:

Но это только отключит дальнейшие прерывания. Как насчет кода ядра, который был прерван этим прерыванием в первую очередь?

Если обработчику прерывания и другому коду ядра требуется доступ к одним и тем же данным, вам необходимо защититься от этого, что обычно выполняется с помощью блокировки вращения, необходимо проявлять большую осторожность, вы не хотите создавать взаимоблокировку и должны убедиться, что такая блокировка вращения не удерживается слишком долго. Для спин-блокировок, используемых в аппаратном обработчике прерываний, вы должны отключить прерывания на этом процессоре, удерживая блокировку — что в Linux делается с помощью функции spin_lock_irqsave().

(хотя он немного устарел, вы можете прочитать о концепции здесь)

Комментарии:

1. Это правильно — если критический раздел совместно используется с обработчиком прерываний, он должен использовать один из вариантов блокировки вращения с отключением прерываний.

Ответ №2:

Код ядра, который был прерван этим прерыванием в первую очередь, прерывается.

Вот почему написание обработчиков прерываний является такой болезненной задачей: они не могут сделать ничего, что могло бы поставить под угрозу корректность основного потока выполнения.

Например, способ, которым ядро xnu от Apple обрабатывает большинство видов прерываний устройства, заключается в том, чтобы записать информацию из прерывания в запись в памяти, добавить эту запись в очередь, а затем возобновить обычное выполнение; затем ядро некоторое время спустя извлекает прерывания из очереди (я полагаю, в основном цикле планировщика). Таким образом, обработчик прерываний взаимодействует с остальной частью системы только через очередь прерываний, и существует небольшая опасность того, что это вызовет проблемы.

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