Запрещение обработки нижних половин

We use cookies. Read the Privacy and Cookie Policy

Запрещение обработки нижних половин

Обычно только одного запрещения обработки нижних половин недостаточно. Наиболее часто, чтобы полностью защитить совместно используемые данные, необходимо захватить блокировку и запретить обработку нижних половин. Методы, которые позволяют это сделать и которые обычно используются при разработке драйверов, будут рассмотрены в главе 9. Однако при разработке самого кода ядра иногда необходимо запретить только обработку нижних половин.

Для того чтобы запретить обработку всех типов нижних половин (всех отложенных прерываний и, соответственно, тасклетов), необходимо вызвать функцию local_bh_disable(). Для разрешения обработки нижних половин необходимо вызвать функцию local_bh_enable(). Да, у этих функций "неправильные" названия. Никто не потрудился переименовать эти функции, когда интерфейс BH уступил место интерфейсу отложенных прерываний. В табл. 7.4 приведены сведения об этих функциях.

Таблица 7.4. Список функций управления обработкой нижних половин

Функция Описание void local_bh_disable() Запретить обработку всех отложенных прерываний (softirq) и тасклетов (tasklet) на локальном процессоре void local_bh_enable() Разрешить обработку всех отложенных прерываний (softirq) и тасклетов (tasklet) на локальном процессоре

Вызовы этих функций могут быть вложенными — при этом только последний вызов функции local_bh_enable() разрешает обработку нижних половин. Например, при первом вызове функции local_bh_disable() запрещается выполнение отложенных прерываний на текущем процессоре. Если функция local_bh_disable() вызывается еще три раза, то выполнение отложенных прерываний будет запрещено. Их выполнение не будет разрешено до тех пор, пока функция local_bh_enable() не будет вызвана четыре раза.

Такая функциональность реализована с помощью счетчика preempt_count, который поддерживается для каждого задания (интересно, что этот же счетчик используется и для вытеснения процессов в режиме ядра)[42]. Когда значение этого счетчика достигает нуля, то можно начать обработку нижних половин. Так как при вызове функции local_bh_enable() обработка нижних половин запрещена, то эта функция также проверяет наличие ожидающих на обработку нижних половин и выполняет их.

Для каждой поддерживаемой аппаратной платформы имеются спои функции, которые обычно реализуются через сложные макросы, описанные в файле <asm/softirq.h>. Для любопытных ниже приведены соответствующие реализации на языке программирования С.

/*

* запрещение обработки нижних половин путем увеличения значения

  счетчика preempt_count

*/

void local_bh_disable(void) {

 struct thread_info *t = current_thread_info();

 t->preempt_count += SOFTIRQ_OFFSET;

}

/*

* уменьшение значения счетчика preempt_count "автоматически" разрешает

* обработку нижних половин, если значение счетчика равно нулю

*

* опционально запускает все обработчики нижних половин,

* которые ожидают на обработку

*/

void local_bh_enable(void) {

 struct thread_info *t = current_thread_info();

 t->preempt_count -= SOFTIRQ_OFFSET;

 /*

 * равно ли значение переменной preempt_count нулю и ожидают ли

 * на обработку какие-либо обработчики нижних половин?

 * если да, то запустить их

 */

 if (unlikely(!t->preempt_count &&

  softirq_pending(smp_processor_id())))

  do_softirq();

}

Эти функции не запрещают выполнения очередей действий. Так как очереди действий выполняются в контексте процесса, нет никаких проблем с асинхронным выполнением и нет необходимости запрещать их. Поскольку отложенные прерывания и тасклеты могут "возникать" асинхронно (например, при возвращении из обработчика аппаратного прерывания), то ядру может потребоваться запрещать их. В случае использования очередей отложенных действий защита совместно используемых данных осуществляется так же, как и при работе в контексте процесса. Детали рассмотрены в главах 8 и 9.