Драйверы для устройств Linux: Спящая, пока удерживается блокировка блокировки - PullRequest
0 голосов
/ 20 мая 2018

Меня всегда учили, что спать с удерживанием спин-блокировки в коде ядра - нет-нет.Причина этого заключается в следующем сценарии:

  1. Поток A получает блокировку, выполняет некоторую работу и вызывает функцию ядра, которая переходит в спящий режим, освобождая процессор.
  2. Поток Bтеперь запускается, что пытается получить блокировку, но не может, поскольку она удерживается потоком A.
  3. Это тупик.Поток A не может быть разбужен, поскольку поток B постоянно вращается, а поток B не может прогрессировать, так как не может получить блокировку.

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

Однако я не совсем уверен, что у меня есть ошибка в моих руках.Используя вышеописанный сценарий, поток A является контекстом пользователя (а именно внутри реализации read()), а поток B является контекстом прерывания (внутри ISR).Блокировка блокируется через spin_lock_irqsave().В результате поток B не может работать, пока поток A удерживает блокировку, что делает невозможным взаимоблокировку.

Я также учел следующее:

  1. Поток A = контекст прерывания.Здесь Поток A не может спать (и не спит), поэтому мы никогда не попадаем в состояние взаимоблокировки.
  2. Поток A и B оба являются контекстом пользователя (то есть одновременные вызовы read()).Это не может произойти из-за наличия других механизмов.

Есть ли что-то, чего мне не хватает?В том, что я описал выше, есть ли реальная опасность, связанная со сном, удерживая замок?

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Меня всегда учили, что спать во время удержания спин-блокировки в коде ядра - нет-нет.

Вы путаете спин-блокировки и отключеныпрерывает (атомарный контекст, IRQ).

  1. Просто спит , имея спин-блокировку (приобретается с spin_lock) вредит perfomance , потому что другой поток, желая заблокировать спин-блокировку, тратит время с занятым ожиданием.Но в остальном система в порядке.

  2. Но спит с отключенными прерываниями означает, что ядро ​​ЦП не работает : ононичего не выполняет и не реагирует на прерывания от других ядер и внешнего мира.

    Это то, что произойдет, если ваш вызов spin_lock_irqsave сопровождается copy_from_user: первая операция отключает прерывания, а втораяможет спать.


Обычно отключенные прерывания сопровождают спин-блокировки (с помощью spin_lock_irqsave или аналогичные).В противном случае, если поток IRQ попытается получить такую ​​же спин-блокировку, будет наблюдаться взаимоблокировка : поток-владелец не сможет продолжить выполнение, поскольку он прерван, и поток IRQ не сможет продолжить работу, поскольку он ожидает спин-блокировки.

Отключение прерываний не требуется для получения некоторой спин-блокировки, если никакой поток IRQ (или поток с прерываниями, отключенными по другой причине) не блокирует данную спин-блокировку.Когда отключение прерываний не требуется, вместо spin_lock_irqsave можно использовать spin_lock.Но очень рекомендуется заменить спин-блокировки без IRQ мьютексами .

0 голосов
/ 21 мая 2018

Вопрос не складывается.

При использовании вышеописанного сценария поток A является пользовательским контекстом (а именно внутри реализации read ()), а поток B является контекстом прерывания (внутри ISR).).Блокировка блокируется с помощью spin_lock_irqsave ().В результате поток B не может работать, пока поток A удерживает блокировку, что делает невозможным взаимоблокировку.

Если вы удерживаете спин-блокировку для copy_to_user & friends, ядро ​​с отладкой предупредит вас о том, что выделать неправильно.Если возникнет необходимость уложить нить в режим сна, она перейдет в режим сна.Тогда вы вернулись на круги своя.

...