Чтение онлайн

на главную - закладки

Жанры

Разработка ядра Linux (Второе издание)
Шрифт:

 unsigned long long timestamp last tick; /* последняя метка времени

планировщика */

 struct task_struct *curr; /* текущее задание, выполняемое на данном

процессоре */

 struct task_struct *idle; /* холостая задача данного процессора */

 struct mm_struct *prev_mm; /* поле mm_struct последнего выполняемого

задания */

 struct prio_array *active; /* указатель на активный массив приоритетов */

 struct prio_array *expired; /* указатель на истекший

массив приоритетов */

 struct prio_array arrays[2]; /*
массивы приоритетов */

 struct task_struct *migration_thread; /* миграционный поток для

данного процессора */

 struct list_head migration_queue; /* миграционная очередь для

данного процессора */

 atomic_t nr_iowait; /* количество заданий, ожидающих на ввод-вывод */

};

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

cpu_rq(processor)
возвращает указатель на очередь выполнения, связанную с процессором, имеющим заданный номер. Аналогично макрос
this_rq
возвращает указатель на очередь, связанную с текущим процессором. И наконец, макрос
task_rq(task)
возвращает указатель на очередь, в которой находится соответствующее задание.

Перед тем как производить манипуляции с очередью выполнения, ее необходимо заблокировать (блокировки подробно рассматриваются в главе 8, "Введение в синхронизацию выполнения кода ядра"). Так как очередь выполнения уникальна для каждого процессора, процессору редко необходимо блокировать очередь выполнения другого процессора (однако, как будет показано далее, такое все же иногда случается). Блокировка очереди выполнения позволяет запретить внесение любых изменений в структуру данных очереди, пока процессор, удерживающий блокировку, выполняет операции чтения или записи полей этой структуры. Наиболее часто встречается ситуация, когда необходимо заблокировать очередь выполнения, в которой выполняется текущее задание. В этом случае используются функции

task_rq_lock
и
task_rq_unlock
, как показано ниже.

struct runqueue *rq;

unsigned long flags;

rq = task_rq_lock(task, &flags);

/* здесь можно производить манипуляции с очередью выполнения */

task_rq_unlock(rq, flags);

Альтернативными функциями выступают функция

this_rq_lock
, которая позволяет заблокировать текущую очередь выполнения, и функция
rq_unlock(struct runqueue *rq)
, позволяющая разблокировать указанную в аргументе очередь.

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

/* для того, чтобы заблокировать ... */

if (rq1 < rq2) (

 spin_lock(&rq1->lock);

 spin_lock(&rq2->lock);

} else (

 spin_lock(&rq2->lock);

 spin_lock(&rq1->lock);

}

/* здесь можно манипулировать обеими очередями ... */

/* для того, чтобы разблокировать ... */

spin_unlock(&rq1->lock);

spin_unlock(&rq2->lock);

С помощью функций

double_rq_lock
и
double_rq_unlock
указанные шаги можно
выполнить автоматически. При этом получаем следующее.

double_rq_lock(rq1, rq2);

/* здесь можно манипулировать обеими очередями ...*/

double_rq_unlock(rq1, rq2);

Рассмотрим небольшой пример, который показывает, почему важен порядок захвата блокировок. Вопрос взаимных блокировок обсуждается в главах 8, "Введение в синхронизацию выполнения кода ядра" и 9, "Средства синхронизации в ядре". Эта проблема касается не только очередей выполнения: вложенные блокировки должны всегда захватываться в одном и том же порядке. Спин-блокировки используются для предотвращения манипуляций с очередями выполнения несколькими задачами одновременно. Принцип работы этих блокировок аналогичен ключу, с помощью которого открывают дверь. Первое задание, которое подошло к двери, захватывает ключ, входит в дверь и закрывает ее с другой стороны. Если другое задание подходит к двери и определяет, что дверь закрыта (потому что за дверью находится первое задание), то оно должно остановиться и подождать, пока первое задание на выйдет и не возвратит ключ. Ожидание называется спиннингом (вращением, spinning), так как на самом деле задание постоянно выполняет цикл, периодически проверяя, не возвращен ли ключ. Теперь рассмотрим, что будет, если одно задание пытается сначала заблокировать первую очередь выполнения, а затем вторую, в то время как другое задание пытается сначала заблокировать вторую очередь, а затем — первую. Допустим, что первое задание успешно захватило блокировку первой очереди, в то время как второе задание захватило блокировку второй очереди. После этого первое задание пытается заблокировать вторую очередь, а второе задание — первую. Ни одно из заданий никогда не добьется успеха, так как другое задание уже захватило эту блокировку. Оба задания будут ожидать друг друга вечно. Так же как в тупике дороги создается блокировка движения, так и неправильный порядок захвата блокировок приводит к тому, что задания начинают ожидать друг друга вечно, и тоже возникает тупиковая ситуация, которая еще называется взаимоблокировкой. Если оба задания захватывают блокировки в одном и том же порядке, то рассмотренной ситуации произойти не может. В главах 8 и 9 представлено полное описание блокировок.

Массивы приоритетов

Каждая очередь выполнения содержит два массива приоритетов (priority arrays): активный и истекший. Массивы приоритетов определены в файле

kernel/sched.c
в виде описания
struct prio_array
. Массивы приоритетов — это структуры данных, которые обеспечивают O(1)-планирование. Каждый массив приоритетов содержит для каждого значения приоритета одну очередь процессов, готовых к выполнению. Массив приоритетов также содержит битовую маску приоритетов (priority bitmap), используемую для эффективного поиска готового к выполнению задания, у которого значение приоритета является наибольшим в системе.

 struct prio_array {

 int nr_active; /* количество заданий */

 unsigned long bitmap[BITMAP_SIZE]; /* битовая маска приоритетов */

 struct list_head queue[MAX_PRIO]; /* очереди приоритетов */

};

Константа

MAX_PRIO
— это количество уровней приоритета в системе. По умолчанию значение этой константы равно 140. Таким образом, для каждого значения приоритета выделена одна структура
struct list_head
. Константа
BITMAP_SIZE
 — это размер массива переменных, каждый элемент которого имеет тип
unsigned long
. Каждый бит этого массива соответствует одному действительному значению приоритета. В случае 140 уровней приоритетов и при использовании 32-разрядных машинных слов, значение константы
BITMAP_SIZE
равно 5. Таким образом, поле
bitmap
 — это массив из пяти элементов, который имеет длину 160 бит.

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

Вкус ледяного поцелуя

Полякова Татьяна Викторовна
2. Ольга Рязанцева
Детективы:
криминальные детективы
9.08
рейтинг книги
Вкус ледяного поцелуя

Проблема майора Багирова

Майер Кристина
1. Спецназ
Любовные романы:
современные любовные романы
6.60
рейтинг книги
Проблема майора Багирова

Прометей: владыка моря

Рави Ивар
5. Прометей
Фантастика:
фэнтези
5.97
рейтинг книги
Прометей: владыка моря

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

(Не)зачёт, Дарья Сергеевна!

Рам Янка
8. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
(Не)зачёт, Дарья Сергеевна!

Запасная дочь

Зика Натаэль
Фантастика:
фэнтези
6.40
рейтинг книги
Запасная дочь

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Отвергнутая невеста генерала драконов

Лунёва Мария
5. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Отвергнутая невеста генерала драконов

Случайная жена для лорда Дракона

Волконская Оксана
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Случайная жена для лорда Дракона

Тройняшки не по плану. Идеальный генофонд

Лесневская Вероника
Роковые подмены
Любовные романы:
современные любовные романы
6.80
рейтинг книги
Тройняшки не по плану. Идеальный генофонд

Идеальный мир для Лекаря 28

Сапфир Олег
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 28

Лейтенант космического флота

Борчанинов Геннадий
1. Звезды на погонах
Фантастика:
боевая фантастика
космическая фантастика
космоопера
рпг
фэнтези
фантастика: прочее
5.00
рейтинг книги
Лейтенант космического флота

Гарем на шагоходе. Том 5

Гремлинов Гриша
5. Волк и его волчицы
Фантастика:
боевая фантастика
фэнтези
5.00
рейтинг книги
Гарем на шагоходе. Том 5

Матабар III

Клеванский Кирилл Сергеевич
3. Матабар
Фантастика:
фэнтези
5.00
рейтинг книги
Матабар III