Вывод из активного состояния

Мы уже обсуждали, как задача попадает в планировщик после вызова fork и как задача перемещается из массивов активных приоритетов в истекшие в очереди выполнения на процессоре. Но когда же задача удаляется из очереди выполнения?
Задача может быть удалена из очереди выполнения двумя основными способами:
• задача прерывается ядром и изменяет состояние на незапущенное, после чего в задачу перестают поступать сигналы (см. строку 2240 в kernel /sched. с);
• на SMP-машинах задача может быть удалена из очереди выполнения и помещена в другую очередь выполнения (см. строку 3384 в kernel/sched. с).
Первый случай происходит, когда schedule () вызывается после того, как процесс погружается в сон в очереди ожидания. Задача помечает себя как невыполняемая (TASK_INTERRUPTIBLE, TASK_UNINTERRUPTIBLE, TASK_STOPPED и т. Д.), и ядро перестает предоставлять ей доступ к процессору, удаляя ее из очереди выполнения.
Случай, когда процесс перемещается в другую очередь выполнения, обрабатывается в SMP-разделе ядра Linux, который мы здесь не рассматриваем.
Теперь мы проследим, как процесс удаляется из очереди выполнения с помощью deactivate_task().
kernel/sched.с
507 static void deactivate_task(struct task_struct *p,
508 {
509 rq->nr_running--;
510 if (p->state == TASK_UNINTERRUPTIBLE)
511 rq->nr_uninterruptible++;
512 dequeue_task(p, p->array);
Строка 509
Сначала планировщик уменьшает количество запущенных процессов, так как р больше не является запущенной.
Строки 510—511
Если задача непрерывна, мы увеличиваем количество непрерывных задач в очереди выполнения. Соответствующие операции декрементации вызываются, когда непрерывный процесс просыпается [см. строку 824 в kernel /sched. с в функции try_to_wake_up () ].
Строки 512-513
Статистика нашей очереди выполнения обновляется, как только мы удаляем процесс из очереди выполнения. Ядро использует поле р->аггау для проверки того, является ли процесс запущенным и находится ли он в очереди выполнения. Так как больше ни одно из этих условий не выполняется, мы устанавливаем его в NULL.
Необходимо сделать еще кое-что с очередью выполнения; давайте рассмотрим специфику degueue_task ().
kernel/sched.с
303 static void dequeue_task(struct task_struct *p, prio_array_t *array)
304 {

305 array->nr_active—;
306 list_del(&p->run_list);
307 if (list_empty(array->gueue + p->prio))
308 clear_bit(p->prio, array->bitmap);
309 }
Строка 305
Мы изменяем количество активных задач в массиве приоритетов, в котором находится процесс р; не важно, активный ли это массив или истекший.
Строки 306-308
Мы удаляем процесс из списка процессов в массиве приоритетов с приоритетом р. Если результирующий список будет пустым, нам нужно очистить бит в битовой карте массива приоритетов для того, чтобы указать, что в p->prio () не осталось процессов.
list_del () выполняет всю работу по удалению за один шаг, так как р-> run_list представляет собой структуру list_head и поэтому содержит указатели на предыдущее и следующее вхождения в списке.
Мы достигли точки, где процесс удаляется из очереди выполнения и становится пол-шктью неактивным. Если этот процесс находится в состоянии TASK_INTERRUPTIBLE т TASK_UNINTERRUPTIBLE, он может быть разбужен и помещен обратно в очередь шиюлнения. Если процесс находится в состоянии TASK_STOPPED, TASK_ZOMBIE или 1BIS5_DEAD, все его структуры удаляются и сбрасываются.