Понимание связи между CONFIG_SMP, Spinlocks и CONFIG_PREEMPT в последнем (3.0.0 и выше) ядре Linux

Чтобы дать вам полный контекст, мое обсуждение началось с наблюдения, что я запускаю SMP linux (3.0.1-rt11) на ARM cortex A8 на базе SoC, который является однопроцессорным. Мне было интересно узнать, будет ли какое-либо преимущество в производительности, отключив поддержку SMP. И если да, какое влияние это окажет на мои драйверы и обработчики прерываний.

Я прочитал кое-что и столкнулся с двумя смежными темами: spinlocks и ядро ​​preemption. Я немного поработал в поисковых системах и читал, но на этот раз все, что у меня есть, - это несколько устаревших и противоречивых ответов. Поэтому я подумал, что позвольте мне попробовать stackoverflow.

Происхождение моих сомнений/вопросов - это пара из драйверов устройств Linux 3-е издание, глава 5:

Спинкины по своей природе предназначены для использования на многопроцессорных систем, , хотя однопроцессорная рабочая станция, работающая на упреждающем Ядро ведет себя как SMP, в отношении concurrency. Если невосприимчивая однопроцессорная система когда-либо заводила на замок, это будет вращаться навсегда; никакая другая нить никогда не сможет получить CPU для освобождения блокировки. По этой причине операции спин-блокировки на однопроцессорные системы без предварительного включения оптимизированы для выполнения ничего, за исключением тех, которые изменяют маскирование IRQ положение дел. Из-за предпосылки, даже если вы никогда не ожидаете, что ваш код будет запускать на SMP-системе, вам по-прежнему необходимо реализовать правильную блокировку.

Мои сомнения/вопросы:

a) Является ли ядро ​​Linux приоритетным в пространстве ядра по умолчанию? Если да, является ли это ограничение преимуществом только процессами или обработчиками прерываний также могут быть вытеснены?

b) Поддерживает ли ядро ​​Linux (на ARM) вложенное прерывание? Если да, будет ли каждый обработчик прерывания (верхняя половина) иметь собственный стек или они будут использовать один и тот же стек режима ядра 4k/8k?

c) Если отключить SMP (Config_SMP) и preemption (Config_preempt), будут ли блокировки в моих драйверах и обработчиках прерываний иметь какой-то смысл?

d) Как прерывания дескриптора ядра возникают при выполнении верхней половины i.e будут ли они отключены или замаскированы?

После некоторого googling я нашел это:

Для ядер, скомпилированных без CONFIG_SMP, и без CONFIG_PREEMPT спин-блокировки вообще не существуют. Это отличное дизайнерское решение: когда никто не может работать одновременно, нет оснований блокировка.

Если ядро ​​скомпилировано без CONFIG_SMP, но CONFIG_PREEMPT set, то spinlocks просто отключить preemption, что достаточно для предотвращать любые расы. Для большинства целей мы можем думать о эквивалентно SMP, и не беспокоиться об этом отдельно.

Но нет версии ядра или даты в источнике . Может ли кто-нибудь подтвердить, что он все еще действителен для последних ядер Linux?

+7
источник поделиться
1 ответ

a) Является ли Linux превентивным или нет, зависит от того, настроен ли он так или нет с CONFIG_PREEMPT. По умолчанию нет. Если вы запустите make config, вам нужно будет выбрать.

b) Прерывания выполняются в Linux; в то время как прерывания обрабатываются, другие прерывания могут исчезнуть. Это верно для ARM и многих других архитектур. Все это в одном стеке. Конечно, стеки пользовательского пространства не используются для прерываний!

c) Если вы отключите SMP и preemption, спин-блокировки вашего кода уменьшатся до no-op, если они являются регулярными прямыми затворами, а блокировки блокировки IRQ (spin_lock_irqsave/spin_lock_irqrestore) превратятся в прерывание disable/enable. Поэтому последние по-прежнему необходимы; они предотвращают гонки между задачами, запускающими ваш код, и прерываниями, запускающими ваш код.

d) "Верхняя половина" традиционно относится к процедурам обслуживания прерываний. Верхний половинный код драйвера управляется прерываниями. Нижняя половина называется задачами (для чтения или записи данных или чего-то еще). Информация об обработке прерываний является специфичной для архитектуры.

Недавно я очень тесно работал с прерываниями Linux в конкретной архитектуре MIPS. На этой конкретной плате было 128 прерывистых линий, маскируемых двумя 64-битными словами. Ядро реализовало схему приоритета поверх этого, поэтому перед выполнением обработчика для данного прерывания нижние были замаскированы через обновления этих 2x64-разрядных регистров. Я внедрил модификацию, чтобы приоритеты прерываний можно было задавать произвольно, а не по позиции аппаратного обеспечения и динамически, записывая значения в запись /proc. Более того, я вложил взломы, в результате чего часть числового приоритета IRQ перекрывалась с приоритетом задач в реальном времени. Таким образом, задачи RT (то есть потоки пользовательского пространства), назначенные определенному диапазону уровней приоритета, могли неявно подавлять определенный диапазон прерываний во время работы. Это было очень полезно для предотвращения помех, вызванных нарушениями критически важных задач (например, подпрограммы обслуживания прерываний в коде драйвера IDE, используемого для компактной вспышки, которая выполняет петли занятости из-за плохо спроектированного аппаратного интерфейса, становятся де-факто наивысшим приоритетом в системе.) Так или иначе, поведение маскировки IRQ не написано на камне, если вы контролируете ядро, используемое клиентами.

Указанные предложения в вопросе верны только о регулярных спин-блоках (spin_lock function/macro), а не оверлоках IRQ (spin_lock_irqsave). В привилегированном ядре на однопроцессорной системе spin_lock просто нужно отключить преемственность, чего достаточно, чтобы оставить все остальные задачи вне ядра до spin_unlock. Но spin_lock_irqsave должен отключить прерывания.

+6
источник

Посмотрите другие вопросы по меткам или Задайте вопрос