Следующим шагом в fork является выделение и инициализация структуры нового процесса. Эта операция должна быть сделана до того, как адресное пространство текущего процесса будет дублировано, поскольку она записывает состояние в структуру процесса. С момента времени, когда выделяется структура процесса, до тех пор, пока не будут выделены все необходимые ресурсы, родительский процесс заблокирован от подкачки, чтобы избежать тупиков. Порожденный процесс находится в противоречивом состоянии и еще не может быть запущен или выгружен, поэтому необходим родитель, чтобы завершить копирование его адресного пространства. Чтобы гарантировать игнорирование порожденного процесса планировщиком, ядро устанавливает состояние процесса в течение всей процедуры fork в NEW.
Исторически системный вызов fork действовал путем копирования всего адресного пространства родительского процесса. Когда разветвляются большие процессы, копирование всего адресного пространства пользователя дорого. Все страницы, находящиеся во вторичном хранилище, должны быть для копирования считаны обратно в память. Если памяти для обеих полных копий процесса недостаточно, этот недостаток памяти заставит систему начать подкачку, чтобы создать достаточно памяти для копирования. Операция копирования может привести к выгрузке частей родительского и порожденного процессов, а также к выгрузке частей не имеющих к этому отношения процессов.
Методика, используемая FreeBSD для создания процессов без этих издержек, называется копирование при записи (copy-on-write). Вместо того чтобы копировать каждую страницу родительского процесса, и родительскому, и порожденному процессам, проистекающим из разветвления, даются ссылки на одни и те же физические страницы. Таблицы страниц изменяются, чтобы предотвратить изменение любым из процессов разделяемой страницы. Вместо этого, когда процесс пытается изменить страницу, осуществляется вход в ядро с отказом защиты. После определения того, что отказ был вызван попыткой модификации разделяемой страницы, ядро просто копирует страницу и изменяет поле защиты для страницы, чтобы снова разрешить изменение. Нужно копировать лишь страницы, измененные одним из процессов. Эта методика значительно повышает производительность fork, поскольку разветвляющиеся процессы обычно перекрывают порожденный процесс новым образом при выполнении exec вскоре после fork.
Следующим шагом в fork является прохождение по списку структур vm_map_entry в родителе и создание соответствующих элементов в порожденном. Каждый элемент должен быть проанализирован, и должно быть предпринято соответствующее действие.
Если элемент отображает область только для чтения или разделяемую область, потомок может получить ссылку на нее.
Если элемент отображает индивидуально отображенную область (такую, как область данных или стек), потомок должен создать отображение области с атрибутом копирования при записи. Отображение области в родителе должно быть преобразовано в копирование при записи. Если любой из процессов впоследствии попытается осуществить запись в эту область, он создаст теневое отображение, чтобы сохранить модифицированные страницы.
Элементы отображения для процесса никогда не объединяются (упрощаются). Объединяться могут лишь элементы для отображения самого ядра. Элементы отображения ядра нуждаются в упрощении таким образом, чтобы избежать чрезмерного расширения. Может оказаться целесообразным сделать такое объединение элементов отображения для процесса, когда он разветвляется, особенно для больших или долгоживущих процессов.
- 28/10/2010 17:19 - Изменение размера процесса
- 28/10/2010 11:59 - Раскраска страниц (page coloring)
- 28/10/2010 08:07 - Манипулирование процесса своим адресным пространством
- 26/10/2010 13:51 - Исполнение файла
- 26/10/2010 11:57 - Дизайн аппаратного кеша
- 26/10/2010 06:04 - Зональный распределитель ядра
- 25/10/2010 19:26 - Резервирование ресурсов ядра
- 25/10/2010 16:31 - Создание нового процесса
- 24/10/2010 07:08 - Malloc ядра
- 24/10/2010 06:47 - Индивидуальные моментальные снимки