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

на главную

Жанры

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

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

Сила рода. Том 3

Вяч Павел
2. Претендент
Фантастика:
фэнтези
боевая фантастика
6.17
рейтинг книги
Сила рода. Том 3

Измена. Истинная генерала драконов

Такер Эйси
1. Измены по-драконьи
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Измена. Истинная генерала драконов

Убивать чтобы жить 7

Бор Жорж
7. УЧЖ
Фантастика:
героическая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 7

Самый лучший пионер

Смолин Павел
1. Самый лучший пионер
Фантастика:
попаданцы
альтернативная история
5.62
рейтинг книги
Самый лучший пионер

Завод 2: назад в СССР

Гуров Валерий Александрович
2. Завод
Фантастика:
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Завод 2: назад в СССР

Я тебя не предавал

Бигси Анна
2. Ворон
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Я тебя не предавал

Весь цикл «Десантник на престоле». Шесть книг

Ланцов Михаил Алексеевич
Десантник на престоле
Фантастика:
альтернативная история
8.38
рейтинг книги
Весь цикл «Десантник на престоле». Шесть книг

Газлайтер. Том 17

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

Курсант: назад в СССР 2

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

Сердце Дракона. Том 9

Клеванский Кирилл Сергеевич
9. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.69
рейтинг книги
Сердце Дракона. Том 9

Газлайтер. Том 1

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

Белые погоны

Лисина Александра
3. Гибрид
Фантастика:
фэнтези
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Белые погоны

Кротовский, сколько можно?

Парсиев Дмитрий
5. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Кротовский, сколько можно?

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

Северный Лис
5. Мимик!
Фантастика:
юмористическая фантастика
попаданцы
рпг
5.00
рейтинг книги
Мимик нового Мира 6