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

       

Очереди задач


Очереди задач могут рассматриваться как, своего рода, динамическое расширение bottom halves. Фактически, в исходном коде, очереди задач иногда называются как "новые" bottom halves. Старые bottom halves, обсуждавшиеся в предыдущей секции, имеют следующие ограничения:

  • Фиксированное количество (32).
  • Каждый bottom half может быть связан только с одним обработчиком.
  • Bottom halves используются с захватом блокировки (spinlock) так что они не могут блокироваться.
  • В очередь же, может быть вставлено произвольное количество задач. Создается новая очередь задач макросом DECLARE_TASK_QUEUE(), а задача добавляется функцией queue_task(). После чего, очередь может быть обработана вызовом run_task_queue(). Вместо того, чтобы создавать собственную очередь (и работать с ней "вручную"), можно использовать одну из предопределенных в Linux очередей:

  • tq_timer: очередь таймера, запускается на каждом прерывании таймера и при освобождении устройства tty (закрытие или освобождение полуоткрытого терминального устройства). Так как таймер запускается в контексте прерывания, то и задачи из очереди tq_timer так же запускаются в контексте прерывания и следовательно не могут быть заблокированы.
  • tq_scheduler: очередь обслуживается планировщиком (а так же при закрытии устройств tty, аналогично tq_timer). Так как планировщик работает в контексте процесса, то и задачи из tq_scheduler могут выполнять действия, характерные для этого контекста, т.е. блокировать, использовать данные контекста процесса (для чего бы это?) и пр.
  • tq_immediate: в действительности представляет собой bottom half IMMEDIATE_BH, таким образом драйверы могут установить себя в очередь вызовом queue_task(task, &tq_immediate) и затем mark_bh(IMMEDIATE_BH) чтобы использоваться в контексте прерывания.
  • tq_disk: используется при низкоуровневом доступе к блоковым учтройствам (и RAID). Эта очередь экспортируется в модули но должна использоваться только в исключительных ситуациях.
  • Нет необходимости в драйвере вызывать run_tasks_queues(), если не используется своя собственная очередь задач, за исключением случаев, приведенных ниже.

    Драйвер, если помните, может запланировать задачи в очереди, но исполнение этих задач имеет смысл лишь до тех пор, пока экземпляр устройства остается верным - что обычно означает до тех пор, пока приложение не закрыло его. Поскольку очереди tq_timer/tq_scheduler используются не только в обычном месте (например они вызываются при закрытии tty устройств), то может возникнуть необходимость в вызове run_task_queue() из драйвера. для выталкивания задач из очереди, поскольку дальнейшее их исполнение не имеет смысла. По этой причине, иногда можно встретить вызов run_task_queue() для очередей tq_timer и tq_scheduler не только в обработчике прерываний от таймера и в schedule(), соответственно, но и в других местах.



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