Ядро Linux в комментариях

Schedule


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

Как уже упоминалось в , здесь выполняются «нижние половины» обработчиков прерываний.

Реализует часть планировщика реального времени (SCHED_RR), перемещая «исчерпавшийся» процесс RR — уже полностью использовавший свой временной квант — в конец очереди, чтобы другие процессы RR с таким же приоритетом могли сделать свой ход. Одновременно это обновляет временной квант исчерпавшегося процесса. Важно, чтобы такое обновление не выполнялось для SCHED_FIFO, чтобы последующие процессы не были вынуждены освобождать процессор при истечении отведенных им временных квантов.

schedule часто используется потому, что какой-то другой фрагмент программы пришел к заключению о необходимости перемещения процесса в или из состояния TASK_RUNNING — например, при выполнении аппаратного условия, которого дожидался процесс; поэтому данный переключатель при необходимости изменяет состояние процесса. Если процесс уже находится в состоянии TASK_RUNNING, он остается неизменным. Если он был прерываемым (дожидающимся сигнала) и сигнал пришел, процесс возвращается в состояние TASK_RUNNING. Во всех остальных случаях (например, если процесс переходит в состояние TASK_UNINTERRUPTIBLE) процесс долен быть удален из текущей очереди.

Инициализирует значением, соответствующим первой задаче в текущей очереди; р выполнит циклический просмотр всех задач в очереди.

с отслеживает наибольшую адекватность (goodness) всех процессов в текущей очереди — наиболее адекватный процесс — тот, который имеет наибольшие требования к процессору. (Функция goodness будет вскоре рассмотрена.) Чем выше адекватность, тем лучше; причем значение адекватности процесса никогда не бывает отрицательным, в отличие от непонятной ситуации, ставшей привычной для пользователей Unix, когда более высокий приоритет (обычно называемый более высоким уровнем правильности (niceness)) приводит к тому, что процессу будет выделен меньший интервал времени процессора. (По крайней мере, это имеет смысл внутри ядра.)


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

В этом цикле рассматриваются только те процессы, которые могут быть запланированы. Реализация SMP-макроса can_schedule приведена в строке ; его определение заставляет ядро SMP рассматривать планирование задач в этом центральном процессоре только если задача еще не выполняется в нем. (В этом заключен большой смысл — было бы расточительным без необходимости перетасовывать задачи.) однопроцессорная версия приведена в строке и это значение всегда истинно — другими словами, в однопроцессорной системе все процессы в текущей очереди соревнуются за получение доступа к центральному процессору.

Значение адекватности, равное 0, означает, что процесс полностью использовал свой лимит временного кванта, или что он был вынужден освободить процессор. Если все процессы в текущей очереди имеют значение адекватности, равное 0, в конце цикла с равно 0, В этом случае schedule повторно вычисляет счетчики процессов; новое значение счетчика равно половине старого значения плюс значение статического приоритета процесса — и поскольку старое значение равно 0, если только процесс не освободил процессор, обычно schedule всего лишь повторно инициализирует счетчики значениями их статического приоритета. (Встретившийся в этом цикле процесс, мог бы также быть добавлен обработчиком прерываний или подпрограммой fork другого процессора, пока функция schedule искала наивысшее значение адекватности; поэтому значение его счетчика могло быть ненулевым. Однако, такой случай встречается редко.) Тем не менее, планировщик не утруждает себя повторным вычислением того, какой процесс обладает наивысшей адекватностью в данный момент; он лишь планирует процесс, первым встретившийся ему в предыдущем цикле. На тот момент этот процесс был первым найденным им, который имел наилучшее на тот момент значение адекватности (0), поэтому функция schedule заключает, что пока все сделано, и что программа будет успешно работать в течение длительного времени. (Помните, что речь идет о мышлении в стиле «быстро и приблизительно».)



Если schedule решила запланировать другой процесс из тех, что выполнялись ранее, она должна подавить старый процесс и позволить выполняться новому. Это выполняется с помощью функции switch_to, которая будет исследована следующей. Один важный результат работы функции switch_to может показаться очень странным разработчикам приложений: обращение к функции schedule не выполняет возврат. По крайней мере, не сразу; функция осуществляет возврат, когда система снова переключается на текущую задачу. Особым случаем вызова schedule является случай, когда она вызывается потому, что задача осуществляет выход; в этом случае вызов schedule никогда не возвращает значение — поскольку ядро никогда не переключается на задачу, которая осуществила выход. Еще один особый случай — когда функция schedule не запланировала другой процесс — т.е., если значения next и prev равны по окончании работы schedule — и, следовательно, переключение контекста не выполняется, а schedule действительно возвращает значение немедленно.

В однопроцессорных системах функции __schedule_tail и reacquire_kernel_lock в конце функции schedule не представляют собой ничего особенного, поэтому мы закончим исследование ядра планировщика. При случае, чтобы убедиться в правильном понимании кода, попытайтесь доказать следующее свойство: если текущая очередь пуста, следующей будет запланирована простаивающая задача.


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