The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

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

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

Предыдущая  Содержание  Следующая V*D*V

Создание процесса в Linux осуществляется с помощью системного вызова fork(). fork() создаёт для вызывающей стороны новый дочерний процесс. Как только fork возвращается, порождающий и порождённый становятся двумя независимыми субъектами, имеющими разные PID-ы. Теоретически, то, что необходимо сделать fork(), это создать точную копию всех структур данных родительского процесса, включая страницы памяти родительского процесса, доступные только ему. В Linux это дублирование страниц памяти родительского процесса является отложенным. Вместо этого порождающий и дочерний процессы совместно используют одни и те же страницы в памяти, пока один из них не попытается изменить общие страницы. Такой подход называется COW (Copy on Write, копирование при записи). Теперь давайте посмотрим, как fork() достигает этого. Мы обсудим  реализацию fork в Linux 2.6. В Linux 2.4 API называются по другому, но функциональность осталась прежней.

 

1.Создаётся новая структура задачи процесса для дочернего процесса.
 
p = dup_task_struct(current);
 
Это создаст новую структуру задачи и скопирует некоторые указатели из current.
 

2.Получается PID для дочернего процесса.
 
p->pid = alloc_pidmap();
 

3.Из родительского в дочерний процесс копируются файловые дескрипторы, обработчики сигналов, политики планировщика и так далее.
 
/* копируем всю информацию процесса */
 …
 …
// Копируем файловые дескрипторы
if ((retval = copy_files(clone_flags, p)))
 goto bad_fork_cleanup_semundo;
if ((retval = copy_fs(clone_flags, p)))
 goto bad_fork_cleanup_files;
 
// Копируем обработчики сигналов
if ((retval = copy_sighand(clone_flags, p)))
 goto bad_fork_cleanup_fs;
 
// Копируем информацию о сигналах
if ((retval = copy_signal(clone_flags, p)))
 goto bad_fork_cleanup_sighand;
 
// Копируем страницы памяти
if ((retval = copy_mm(clone_flags, p)))
 goto bad_fork_cleanup_signal;
 …
 …
 

4.Порождённый процесс добавляется в очередь планировщика задач и выполняется возврат.
 
 …
 …
/* Выполняем относящуюся к планировщику настройку */
sched_fork(p);
 …
 …
 
if (!(clone_flags & CLONE_STOPPED))
 wake_up_new_task(p, clone_flags);
else
 p->state = TASK_STOPPED;
 …
 …
 
Это изменит состояние процесса на TASK_RUNNING и включит данный процесс в список процесс работоспособных процессов, содержащийся в планировщике задач.

 

Как только fork возвращается, дочерний процесс становится работоспособным процессом и будет запланирован в соответствии с политикой планирования родительского процесса. Обратите внимание, что в fork копируются только структуры данных родительского процесса. Его сегменты текста, данных и стека не копируются. fork пометила такие страницы как COW для последующего выделения памяти по требованию.

На шаге 3 функция copy_mm() по существу помечает страницы родителя как общие только читаемые между родителем и потомком. Атрибут "только чтение" гарантирует, что содержимое памяти не может быть изменено, пока оно является общим. Всякий раз, когда любой из двух процессов пытается записать в эту страницу, обработчик ошибки страницы определяет COW страницу с помощью специальной проверки дескрипторов страницы. Страница, соответствующая ошибке, дублируется и помечается как доступная для записи в процессе, который пытался записать. Исходная страница остаётся защищённой от записи, пока другой процесс не попытается выполнить запись, в течение которой эта страница помечается доступной для записи только после проверки, что она уже не используется каким-то другим процессом.

Как показано выше, процесс дублирования в Linux, осуществляемый через COW, реализован с помощью обработчика ошибки страницы и, следовательно, uClinux не поддерживает fork(). Также для родителя и потомка невозможно иметь аналогичное виртуальное адресное пространство, как это ожидается от fork. Вместо использования для создания дочернего процесса fork(), разработчики uClinux предлагают использование vfork() вместе с exec(). Системный вызов vfork() создаёт дочерний процесс и блокирует выполнение родительского процесса, пока потомок не завершит работу или не выполнит новую программу. Это гарантирует, что родительскому и дочернему процессам не требуется иметь общий доступ к страницам памяти.

 

Предыдущая  Содержание  Следующая