spin_lock_irqsave против spin_lock_irq - PullRequest
24 голосов
/ 01 апреля 2010

На SMP-машине мы должны использовать spin_lock_irqsave, а не spin_lock_irq из контекста прерывания.

Зачем нам сохранять флаги (которые содержат IF)?

Есть ли другая процедура прерывания, которая может прервать нас?

Ответы [ 5 ]

39 голосов
/ 19 февраля 2013

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

Пример:

  1. Допустим, что прерывание x было отключено до того, как была получена блокировка вращения
  2. spin_lock_irq отключит прерывание x и снимет блокировку
  3. spin_unlock_irq включит прерывание x.

Таким образом, на третьем шаге выше после снятия блокировки у нас будет включено прерывание x, которое ранее было отключено до получения блокировки.

То есть, только когда вы уверены, что прерывания не отключены, вы должны spin_lock_irq, иначе вы всегда должны использовать spin_lock_irqsave.

21 голосов
/ 03 апреля 2010

Я новичок в ядре, но из того, что я почерпнул из книги Роберта Лава "Разработка ядра Linux", если прерывания уже отключены на процессоре до того, как ваш код начинает блокироваться, при вызове spin_unlock_irq вы снимаете блокировку с ошибкой манера. Если вы сохраните флаги и отпустите их с флагами, функция spin_lock_irqsave просто вернет прерывание в предыдущее состояние.

Пример с spin_lock_irqsave

spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;

spin_lock_irqsave(&mLock, flags); // save the state, if locked already it is saved in flags
// Critical section
spin_unlock_irqrestore(&mLock, flags); // return to the formally state specified in flags

Пример с spin_lock_irq (без irqsave):

spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;

spin_lock_irq(&mLock); // Does not know if already locked
// Critical section
spin_unlock_irq(&mLock); // Could result in an error unlock...
5 голосов
/ 30 мая 2015

Потребность в spin_lock_irqsave помимо spin_lock_irq очень похожа на причину, по которой local_irq_save(flags) необходим помимо local_irq_disable. Вот хорошее объяснение этого требования, взятое у Роберта Лава из Linux Kernel Development Second Edition.

Функция local_irq_disable () опасна, если прерывания были уже отключен до его вызова. Соответствующий вызов local_irq_enable () безоговорочно разрешает прерывания, несмотря на факт, что они были с самого начала. Вместо этого нужен механизм восстановить прерывания в предыдущее состояние. Это общая проблема потому что заданный путь кода в ядре может быть достигнут как с без включенных прерываний, в зависимости от цепочки вызовов. Например, представьте, что предыдущий фрагмент кода является частью большой функции. Представьте, что эта функция вызывается двумя другими функциями, одна из которых отключает прерывания и тот, который не делает. Потому что это становится сложнее по мере увеличения размера и сложности ядра узнать весь код пути, ведущие к функции, гораздо безопаснее сохранить состояние система прерываний перед ее отключением. Затем, когда вы готовы включаемые прерывания, вы просто восстанавливаете их в исходное состояние:

unsigned long flags;

local_irq_save(flags);    /* interrupts are now disabled */ /* ... */
local_irq_restore(flags); /* interrupts are restored to their previous
state */

Обратите внимание, что эти методы реализованы, по крайней мере частично, как макросы, поэтому Параметр flags (который должен быть определен как unsigned long) казалось бы, передается по значению. Этот параметр содержит специфичные для архитектуры данные, содержащие состояние прерывания системы. Потому что по крайней мере одна поддерживаемая архитектура включает складывать информацию в значение (ahem, SPARC), флаги не могут быть переданы другой функции (в частности, она должна оставаться в том же стеке Рамка). По этой причине вызов сохранить и призыв восстановить прерывания должны происходить в одной и той же функции.

Все предыдущие функции могут быть вызваны как из прерывания, так и из контекст процесса.

2 голосов
/ 05 июля 2011

Чтение Почему код / ​​поток ядра, выполняющийся в контексте прерывания, не может спать? , который ссылается на Роберта Лавса статья , я прочитал это:

некоторые обработчики прерываний (известные в Linux как быстрые обработчики прерываний) со всеми прерываниями на местном процессор отключен. Это сделано для убедитесь, что обработчик прерываний работает без перерыва, так быстро, как возможный. Более того, все прерывают обработчики бегут со своим текущим линия прерывания отключена на всех процессоры. Это гарантирует, что два обработчики прерываний для того же линия прерывания не запускается одновременно. Это также предотвращает устройство писатели драйвера от необходимости справляться рекурсивные прерывания, которые усложняют программирования.

0 голосов
/ 13 августа 2018

Этот вопрос начинается с ложного утверждения: On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.

Ни один из них не должен использоваться от прерывания контекст, на SMP или на UP. Тем не менее, spin_lock_irqsave() может использоваться из контекста прерывания, поскольку является более универсальным (может использоваться как в прерывании, так и в обычном контексте), но вы должны использовать spin_lock() из контекста прерывания, и spin_lock_irq() или spin_lock_irqsave() из обычного контекста. Использование spin_lock_irq() почти всегда неправильно делать в контексте прерывания, будучи этим SMP или UP. Может сработает потому что большинство обработчиков прерываний работают с локальными IRQ, но вы не должны пытаться это сделать.

...