Внутреннее устройство ядра Linux 2.4

       

Нижние половины (Bottom Halves)


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

Bottom halves - это самый старый механизм отложенного исполнения задач ядра и был доступен еще в Linux 1.x.. В Linux 2.0 появился новый механизм - "очереди задач" ('task queues'), который будет рассмотрен ниже.

Bottom halves упорядочиваются блокировкой (spinlock) global_bh_lock, т.е. только один bottom half может быть запущен на любом CPU за раз. Однако, если при попытке запустить обработчик, global_bh_lock оказывается недоступна, то bottom half планируется на исполнение планировщиком - таким образом обработка может быть продолжена вместо того, чтобы стоять в цикле ожидания на global_bh_lock.

Всего может быть зарегистрировано только 32 bottom halves. Функции, необходимые для работы с ними перечислены ниже (все они экспортируются в модули):

  • void init_bh(int nr, void (*routine)(void)): устанавливает обработчик routine в слот nr. Слоты должны быть приведены в include/linux/interrupt.h в форме XXXX_BH, например TIMER_BH или TQUEUE_BH. Обычно подпрограмма инициализации подсистемы (init_module() для модулей) устанавливает необходимый обработчик (bottom half) с помощью этой функции.
  • void remove_bh(int nr): выполняет действия противоположные init_bh(), т.е. удаляет установленный обработчик (bottom half) из слота nr. Эта функция не производит проверок на наличие ошибок, так, например remove_bh(32)

    вызовет panic/oops. Обычно подпрограммы очистки подсистемы (cleanup_module() для модулей) используют эту функцию для освобождения слота, который может быть позднее занят другой подсистемой. (TODO: Не плохо бы иметь /proc/bottom_halves - перечень всех зарегистрированных bottom halves в системе? Разумеется, что global_bh_lock должна быть типа "read/write")

  • void mark_bh(int nr): намечает bottom half в слоте nr на исполнение. Как правило, обработчик прерывания намечает bottom half на исполнение в наиболее подходящее время.
  • Bottom halves, по сути своей, являются глобальными "блокированными" тасклетами (tasklets), так, вопрос: "Когда исполняются обработчики bottom half ?", в действительности должен звучать как: "Когда исполняются тасклеты?". На этот вопрос имеется два ответа:

    а) при каждом вызове schedule()

    б) каждый раз, при исполнении кода возврата из прерываний/системных вызовов (interrupt/syscall return path) в entry.S.



    Содержание раздела