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

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

Жанры

Разработка ядра 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
.

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

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

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

Наследник с Меткой Охотника

Тарс Элиан
1. Десять Принцев Российской Империи
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Наследник с Меткой Охотника

Волк 2: Лихие 90-е

Киров Никита
2. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 2: Лихие 90-е

Наследница Драконов

Суббота Светлана
2. Наследница Драконов
Любовные романы:
современные любовные романы
любовно-фантастические романы
6.81
рейтинг книги
Наследница Драконов

Я – Орк. Том 4

Лисицин Евгений
4. Я — Орк
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я – Орк. Том 4

Бывшая жена драконьего военачальника

Найт Алекс
2. Мир Разлома
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Бывшая жена драконьего военачальника

Мимик нового Мира 4

Северный Лис
3. Мимик!
Фантастика:
юмористическая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Мимик нового Мира 4

Восход. Солнцев. Книга X

Скабер Артемий
10. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга X

Проводник

Кораблев Родион
2. Другая сторона
Фантастика:
боевая фантастика
рпг
7.41
рейтинг книги
Проводник

Польская партия

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

Последний Паладин. Том 2

Саваровский Роман
2. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 2

Черный Маг Императора 5

Герда Александр
5. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 5

Провинциал. Книга 2

Лопарев Игорь Викторович
2. Провинциал
Фантастика:
космическая фантастика
рпг
аниме
5.00
рейтинг книги
Провинциал. Книга 2

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

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