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

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

Традиционно при выполнении функции 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().

Основную массу работы по разветвлению процесса выполняет функция do_fork(), которая определена в файле kernel/fork.c. Эта функция, в свою очередь, вызывает функцию copy_process() и запускает новый процесс на выполнение. Ниже описана та интересная работа, которую выполняет функция copy_process().

• Вызывается функция dup_task_struct(), которая создает стек ядра, структуры thread_info и task_struct для нового процесса, причем все значения указанных структур данных идентичны для порождающего и порожденного процессов. На этом этапе дескрипторы родительского и порожденного процессов идентичны.

• Проверяется, не произойдет ли при создании нового процесса переполнение лимита на количество процессов для данного пользователя.

• Теперь необходимо сделать порожденный процесс отличным от родительского. При этом различные поля дескриптора порожденного процесса очищаются или устанавливаются в начальные значения. Большое количество данных дескриптора процесса является совместно используемым.

• Далее состояние порожденного процесса устанавливается в значение TASK_UNINTERRUPTIBLE, чтобы гарантировать, что порожденный процесс не будет выполняться.

• Из функции copy_process() вызывается функция copy_flags(), которая обновляет значение поля flags структуры task struct. При этом сбрасывается флаг PF_SUPERPRIV, который определяет, имеет ли процесс права суперпользователя. Флаг PF_FORKNOEXEC, который указывает на то, что процесс не вызвал функцию exec(), — устанавливается.

• Вызывается функция get_pid(), которая назначает новое значение идентификатора PID для новой задачи.

• В зависимости от значений флагов, переданных в функцию clone(), осуществляется копирование или совместное использование открытых файлов, информации о файловой системе, обработчиков сигналов, адресного пространства процесса и пространства имен (namespace). Обычно эти ресурсы совместно используются потоками одного процесса. В противном случае они будут уникальными и будут копироваться на этом этапе.

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

• Наконец, происходит окончательная зачистка структур данных и возвращается указатель на новый порожденный процесс.

Далее происходит возврат в функцию do_fork(). Если возврат из функции copy_process() происходит успешно, то новый порожденный процесс возобновляет выполнение. Порожденный процесс намеренно запускается на выполнение раньше родительского[16].

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

Функция vfork()

Системный вызов vfork() позволяет получить тот же эффект, что и системный вызов fork(), за исключением того, что записи таблиц страниц родительского процесса не копируются. Вместо этого порожденный процесс запускается как отдельный поток в адресном пространстве родительского процесса и родительский процесс блокируется до того момента, пока порожденный процесс не вызовет функцию exec() или не завершится. Порожденному процессу запрещена запись в адресное пространство. Такая оптимизация была желанной в старые времена 3BSD, когда реализация системного вызова fork() не базировалась на технике копирования страниц памяти при записи. Сегодня, при использовании техники копирования страниц памяти при записи и запуске порожденного процесса перед родительским, единственное преимущество вызова vfork() — это отсутствие копирования таблиц страниц родительского процесса. Если когда-нибудь в операционной системе Linux будет реализовано копирование полей таблиц страниц при записи[17], то вообще не останется никаких преимуществ. Поскольку семантика функции vfork() достаточно ненадежна (что, например, будет, если вызов exec() завершится неудачно?), то было бы здорово, если бы системный вызов vfork() умер медленной и мучительной смертью. Вполне можно реализовать системный вызов vfork() через обычный вызов fork(), что действительно имело место в ядрах Linux до версии 2.2.

Сейчас системный вызов vfork() реализован через специальный флаг в системном вызове clone(), как показано ниже.

• При выполнении функции copy_process() поле vfork_done структуры task_struct устанавливается в значение NULL.

• При выполнении функции do_fvork(), если соответствующий флаг установлен, поле vfork_done устанавливается в ненулевое значение (начинает указывать на определенный адрес).

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

• При выполнении порожденным процессом функции mm_release() (которая вызывается, когда задание заканчивает работу со своим адресным пространством), если значение поля vfork_done не равно NULL, родительский процесс получает указанный выше сигнал.

• При возврате в функцию do_fork() родительский процесс возобновляет выполнение и выходит из этой функции.

Если все прошло так, как запланировано, то теперь порожденный процесс выполняется в новом адресном пространстве, а родительский процесс — в первоначальном адресном пространстве. Накладные расходы меньше, но реализация не очень привлекательна.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Учетные записи

Из книги Windows Vista автора Леонтьев Виталий Петрович

Учетные записи Windows – система не только многозадачная, но и МНОГОПОЛЬЗОВАТЕЛЬСКАЯ, рассчитанная на работу с несколькими пользовательскими конфигурациями. Причем каждая из них может не просто хранить в себе настройки интерфейса, но и обладать собственным набором


3. Записи

Из книги Информатика и информационные технологии: конспект лекций автора Цветкова А В

3. Записи Запись представляет собой совокупность ограниченного числа логически связанных компонент, принадлежащих к разным типам. Компоненты записи называются полями, каждое из которых определяется именем. Поле записи содержит имя поля, вслед за которым через


12. Записи

Из книги Информатика и информационные технологии автора Цветкова А В

12. Записи Запись представляет собой совокупность ограниченного числа логически связанных компонент, принадлежащих к разным типам. Компоненты записи называются полями, каждое из которых определяется именем. Поле записи содержит имя поля, вслед за которым через


Свойства записи

Из книги Sound Forge 9 автора Квинт Игорь

Свойства записи В программе Sound Forge все действия, связанные с записью, выполняются в окне Record (Запись) (рис. 7.5), для открытия которого необходимо выполнить команду Special ? Transport ? Record (Дополнительно ? Перемещение ? Запись). Рис. 7.5. Окно Record (Запись)О записи поговорим позже, а


Учетные записи

Из книги Тонкости реестра Windows Vista. Трюки и эффекты автора Клименко Роман Александрович

Учетные записи В состав меню Сервис программы Почта Windows входит команда Учетные записи.Возможности реестра позволяют удалить команду Учетные записи из меню Сервис. Для этого в разделе реестра HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows Mail необходимо создать REG_DWORD-параметр No modify accts и


Записи

Из книги Delphi. Учимся на примерах автора Парижский Сергей Михайлович


2.1.4. Записи

Из книги Интернет решения от доктора Боба автора Сворт Боб


2.2.7. Записи

Из книги MySQL: руководство профессионала автора Паутов Алексей В


2.4.5.7. Слот записи

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

2.4.5.7. Слот записи Слот записи представляет собой внутренний идентификатор записи, который используется, чтобы найти записи в памяти и на диске. Это по существу указатель на страницы, которые содержат данные для специфической записи. Новый слот записи создан для каждой


12.14.1 Записи SOA

Из книги Яндекс для всех автора Абрамзон М. Г.

12.14.1 Записи SOA Первой записью в файле стоит начало авторизации (Start of Authority — SOA):FISHFOOD.COM. IN SOA NS.FISHFOOD.COM. (                      postmaster.FISHFOOD.COM.                      94101101 ; serial number                         86400 ; refresh after 24 hours                          7200 ; retry after 2


12.14.5 Записи об адресе

Из книги Ubuntu 10. Краткое руководство пользователя автора Колисниченко Д. Н.

12.14.5 Записи об адресе Запись об адресе (address records) — это просто отображение имени в адрес. Таким образом, адресом ns.fishfood.com будет


1.11.3. Популярные записи

Из книги Недокументированные и малоизвестные возможности Windows XP автора Клименко Роман Александрович

1.11.3. Популярные записи Обновление списка популярных записей происходит раз в сутки. Таких записей отбирается несколько десятков, но лишь несколько самых популярных выносится на титульную страницу раздела Поиска. Остальные можно посмотреть по ссылке Всего записей.


12.1. Что нужно для записи CD и DVD?

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард

12.1. Что нужно для записи CD и DVD? Что же необходимо для комфортной записи CD и DVD? Давайте подумаем вместе.? Компьютер — это само собой разумеется. С одной стороны, ультрасовременный компьютер никогда не помешает, а с другой — CD и даже DVD можно записывать далеко не на самых


Угроза получения учетной записи администратора с помощью учетной записи опытного пользователя

Из книги Описание языка PascalABC.NET автора Коллектив РуБоард

Угроза получения учетной записи администратора с помощью учетной записи опытного пользователя Как говорилось раньше, использование группы Опытные пользователи не приветствуется Microsoft, так как данная группа имеет очень многие права в системе. В этой главе хотелось бы


Записи ресурсов

Из книги автора

Записи ресурсов Записи в DNS называются записями ресурсов (resource records, RR). Нас интересуют только несколько типов RR.? А. Запись типа А преобразует имя узла в 32-разрядный адрес IPv4. Вот, например, четыре записи DNS для узла freebsd в домене unpbook.com, первая из которых — это запись типа