Почему отключение прерываний отключает вытеснение в ядре и как спин-блокировка отключает вытеснение
Я недавно читаю Linux Kernel Development, и у меня есть несколько вопросов, связанных с отключением вытеснения.
В разделе "Контроль прерываний" главы 7 говорится:
Кроме того, отключение прерываний также отключает вытеснение ядра.
Я также прочитал из книги, что выгрузка ядра может происходить в следующих случаях:
При выходе из обработчика прерываний, прежде чем вернуться в пространство ядра.
Когда код ядра снова становится вытесняемым.
Если задача в ядре явно вызывает schedule()
Если задача в ядре блокируется (что приводит к вызову schedule())Но я не могу связать отключение прерываний с этими случаями.
Насколько я знаю, спин-блокировка отключит выгрузку с помощью функции preempt_disable().
Пост Что такое "спин-лок"? говорит:
На одноядерном компьютере спин-блокировка - это просто "отключение прерываний" или "повышение IRQL", которое полностью предотвращает планирование потоков.
Отключает ли preempt_disable() приоритетное прерывание, отключая прерывания?
2 ответа
Я не гуру планировщика, но я хотел бы объяснить, как я это вижу. Вот несколько вещей.
- preempt_disable() не отключает IRQ. Это просто увеличивает
thread_info->preempt_count
переменная. - Отключение прерываний также отключает приоритетное прерывание, потому что планировщик не работает после этого - но только на машине с одним ЦП. На SMP этого недостаточно, потому что когда вы закрываете прерывания на одном процессоре, другие / другие все еще делают / делают что-то асинхронно.
- Большой замок (означает - закрытие всех прерываний на всех процессорах) резко замедляет работу системы, поэтому он больше не используется. Это также причина, почему preempt_disable() не закрывает IRQ.
Вы можете увидеть, что такое preempt_disable(). Попробуйте это: 1. Получить спинлок. 2. Расписание звонков ()
В dmesg вы увидите что-то вроде "BUG: планирование пока атомное". Это происходит, когда планировщик обнаруживает, что ваш процесс находится в атомарном (не вытесняющем) контексте, но сам планирует.
Удачи.
В тестовом модуле ядра, который я написал для мониторинга / профилирования задачи, я попытался отключить прерывания:
1 - Использование local_irq_save ()
2 - Использование spin_lock_irqsave ()
3 - отключение вручную IRQ () для всех IRQ в / proc / interrupts
Во всех трех случаях я все еще мог использовать hrtimer для измерения времени, даже если прерывания IRQ были отключены (и задача, которую я отслеживал, также была прервана).
Я нахожу этот вееееерррыйый странным... Я лично предвосхищал то, на что указал Себастьян Маунтаниол -> Никаких прерываний - нет часов. Нет часов - нет таймеров...
Ядро Linux 2.6.32 на одно ядро, один процессор... Кто-нибудь может дать лучшее объяснение?
preempt_disable()
не отключает прерывания. Однако он увеличивает счетчик вытеснения. Допустим, вы звонитеpreempt_disable()
n раз в пути кода, приоритетное прерывание будет разрешено только на n-мpreempt_enable()
.- отключение прерываний для предотвращения вытеснения: небезопасный способ. Это, несомненно, отключит обычное приоритетное прерывание работы ядра, потому что
scheduler_tick()
не будет вызываться при системном тике (обработчик прерывания не вызывается). Однако, если программа запускает функцию расписания, приоритетное обслуживание произойдет, еслиpreempt_disable()
не был вызван. - В Linux
raw_spin_lock()
не отключает локальные прерывания, которые могут привести к тупиковой ситуации. Например, если вызывается обработчик прерывания, который пытается заблокировать уже удерживаемую блокировку спина, он не сможет этого сделать, если сам процесс не освободит его, что невозможно, поскольку не произойдет возврата из прерывания. Итак, лучше использоватьraw_spin_lock_irq()
, который отключает прерывания.
Отключение прерывания отключает некоторые формы вытеснения ядра, но есть и другие способы вытеснения ядра. По этой причине отключение прерываний не считается безопасным способом предотвращения вытеснения ядра.
Например, с отключенными прерываниями cond_resched() все равно будет вызывать приоритетное прерывание, но не будет, если прерывание было явно отключено.
Вот почему, что касается вашего второго вопроса, спин-блокировки не используют отключение прерывания для отключения вытеснения. Они явно вызывают preempt_disable(), которая увеличивает preempt_count и отключает все возможные способы вытеснения, кроме явных вызовов schedule().