Ю. Вахалия - UNIX изнутри (2003) (1114670), страница 19
Текст из файла (страница 19)
Процесс также имеет возможность временной блокировки сигнала. В таком случае сигнал будет доставлен процессу только после того, как тот будет разблокирован. Процесс не в состоянии прореагировать на сигнал немедленно. После вырабатывания сигнала ядро системы уведомляет об этом процесс при помощи установки бита в маске ожидающих сигналов, расположенной в структуре ргос данного процесса. Процесс должен постоянно быть готовым к получению сигнала и ответу на него. Это возможно только в том случае, если он находится в очереди на выполнение.
В начале выполнения процесс обрабатывает 84 Глава 2, Ядро и процессы все ожидающие его сигналы и только затем продолжает работать в режиме задачй. (Эта процедура не включает функционирование самих обработчиков Сигналов, которые также выполняются в режиме задачи.) Что же происходит в том случае, если сигнал предназначен для спящего процесса г Будет ли он ожидать того момента, когда процесс снова станет работоспособным, или его «сон» будет прерван? Это зависит от причины приостановки работы процесса. Если процесс ожидает события, которое вскоре должно произойти (например, завершение операции ввода-вывода с диска), то нет необходимости «будить» такой процесс.
С другой стороны, если процесс ожидает такое событие, как ввод с терминала, то заранее не известно, через какой промежуток времени оно может произойти. В таких случаях ядро системы будит процесс и прерывает выполнение системного вызова, из-за которого данный процесс был заблокирован. В операционной системе 4.3ВБР поддерживается системный вызов э1уп1еггцр1, который служит для управления реакцией системного вызова'.
Используя з1ул1епвр1, разработчик может указать, будет ли обработка системных вызовов, прерываемых сигналами, прекращена или возобновлена, Более подробно сигналы будут описаны в главе 4. 2.8. Новые процессы и программы Система ()Х1Х является многозадачной средой, и различные процессы действуют в ней все время. Каждый процесс в один момент времени выполняет только одну программу, однако несколько процессов могут выполнять одну и ту же программу в параллельном режиме. Такие процессы умеют разделять между собой единую копию текста (кода) программы, хранящейся в памяти, но при этом содержать собственные области данных и стека. Более того, процесс способен загружать одну или больше программ в течение своего времени жизни.
()Х1Х таким образом разделяет процессы и программы, которые могут выполняться при их помощи. Для поддержки многозадачной среды в ()Х1Х существует несколько различных системных вызовов, создающих и завершающих процессы, а также запускающих новые программы. Системные вызовы 1ог1 и ц1огМ служат для создания новых процессов. Вызов ехес загружает новую программу. Следует помнить о том, что работа процесса может быть завершена после принятия определенного сигнала. 2.8.1.
Вызовы Фогтс и ехес Системный вызов 1ог1 создает новый процесс. При этом вызывающий процесс становится родительским, а новый процесс является его потомком. Связь «родитель-потомок» создает иерархию процессов, графически изображенную ' Из-за которого процесс заблокирован, — Прим. ред. 2.8. Новые процессы и программы 85 на рис. 2.4. Процесс-потомок является точной копией своего родительского процесса. Его адресное пространство полностью повторяет пространство родительского процесса, а программа, выполняемая им изначально, также не отличается от той, что выполняет процесс-родитель. Фактически процесс-потомок начинает работу в режиме задачи после возврата из вызова Гот)с. Так как оба процесса (родитель и его потомок) выполняют одну и ту же программу, необходимо найти способ отличия их друг от друга и предоставления им возможности нормального функционирования.
С другой стороны, различные процессы' невозможно заставить выполнять различные действия. Поэтому системный вызов 1от)с возвращает различные значения процессу-родителю и его потомку: для потомка возвращается значение О, а для родителя — идентификатор Р!Е) потомка. Чаще всего после вызова )от)с процесс-потомок сразу же вызывает ехес и тем самым начинает выполнение новой программы. В библиотеке языка С существует несколько различных форм вызова ехес, таких как ехесе, ехесче и ехесчр. Все они незначительно отличаются друг от друга набором аргументов и после некоторых предварительных действий используют один и тот же системный вызов.
Общее имя ехес относится к любой неопределенной функции этой группы. В листинге 2.2 приведен фрагмент кода программы, использующий вызовы Гот)с и ехес. Листинг 2.2. Использование вызовов (огх и ехес !т ((гевц1с=тсгК)))==0 ( /* код прсцесса-пстснка */ 1( (ехесче("пеи ргс0гав("....)<О) реггог("ехесче таз1ее"); ех!т()): ) е1ве 1т (гезц1т<0) ( реггсг( тогк"); /* вызов тсгк неудачен */ ) /* здесь прсдолкаетсв выполнение прсцесса-предка*/ После наложения новой программы на существующий процесс при помощи ехес потомок не возвратит управление предыдущей программы, если не произойдет сбоя вызова. После успешного завершения работы функции ехес адресное пространство процесса-потомка будет заменено пространством новой программы, а сам процесс будет возвращен в режим задачи с установкой его указателя команд на первую выполняемую инструкцию этой программы.
Так как вызовы Гот)( и ехес часто используются вместе, возникает закономерный вопрос а может стоит использовать для выполнения задачи единый системный вызов, который создаст новый процесс и выполнит в нем новую программу. Первые системы (.))ч))Х (91 теряли много времени на дублирова- ' Имеется в виду оригинал и копия. — Прим. ред. 86 Глава 2. Ядро и процессы ние адресного пространства процесса-родителя для его потомка (в течение выполнения Го%) для того, чтобы потом все равно заменить его новой программой. Однако существует и немало преимуществ в разделении этих системных вызовов.
Во многих клиент-серверных приложениях сервер может создавать при помощи Гогй множество процессов, выполняющих одну и ту же программу', С другой стороны, иногда процессу необходимо запустить новую программу без создания для ее функционирования нового процесса. И наконец, между системными вызовами Гоги и ехес процесс-потомок может выполнить некоторое количество заданий, обеспечивающих функционирование новой программы в желаемом состоянии. Это могут быть задания, выполняющие: + операции перенаправления ввода, вывода или вывода сообщений об ошибках; + закрытие не нужных для новой программы файлов, наследованных от предка; + изменение идентификатора РГР или СГР (группы процесса); + сброс обработчиков сигналов.
Если все эти функции попробовать выполнить при помощи единственного системного вызова, то такая процедура окажется громоздкой и неэффективной. Существующая связка Гог1-ехес предлагает высокий уровень гибкости, а также является простой и модульной. В разделе 2.8.3 мы расскажем о способах минимизации проблем, связанных с быстродействием этой связки (из-за использования раздельных вызовов).
2.8.2. Создание процесса Системный вызов Гоги создает новый процесс, который является почти точной копией его родителя. Единственное различие двух процессов заключается только в необходимости отличать их друг от друга. После возврата из Гой процесс-родитель и его потомок выполняют одну и ту же программу (функционирование которой продолжается сразу же вслед за Гогк) и имеют идентичные области данных и стека. Системный вызов Гога во время своей работы должен совершить следующие действия: + зарезервировать пространство свопинга для данных и стека процесса- потомка; + назначить новый идентификатор РГР и структуру ргос потомка; + инициализировать структуру ргос потомка.
Некоторые поля этой структуры копируются от процесса-родителя (такие как идентификаторы ' С появлением современных многопотоковых систем 111ч!Х такая возможность больше не востребована: теперь сервер может иметь возможность сознания необходимого количества нитей выполнения. 2.8.
Новые процессы и программы 87 пользователя и группы, маски сигналов и группа процесса), часть полей устанавливается в 0 (время нахождения в резидентном состоянии, использование процессора, канал сна и т. д.), а остальным присваиваются специфические для потомка значения (поля идентификаторов РПЭ потомка и его родителя, указатель на структуру ргос родителя); + разместить карты трансляции адресов для процесса-потомка; + выделить область п потомка и скопировать в нее содержимое области ц процесса-родителя; + изменить ссылки области в на новые карты адресации и пространство свопинга; + добавить потомка в набор процессов, разделяющих между собой область кода программы, выполняемой процессом-родителем; + постранично дублировать области данных и стека родителя и модифицировать карты адресации потомка в соответствии этими новыми страницами; + получить ссылки на разделяемые ресурсы, наследуемые потомком, такие как открытые файлы и текущий рабочий каталог; + инициализировать аппаратный контекст потомка посредством копирования текущего состояния регистров его родителя; + сделать процесс-потомок выполняемым и поместить его в очередь планировщика; + установить для процесса-потомка по возврату из вызова (ой нулевое значение; + вернуть идентификатор Р10 потомка его родителю.
2.8.3. Оптимизация вызова 1ог1с Системный вызов 1ог1 должен предоставить процессу-потомку логически идентичную копию адресного пространства его родителя. В большинстве случаев потомок заменяет предоставленное адресное пространство, так как сразу же после выполнения $ой вызывает ехес или ех11. Таким образом, создание копии адресного пространства (так, как это реализовано в первых системах ПХ1Х) является неоптимальной процедурой. Вышеописанная проблема была решена двумя различными способами. Сначала был разработан метод копирования при записи, впервые нашедший реализацию в ОС Кузеев Ч и в настояший момент используемый в большинстве систем У1ч1Х.
При таком подходе страницы данных и стека родителя временно получают атрибут «только для чтения» и маркируются как «копируемые при записи», Потомок получает собственную копию карт трансляции адресов, но использует одни и те же страницы памяти вместе со своим родительским процессом. Если кто-то из них (родитель или потомок) попытается изменить страницу памяти, произойдет ошибочная исключительная 88 Глава 2. Ядро и процессы ситуация (так как страницы доступны только для чтения), после чего ядро системы запустит обработчик произошедшей ошибки.