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

на главную

Жанры

Разработка ядра Linux
Шрифт:

Каждый процесс в системе имеет всего один порождающий процесс. Кроме того, каждый процесс может иметь один или более порожденных процессов. Процессы, которые порождены одним и тем же родительским процессом, называются родственными (siblings). Информация о взаимосвязи между процессами хранится в дескрипторе процесса. Каждая структура

task_struct
содержит указатель на структуру
task_struct
родительского процесса, который называется parent, эта структура также имеет список порожденных процессов, который называется
children
. Следовательно, если известен текущий процесс (
current
), то для него можно определить дескриптор родительского процесса с помощью
выражения:

struct task_struct *task = current->parent;

Аналогично можно выполнить цикл по процессам, порожденным от текущего процесса, с помощью кода:

struct task_struct *task;

struct list_head *list;

list_for_each(list, &current->children) {

 task = list_entry(list, struct task_struct, sibling);

 /* переменная task теперь указывает на один из процессов,

порожденных текущим процессом */

}

Дескриптор процесса

init
— это статически выделенная структура данных с именем
init_task
. Хороший пример использования связей между всеми процессами — это приведенный ниже код, который всегда выполняется успешно.

struct task_struct *task;

for (task = current; task != $init_task; task = task->parent)

 ;

/* переменная task теперь указывает на процесс init */

Конечно, проходя по иерархии процессов, можно перейти от одного процесса системы к другому. Иногда, однако, желательно выполнить цикл по всем процессам системы. Такая задача решается очень просто, так как список задач — это двухсвязный список. Для того чтобы получить указатель на следующее задание из этого списка, имея действительный указатель на дескриптор какого-либо процесса, можно использовать показанный ниже код:

list_entry(task->tasks.next, struct task_struct, tasks);

Получение указателя на предыдущее задание работает аналогично.

list_entry(task->tasks.prev, struct task_struct, tasks);

Дна указанных выше выражения доступны также в виде макросов

next_task(task)
(получить следующую задачу),
prev_task(task)
(получить предыдущую задачу). Наконец, макрос
for_each_process(task)
позволяет выполнить цикл по всему списку задач. На каждом шаге цикла переменная
task
указывает на следующую задачу из списка:

struct task_struct *task;

for_each_process(task) {

 /* просто печатается имя команды и идентификатор PID

для каждой задачи */

 printk("%s[%d]\n", task->comm, task->pid);

}

Следует заметить, что организация цикла по всем задачам системы, в которой выполняется много процессов, может быть достаточно дорогостоящей операцией. Для применения такого кода должны быть веские причины (и отсутствовать другие альтернативы).

Создание нового процесса

В операционной системе Unix создание процессов происходит уникальным образом. В большинстве операционных систем для создания процессов используется метод порождения процессов (spawn). При этом создается новый процесс в новом адресном пространстве, в которое считывается исполняемый файл, и после этого начинается исполнение процесса. В ОС Unix используется другой подход, а именно разбиение указанных выше операций на две функции:

fork
и
exec
[15] .

15

Под

exec
будем понимать любую функцию из семейства
exec*
. В ядре реализован системный вызов
execve
, на основе которого реализованы библиотечные функции
execlp
,
execle
,
execv
и
execvp
.

В начале с помощью функции

fork
создается порожденный процесс, который является копией текущего задания. Порожденный процесс отличается от родительского только значением идентификатора
PID
(который является уникальным в системе), значением параметра
PPID
(идентификатор
PID
родительского процесса, который устанавливается в значение
PID
порождающего процесса), некоторыми ресурсами, такими как ожидающие на обработку сигналы (которые не наследуются), а также статистикой использования ресурсов. Вторая функция —
exec
— загружает исполняемый файл в адресное пространство процесса и начинает исполнять его. Комбинация функций
fork
и
exec
аналогична той одной функции создания процесса, которую предоставляет большинство операционных систем.

Копирование при записи

Традиционно при выполнении функции

fork
делался дубликат всех ресурсов родительского процесса и передавался порожденному. Такой подход достаточно наивный и неэффективный. В операционной системе Linux вызов
fork
реализован с использованием механизма копирования при записи (copy-on-write) страниц памяти. Технология копирования при записи (copy-on-write, COW) позволяет отложить или вообще предотвратить копирование данных. Вместо создания дубликата адресного пространства процесса родительский и порожденный процессы могут совместно использовать одну и ту же копию адресного пространства. Однако при этом данные помечаются особым образом, и если вдруг один из процессов начинает изменять данные, то создается дубликат данных, и каждый процесс получает уникальную копию данных. Следовательно, дубликаты ресурсов создаются только тогда, когда в эти ресурсы осуществляется запись, а до того момента они используются совместно в режиме только для чтения (read-only). Такая техника позволяет задержать копирование каждой страницы памяти до того момента, пока в эту страницу памяти не будет осуществляться запись. В случае, если в страницы памяти никогда не делается запись, как, например, при вызове функции
exec
сразу после вызова
fork
, то эти страницы никогда и не копируются. Единственные накладные расходы, которые вносит вызов функции
fork
, — это копирование таблиц страниц родительского процесса и создание дескриптора порожденного процесса. Данная оптимизация предотвращает ненужное копирование большого количества данных (размер адресного пространства часто может быть более 10 Мбайт), так как процесс после разветвления в большинстве случаев сразу же начинает выполнять новый исполняемый образ. Эта оптимизация очень важна, потому чти идеология операционной системы Unix предусматривает быстрое выполнение процессов.

Функция
fork

В операционной системе Linux функция

fork
реализована через системный вызов
clone
. Этот системный вызов может принимать в качестве аргументов набор флагов, определяющих, какие ресурсы должны быть общими (если вообще должны) у родительского и порожденного процессов. Далее в разделе "Реализация потоков в ядре Linux" об этих флагах рассказано более подробно. Библиотечные вызовы
fork
,
vfork
и
__clone
вызывают системную функцию
clone
с соответствующими флагами. В свою очередь системный вызов
clone
вызывает функцию ядра
do_fork
.

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

Искушение генерала драконов

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

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

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

Третье правило дворянина

Герда Александр
3. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Третье правило дворянина

Третий. Том 2

INDIGO
2. Отпуск
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 2

Лорд Системы 11

Токсик Саша
11. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 11

Обыкновенные ведьмы средней полосы

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Обыкновенные ведьмы средней полосы

Купеческая дочь замуж не желает

Шах Ольга
Фантастика:
фэнтези
6.89
рейтинг книги
Купеческая дочь замуж не желает

Para bellum

Ланцов Михаил Алексеевич
4. Фрунзе
Фантастика:
попаданцы
альтернативная история
6.60
рейтинг книги
Para bellum

Неверный

Тоцка Тала
Любовные романы:
современные любовные романы
5.50
рейтинг книги
Неверный

Неудержимый. Книга VI

Боярский Андрей
6. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга VI

Огненный князь

Машуков Тимур
1. Багряный восход
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Огненный князь

Вперед в прошлое 6

Ратманов Денис
6. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 6

Без шансов

Семенов Павел
2. Пробуждение Системы
Фантастика:
боевая фантастика
рпг
постапокалипсис
5.00
рейтинг книги
Без шансов

Истребители. Трилогия

Поселягин Владимир Геннадьевич
Фантастика:
альтернативная история
7.30
рейтинг книги
Истребители. Трилогия