Неявное приоритетное прерывание обслуживания ядра

В Linux 2.6 реализовано новое неявное приоритетное прерывание обслуживания ядра. Когда задача ядра получает управление процессором, его обслуживание может приоритетно прерываться только другой задачей ядра, если она не содержит никаких блокировок. Каждая задача имеет поле preempt__count, помечающее задачу как приоритетно прерываемую. Счетчик увеличивается каждый раз, когда задача блокируется, и уменьшается, когда разблокируется. Функция schedule () отключает приоритетное прерывание обслуживания, когда определяет, какую задачу запустить следующей.
Существует две возможности для неявного приоритетного прерывания обслуживания ядра: либо код ядра вызывается из блока кода, для которого отключено приоритетное прерывание обслуживания, или процесс возвращается в код ядра из прерывания. Если управление возвращается в пространство ядра из прерывания, прерывание вызывает schedule () и новая задача вызывается тем же, описанным выше способом.
Если код ядра вызывается из блока кода с отключенным приоритетным прерыванием обслуживания, включение приоритетного прерывания обслуживания может привести к приоритетному прерыванию обслуживания текущей задачи:
iaclude/linux/preempt.h
46 #define preempt_enable() \
47 do { \

48 preempt_enable_no_resched(); \
49 preempt_check_resched(); \
50 } while (0)
include/linux/preempt.h
40 #define preempt_check_resched() \
41 do { \
42 if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
43 preempt_schedule(); \
44 } while (0)

Строки 40-44
Preempt_check_resched () смотрит, помечена ли текущая задача как требующая перепланировки; если это так, вызывается preempt_schedule ().
_sched preempt_schedule(void)

kernel/sched.c
2328 asmlinkage void
2329 {

386

Глава 7 • Планировщик и синхронизация ядра

2330 struct thread_info *ti = current_thread_infо();
2331
2332 /*
2333 * Если отключено ненулевое количество preempt_count или
2334 * прерываний, мы не хотим приоритетно прерывать обслуживание
2335 * текущей задачи. Просто возвращаемся. */
2336 if (unlikely(ti->preempt_count || irqs_disabled()))
2337 return;
2338
233 9 need_resched:
2340 ti->preempt_count = PREEMPT_ACTIVE;
2341 schedule();
2342 ti->preempt_count = 0; 2343
2344 /* мы можем потерять возможность приоритетного прерывания
обслуживания между планировщиком и текущим моментом */
2345 barrier!),-
2346 if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
2347 goto need_resched;
2348 }

Строки 2336-2337
Если текущая задача все еще имеет положительное значение preempt_count, как при рекурсивной команде preempt_disable (), или если для текущей задачи отключены прерывания, мы возвращаем управление процессором текущей задаче.
Строки 2340-2347
Текущая задача не имеет блокировок, так как preempt_count равно 0, a IRQ включены. Поэтому мы устанавливаем preempt_count текущей задачи для обозначения входящего приоритетного прерывания обслуживания и вызываем schedule (), выбирающую другую задачу.
Если задача запущена из кода, требующего перепланировки, ядру нужно удостовериться, что у текущей задачи можно забрать управление процессором. Ядро проверяет значение preempt_count задачи. Если preempt_count равно 0 и поэтому текущая задача не содержит блокировок, вызывается schedule () и для выполнения выбирается новая задача. Если preempt_count не равно 0, передавать управление другой задаче небезопасно, а управление возвращается в текущую задачу до тех пор, пока с нее не будут сняты все блокировки. Когда текущая задача освобождает блокировку, проверяют, требует ли задача перепланировки. Когда текущая задача освобождает последнюю блокировку и preempt_count достигает 0, производится немедленное перепланирование.