2016-05-10 12 views
1

Я читал о реализации семафоров Linux. Из-за атомарности, сигнала и ожидания (вверх и вниз в исходном коде) используются блокировки спина. Затем я увидел прерывание с отключением Linux в spin_lock_irqsave и повторное включение прерывания в spin_unlock. Это меня смутило. На мой взгляд, в критическом разделе действительно нет прерывания прерывания точки.Почему прерывание отключено между spin_lock и spin_unlock в Linux?

Например, proc A (в настоящее время активен) получил блокировку, proc B (заблокирован) ждет блокировки, а proc C выполняет некоторые несвязанные вещи. Это имеет смысл переключиться на контекст в C в критической секции между A и B. Даже если C также пытается получить блокировку, так как блокировка уже заблокирована A, результатом будет блокировка C и возобновление выполнения.

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

+0

Это может помочь вам понять, почему: http://www.makelinux.net/ldd3/chp-5-sect-5 –

+0

Спасибо! В разделе 5.5.2 предлагаемой статьи были рассмотрены мои проблемы. – secXsQuared

ответ

1

Позвольте мне начать с оговоркой, что я не эксперт Linux, так что мой ответ не может быть наиболее точным. Укажите, пожалуйста, какие-либо недостатки и проблемы.

Представьте, что некоторые общие данные используются различными частями ядра, включая такие операции, как обработчики прерываний, которые должны быть быстрыми и не могут блокироваться. Предположим, что системный вызов foo в настоящее время активен и приобрел блокировку для использования/доступа к общим данным bar, а прерывания не отключены, когда/до получения указанной блокировки.

Теперь (аппаратный) обработчик прерывания, например. клавиатура, ногами и также нуждается в доступе к bar (аппаратные прерывания имеют более высокий приоритет, чем системные вызовы). Поскольку bar в настоящее время заблокирован syscall foo, обработчик прерываний ничего не может сделать. Обработчики прерываний должны быть быстрыми. & не блокируются, поэтому они просто продолжают вращаться, пытаясь получить блокировку, что приведет к тупику (то есть системное зависание), так как syscall foo никогда не получит шанс закончить и отпустить свою блокировку ,

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

+0

Благодарим вас за ответ. Я действительно не рассматривал этот сценарий. Тогда как насчет многоядерной системы? Достаточно ли просто отключить прерывание локального ядра?Поскольку в этом случае не было бы тупика. – secXsQuared

+0

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

+0

Следует также отметить, что если данные используются несколькими обработчиками прерываний, вы должны отключить прерывания перед тем, как получить спин-блокировку (используя 'spin_lock_irqsave') для ** всех ** обработчиков и функций, которые могут быть прерваны прерыванием с более высоким приоритетом, что также использует те же данные. Только обработчик прерываний с наивысшим приоритетом не должен отключать прерывания. –

0

Но что, если прерывание хочет сигнализировать ожидающую нить? Или хотите проверить значение sempahore? Отключение irq здесь не для предотвращения переключения контекста между двумя процессами, но для защиты от irq. Все это в комментарии в начале файла:

/* 
    * Some notes on the implementation: 
    * 
    * The spinlock controls access to the other members of the semaphore. 
    * down_trylock() and up() can be called from interrupt context, so we 
    * have to disable interrupts when taking the lock. It turns out various 
    * parts of the kernel expect to be able to use down() on a semaphore in 
    * interrupt context when they know it will succeed, so we have to use 
    * irqsave variants for down(), down_interruptible() and down_killable() 
    * too. 
    * 
    * The ->count variable represents how many more tasks can acquire this 
    * semaphore. If it's zero, there may be tasks waiting on the wait_list. 
    */ 
+0

Спасибо за ваш ответ. Если я правильно понимаю, если прерывание пытается получить блокировку, которая была заблокирована контекстом до прерывания, тогда возник бы тупик, поскольку обработчики прерываний не могут быть выгружены? В следующий раз я обязательно прочитаю комментарии. – secXsQuared