Вход/Регистрация
Разработка ядра Linux
вернуться

Лав Роберт

Шрифт:

sd->nr_balance_failed = 0;

 sd->balance_interval = sd->min_interval;

 return nr_moved;

out_balanced:

 spin_unlock(&this_rq->lock);

 if (sd->balance_interval < sd->max_interval)

sd->balance_interval *= 2;

 return 0;

}

Вытеснение и переключение контекста

Переключение контекста — это переключение от одной, готовой к выполнению задачи к другой. Это переключение производится с помощью функции

context_switch
, определенной в файле
kernel/sched.c
. Данная функция вызывается функцией
schedule
, когда новый процесс выбирается для выполнения. При этом выполняются следующие шаги.

• Вызывается функция

switch_mm
, которая определена в файле
include/asm/mmu_context.h
и предназначена для переключения от виртуальной памяти старого процесса к виртуальной памяти нового процесса.

• Вызывается функция

switch_to
, определенная в файле
include/asm/system.h
, для переключения от состояния процессора предыдущего процесса к состоянию процессора нового процесса. Эта процедура включает восстановление информации стека ядра и регистров процессора.

Ядро должно иметь информацию о том, когда вызывать функцию

schedule
. Если эта функция будет вызываться только тогда, когда программный код вызывает ее явно, то пользовательские программы могут выполняться неопределенное время. Поэтому ядро поддерживает флаг
need_resched
для того, чтобы сигнализировать, необходимо ли вызывать функцию
schedule
(табл. 4.2). Этот флаг устанавливается функцией
scheduler_tick
, когда процесс истрачивает свой квант времени, и функцией
try_to_wake_up
, когда процесс с приоритетом более высоким, чем у текущего процесса, возвращается к выполнению. Ядро проверяет значение этого флага, и если он установлен, то вызывается функция
schedule
для переключения на новый процесс. Этот флаг является сообщением ядру о том, что планировщик должен быть активизирован по возможности раньше, потому что другой процесс должен начать выполнение.

Таблица 4.2. Функции для управления флагом need_resched

Функция Назначение
set_tsk_need_resched(task)
Установить флаг
need_resched
для данного процесса
clear_tsk_need_resched(task)
Очистить флаг
need_resched
для данного процесса
need_resched
Проверить значение флага
need_resched
для данного процесса. Возвращается значение
true
, если этот флаг установлен, и
false
, если не установлен

Во время переключения в пространство пользователи или при возврате из прерывания, значение флага

need_resched
проверяется. Если он установлен, то ядро активизирует планировщик перед тем, как продолжить работу.

Этот флаг не является глобальной переменной, так как обращение к дескриптору процесса получается более быстрым, чем обращение к глобальным данным (из-за скорости обращения к переменной

current
и потому, что соответствующие данные могут находиться в кэше). Исторически, этот флаг был глобальным в ядрах до серии 2.2. В ядрах серий 2.2 и 2.4 этот флаг принадлежал структуре
task_struct
и имел тип
int
. В серии ядер 2.6 этот флаг перемещен в один определенный бит специальной переменной флагов структуры
thread_info
. Легко видеть, что разработчики ядра никогда не могут быть всем довольны.

Вытеснение пространства пользователя

Вытеснение пространства пользователя (user preemption) происходит в тот момент, когда ядро собирается возвратить управление режиму пользователя, при этом устанавливается флаг

need_resched
и, соответственно, активизируется планировщик. Когда ядро возвращает управление в пространство пользователя, то оно находится в безопасном и "спокойном" состоянии. Другими словами, если продолжение выполнения текущего задания является безопасным, то безопасным будет также и выбор нового задания для выполнения. Поэтому когда ядро готовится возвратить управление в режим пользователя или при возврате из прерывания или после системного вызова, происходит проверка флага
need_resched
. Если этот флаг установлен, то активизируется планировщик и выбирает новый, более подходящий процесс для исполнения. Как процедура возврата из прерывания, так и процедура возврата из системного вызова являются зависимыми от аппаратной платформы и обычно реализуются на языке ассемблера в файле
entry.S
(этот файл, кроме кода входа в режим ядра, также содержит и код выхода из режима ядра). Если коротко, то вытеснение пространства пользователя может произойти в следующих случаях.

• При возврате в пространство пользователя из системного вызова.

• При возврате в пространство пользователя из обработчика прерывания.

Вытеснение пространства ядра

Ядро операционной системы Linux, в отличие от ядер большинства вариантов ОС Unix, является полностью преемптивным (вытесняемым, preemptible). В непреемптивных ядрах код ядра выполняется до завершения. Иными словами, планировщик не может осуществить планирование для выполнения другого задания, пока какое-либо задание выполняется в пространстве ядра — код ядра планируется на выполнение кооперативно, а не посредством вытеснения. Код ядра выполняется до тех пор, пока он не завершится (возвратит управление в пространство пользователя) или пока явно не заблокируется. С появлением серии ядер 2.6, ядро Linux стало преемптивным: теперь есть возможность вытеснить задание в любой момент, конечно, пока ядро находится в состоянии, когда безопасно производить перепланирование выполнения.

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

Первое изменение, внесенное для поддержки вытеснения пространства ядра, — это введение счетчика преемптивности

preempt_count
в структуру
thread_info
каждого процесса. Значение этого счетчика вначале равно нулю и увеличивается на единицу при каждом захвате блокировки, а также уменьшается на единицу при каждом освобождении блокировки. Когда значение счетчика равно нулю— ядро является вытесняемым. При возврате из обработчика прерывания, если возврат выполняется в пространство ядра, ядро проверяет значения переменных
need_resched
и
preempt_count
. Если флаг
need_resched
установлен и значение счетчика preempt_count равно нулю, значит, более важное задание готово к выполнению и выполнять вытеснение безопасно. Далее активизируется планировщик. Если значение счетчика
preempt_count
не равно нулю, значит, удерживается захваченная блокировка и выполнять вытеснение не безопасно. В таком случае возврат из обработчика прерывания происходит в текущее выполняющееся задание. Когда освобождаются все блокировки, удерживаемые текущим заданием, значение счетчика
preempt_count
становится равным нулю. При этом код, осуществляющий освобождение блокировки, проверяет, не установлен ли флаг
need_resched
. Если установлен, то активизируется планировщик. Иногда коду ядра необходимо иметь возможность запрещать или разрешать вытеснение в режиме ядра, что будет рассмотрено в главе 9.

  • Читать дальше
  • 1
  • ...
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: