WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!

Pages:     | 1 |   ...   | 2 | 3 || 5 | 6 |   ...   | 8 |

«Андрей Робачевский Операционная система Рекомендовано Министерством общего и профессионального образования Российской Федерации в качестве учебного пособия для студентов высших учебных заведений ...»

-- [ Страница 4 ] --

Специальный регистр (CR3 для Intel) указывает на расположение каталога таблиц страниц в памяти. В SCO UNIX используется только один каталог, независимо от выполняющегося процесса, таким образом значение реги стра CR3 не меняется на протяжении жизни системы. Поскольку ядро (код и данные) является частью выполняющегося процесса, таблицы стра ниц, отображающие старший 1 Гбайт виртуальной памяти, принадлежа щей ядру системы, не изменяются при переключении между процессами.

Для отображения ядра используются старшие 256 элементов каталога.

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

www.books-shop.com Принципы управления памятью • Физическая Виртуальное адресное га пространство Каталог таблиц ядра страниц ОхСООООООО Виртуальное адресное пространство процесса 0x Рис. 3.8. Адресное пространство в режимах ядра и задачи При переключении между процессами, однако, изменяется адресное про странство режима задачи, что вызывает необходимость изменения остав шихся 768 элементов каталога. В совокупности они отображают 3 Гбайт виртуального адресного пространства процесса в режиме задачи. Таким образом, при смене процесса адресное пространство нового процесса ста новится видимым (отображаемым), в то время как адресное пространство предыдущего процесса является Формат виртуальной памяти процесса в режиме задачи зависит, в первую очередь, от типа исполняемого файла, образом которого является процесс.

На рис. 3.9 изображено расположение различных сегментов процесса в виртуальной памяти для двух уже рассмотренных нами форматов испол няемых файлов — COFF и ELF. Заметим, что независимо от формата ис полняемого файла виртуальные адреса процесса не могут выходить за пре делы 3 Гбайт.

Для защиты виртуальной памяти процесса от модификации другими про цессами прикладные задачи не могут менять заданное отображение. По При этом физические страницы, принадлежащие предыдущему процессу, могут по прежнему оставаться в однако доступ к ним невозможен отсутствия новленного отображения. Любой допустимый виртуальный адрес будет отображаться либо в страницы ядра, либо в страницы нового процесса.

www.books-shop.com Глава 3.

управления процессами скольку ядро системы выполняется на привилегированном уровне, оно может управлять отображением как собственного адресного пространства, так и адресного пространства процесса.

COFF ELF Рис. 3.9. Виртуальная память процесса в режиме задачи Управление памятью процесса Можно сказать, что каждый процесс в операционной системе UNIX вы полняется на собственной виртуальной вычислительной машине, где все ресурсы принадлежат исключительно данному процессу. Подсистема управления памятью обеспечивает такую иллюзию в отношении физиче ской памяти.

Как уже говорилось, аппаратная поддержка страничного механизма имеет существенное значение для реализации виртуальной памяти. Однако при этом также требуется участие операционной системы. Можно перечислить ряд операций, за выполнение которых отвечает сама операционная система:

Размещение в памяти каталога страниц и таблиц страниц;

инициа лизация регистра — указателя на каталог таблиц страниц (для Intel — CR3) (в системах, использующих несколько каталогов страниц, каждый процесс хранит в значение этого регистра;

в этом слу чае инициализацию указателя необходимо проводить при каждом переключении контекста);

инициализация каталога страниц.

www.books-shop.com Управление памятью процесса Установка отображения путем записи соответствующих значений в таблицы страниц.

П Обработка страничных ошибок.

П Управление сверхоперативным кэшем.

П Обеспечение обмена страницами между оперативной и вторичной памятью.

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

Области В SCO UNIX адресное пространство процесса разделено на несколько участков, называемых областями (region). Область представляет собой не прерывный участок виртуального адресного пространства процесса, кото рый рассматривается ядром системы как отдельный объект, разделяемый или защищенный от постороннего доступа. Область может использоваться для хранения данных различных типов, включая код, данные, разделяемую память, сегменты библиотек и отображаемые в память файлы. Каждая ак тивная область представлена соответствующей структурой данных ядра и служит основой для управления памятью процесса.

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

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

Поскольку одна и та же область может использоваться несколькими про цессами, для каждого процесса ядро создает связанный список структур pregion (per process region), которые в свою очередь адресуют области, используемые процессом. Указатель на список структур pregion для каж дого процесса находится в записи таблицы процессов — структуре Основные поля структур region и pregion приведены на рис. 3.10.

www.books-shop.com 208 Глава 3. Подсистема управления процессами Виртуальная память процесса Страница физической памяти Рис. 3.10. Управление адресным пространством процесса в SCO UNIX Помимо указателей p_next, организующих структуры pregion в виде связанного списка, и p_reg, обеспечивающих адресацию соответствующей структуры region, в каждой структуре pregion определен набор флагов определяющий права доступа к области, режим блокирования в памяти и т. д. Поле p_type указывает на тип области. Оно может содер жать одно из следующих значений:

Значение Описание РТ UNUSED Область не используется РТ TEXT Область содержит сегмент кода РТ DATA Область содержит сегмент данных РТ STACK Область используется в качестве стека процесса РТ SHMEM Область используется в качестве разделяемой памяти www.books-shop.com Управление памятью процесса (продолжение) Значение Описание Область содержит код библиотек PT_LIBDAT Область содержит данные библиотек PT_SHFIL Область используется для хранения файла, отображенного в память Наконец, поле задает виртуальный адрес области в адресном пространстве процесса.

Поля структуры region, приведенные на рис. ЗЛО, имеют следующие зна чения. Поле определяет размер области в страницах, из которых r_nvalid страниц присутствуют в оперативной памяти (см. далее раздел "Страничное замещение"). Несколько процессов могут ссылаться на одну и ту же область, поле r_refcnt хранит число таких ссылок. Поле адресует таблицу страниц Поле адресует файла, где располагаются данные области (например, для области кода, будет указывать на inode исполняемого файла).

Фактическую информацию о структурах управления адресным пространст вом процесса можно получить с помощью команды В следую щем примере таким образом определяется содержимое структур pregion процесса и характеристики соответствующих областей.

t crash = namelist = /unix, outfile = stdout > pregion SLOT PREG REGVA TYPE G REGVA TYPE FLAGS 101 0 12 0x700000 text rdonly 0 12 0x700000 text 1 22 0x701000 data 2 23 stack 3 145 0x80001000 rdonly 4 187 0x80031000 pr Как можно увидеть из вывода команды с рассматриваемым процессом связаны пять областей: сегмент кода, данных и а также сегменты кода и данных подключенной библиотеки. Столбец опре деляет запись таблицы областей, где расположена адресуемая каждой pregion область region. Заметим, что значение в столбце лишь от части соответствует полю p_reg структуры pregion, поскольку последнее является указателем, а не индексом таблицы. Столбец REGVA содержит значения виртуальных адресов областей.

Для областей, размер которых превышает 4 одной таблицы страниц недостаточно, и region хранит элементы каталога таблиц страниц в виде связанного списка.

piracy@books-shop.com Глава 3. Подсистема управления процессами С помощью полученной информации мы можем более детально рассмот реть любую из областей процесса. Выведем данные о сегментах кода, дан ных и стека:

>region 12 22 SLOT PGSZ VALID NONE SOFF KEF NSW BACK TYPE FLAGS 12 1 1 1 0 0 11 0 0 15 5 154 stxt done 22 3 1 0 0 0 1 0 0 238 23 154 priv done 23 2 1 1 0 0 1 0 0 135 24 priv stack Столбец PGSZ определяет размер области в страницах, а столбец VALID — число страниц этой области, находящихся в оперативной памяти. Как мож но заметить, для сегментов данных и стека страниц недостаточно, поэтому может возникнуть ситуация, когда процессу потребуется обращение к адре су, в настоящее время отсутствующему в памяти. Заметим также, что стол бец INOX содержит индексы таблиц inode, указывающие на метаданные файлов, откуда было загружено содержимое соответствующих сегментов.

Мы можем взглянуть на дополнительные сведения об этом файле:

INODE TABLE SI ZE = 4 7 SLOT FS RCNT LINK SIZE MODE FLAGS 154 1,42 2 1562 3 1 123 56 8972 755 0 R130 tx Из этой таблицы мы можем определить файловую систему, в которой рас положен файл (MAJ/MIN), а также номер его дискового inode — INUMB.

В данном случае он равен 1562. Выполнив команду мы узнаем имя исполняемого файла, соответствующего исследуемому процессу:

$ ncheck Замещение страниц Ранние версии UNIX работали на компьютерах PDP 11 с 16 разрядной архитектурой и адресным пространством 64 Кбайт. Некоторые модифика ции позволяли использовать отдельные адресные пространства для кода и данных, накладывая тем не менее существенные ограничения на размер адресного пространства процесса. Это привело к разработке различных схем программных оверлеев (overlay), использовавшихся как для прикладных задач, так и для ядра операционной системы. Суть этих методов заключа ется в том, что в неиспользуемые участки адресного пространства процес са записываются другие части программы. Например, после запуска сис темы необходимость в функциях начальной инициализации отпадает и часть памяти, содержащая этот код, может быть использована для хране ния других данных или инструкций операционной системы. Не говоря о значительной сложности такого подхода для разработчиков программного обеспечения, использование этих методов приводило к низкой переноси www.books-shop.com Управление памятью процесса мости программ, поскольку они в значительной степени зависели от кон кретной организации памяти. Порой даже расширение оперативной памя ти требовало внесения модификаций в программное обеспечение.

Механизмы управления памятью сводились к использованию свопинга.

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

Рис. Управление памятью, основанное на свопинге Механизм страничного замещения по требованию был реализован в UNIX в году на новом компьютере имевшем 32 разрядную ар www.books-shop.com 212 Глава 3. управления процессами 4 Гбайт адресуемого пространства и аппаратную поддержку страничного механизма. Первой системой UNIX, в которой управление памятью основывалось на страничном замещении по требованию, явилась версия Уже в середине 80 х годов все основные версии UNIX обеспечивали страничное замещение в качестве основного механизма, ос тавляя свопингу вторую роль.

Как уже говорилось в системах с виртуальной памятью, основанной на страничном механизме, адресное пространство процесса разделено на по следовательные участки равной длины, называемыми страницами. Такая же организация присуща и физической памяти, и в конечном итоге любое место физической памяти адресуется номером страницы и смещением в ней. Деление адресного пространства процесса является логическим, при чем логическим последовательным страницам виртуальной памяти при поддержке операционной системы и аппаратуры (MMU процессора) ста вятся в соответствие определенные физические страницы оперативной па мяти. Эта операция получила название трансляции адреса.

Однако механизм трансляции адреса является первым условием реализа ции виртуальной памяти, позволяя отделить виртуальное адресное про странство процесса от физического адресного пространства процессора.

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

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

Вообще говоря, конкретный механизм страничного замещения зависит от того, как реализованы три основных принципа:

1. При каких условиях система загружает страницы в память, т. н. прин цип загрузки (fetch policy).

2. В каких участках памяти система размещает страницы, т. н. принцип размещения (placement policy).

Каким образом система выбирает страницы, которые требуется осво бодить из памяти, когда отсутствуют свободные страницы для разме щения (или их число меньше некоторого порогового значения), т. н.

принцип замещения (replacement policy).

Обычно все физические страницы одинаково подходят для размещения, и принцип размещения не оказывает существенного влияния на работу ме ханизма в целом. Таким образом эффективность управления памятью пол www.books-shop.com Управление памятью процесса ностью зависит от двух остальных принципов: загрузки и замещения. В системах с чистым страничным замещением по требованию в память по мещаются только требуемые страницы, а замещение производится, когда полностью отсутствует свободная оперативная память. Соответственно, производительность таких систем полностью зависит от реализации прин ципа замещения. Однако большинство современных версий UNIX не ис пользуют чистого страничного замещения по требованию. Вместо этого принцип загрузки предполагает размещение сразу нескольких обращение к которым наиболее вероятно в ближайшее время, а замещение производится до того, как память будет полностью занята.

Процесс 1 Физическая память Физическая страница Виртуальная страница Процесс Рис. 3.12. Управление памятью, основанное на страничном замещении по требованию Описанный механизм управления памятью допускает ситуацию, когда суммарный размер всех выполняющихся в данный момент процессов пре вышает размер физической памяти, в которой располагается только часть страниц процессов. Содержимое остальных страниц хранится вне физиче ской памяти и должно быть загружено ядром, если процессу требуется доступ к этой части адресного пространства. Однако виртуальное адресное пространство процесса не зависит от фактического расположения физиче ских страниц, и его размещение производится ядром при создании про цесса или запуске новой программы. Виртуальное адресное пространство может изменяться в результате динамического размещения памяти (хипа) или увеличения стека процесса.

Таким образом, сам процесс "видит" только собственное виртуальное ад ресное пространство. Однако физические страницы, соответствующие www.books-shop.com процессами 214 Глава 3.

этому адресному пространству могут в действительности располагаться в различных местах, как это показано на рис. 3.13.

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

2. Страница может быть перемещена в область свопинга, если требуется освободить память для другого процесса. Обращение к виртуальному адресу, соответствующему этой странице, приведет к страничной ошибке, что, в свою очередь, потребует от ядра размещения новой страницы в памяти, записи ее содержимого из области свопинга и со ответствующего изменения карты отображения (записи таблицы стра ниц) таким образом, чтобы виртуальный адрес указывал на новую страницу. Если потребуется опять переместить такую страницу в об www.books-shop.com Управление памятью процесса свопинга, ядро сделает это только в том случае, если с момента последней загрузки произошла модификация страницы.

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

4. Адресуемая страница отсутствует в памяти и она не ассоциирована ни с областью свопинга, ни с файлом. Типичным примером такой ситуа ции является страница сегмента неинициализированных данных. Об ращение к такой странице потребует размещения новой страницы, за полненной нулями.

Ядро должно иметь достаточную информацию обо всех страницах, отсутст вующих в памяти для того, чтобы при необходимости загрузить их в память.

Для страниц, перемещенных во вторичную память, необходимо знать их расположение в области свопинга. Ядро должно иметь возможность распо знать, что страницу необходимо заполнить нулями или загрузить ее содер жимое из файла. В последнем случае ядро должно хранить местонахождение файла в файловой системе. Таким образом, наряду с картами необходимыми для трансляции адреса, ядро хранит ряд структур данных для поиска и загрузки отсутствующих в памяти страниц.

Различные версии UNIX используют разные подходы. Например, в SCO UNIX для описания страниц используются структуры pfdat и связанные с ними дескрипторы дисковых блоков. В UNIX для этого исполь зуются поля записи таблицы страниц.

Страничное замещение имеет ряд важных преимуществ по сравнению со свопингом:

Размер программы ограничивается лишь размером виртуальной па мяти, который для компьютеров с 32 разрядной архитектурой со ставляет 4 Гбайт.

СИ Запуск программы происходит очень быстро, т. к. не требуется за гружать в память всю программу целиком.

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

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

www.books-shop.com 216 Глава 3. управления процессами Планирование выполнения процессов Как и оперативная память, процессор является разделяемым ресурсом, ко торый должен быть справедливо распределен между конкурирующими процессами. Планировщик процессов как раз и является той подсистемой ядра, которая обеспечивает предоставление процессорных ресурсов про цессам, выполняющимся в операционной системе. UNIX является систе мой разделения времени, это означает, что каждому процессу вычисли тельные ресурсы выделяются на ограниченный промежуток времени, по сле чего они предоставляются другому процессу и т. д. Максимальный временной интервал, на который процесс может захватить процессор, на зывается временным квантом (time quantum или time slice). Таким образом создается иллюзия, что процессы выполняются одновременно, хотя в дей ствительности в каждый момент времени выполняется только один (на однопроцессорной системе) процесс.

UNIX является многозадачной системой, а это значит, что одновременно выполняются несколько приложений. Очевидно, что приложения предъ являют различные требования к системе с точки зрения их планирования и общей производительности. Можно выделить три основных класса при ложений:

Интерактивные приложения. К этому классу относятся командные интерпретаторы, текстовые редакторы и другие программы, непо средственно взаимодействующие с пользователем. Такие приложения большую часть времени обычно проводят в ожидании пользователь ского ввода, например, нажатия клавиш клавиатуры или действия мышью. Однако они должны достаточно быстро обрабатывать такие действия, обеспечивая комфортное для пользователя время реакции.

Допустимая задержка для таких приложений составляет от 100 до миллисекунд.

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

О Приложения реального времени. Хотя система UNIX изначально раз рабатывалась как операционная система разделения времени, ряд приложений требуют дополнительных системных возможностей, в частности, гарантированного времени совершения той или иной операции, времени отклика и т. п. Примером могут служить измери тельные комплексы или системы управления. Видеоприложения www.books-shop.com Планирование выполнения процессов также могут обладать определенными ограничениями на время обра ботки кадра изображения.

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

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

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

Большинство систем хранят это значение в константе HZ, которая опреде лена в файле заголовков . Например, для тика в 10 миллисекунд значение HZ устанавливается равным 100.

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

Обновление статистики использования процессора для текущего процесса П Выполнение ряда функций, связанных с планированием процессов, например пересчет приоритетов и проверку истечения временного кванта для процесса Проверка превышения процессорной квоты для данного процесса и отправка этому процессу сигнала в случае превышения www.books-shop.com Глава 3. управления процессами П Обновление системного времени (времени дня) и других связанных с ним таймеров П Обработка отложенных вызовов П Обработка (alarm) П Пробуждение в случае необходимости системных процессов, напри мер диспетчера страниц и свопера Часть задач не требует выполнения на каждом тике. Боль шинство систем вводят нотацию главного тика (major tick), который про исходит каждые тиков, где зависит от конкретной версии системы.

Определенный набор функций выполняется только на главных тиках. На пример, производит пересчет приоритетов каждые 4 тика, a SVR обрабатывает и производит пробуждение системных процессов раз в секунду.

Отложенные вызовы вызов определяет функцию, вызов которой будет произведен ядром системы через некоторое время. Например, в SVR4 любая подсис тема ядра может зарегистрировать отложенный вызов следующим образом:

int co_ID = arg, long где f n определяет адрес функции, которую необходимо вызвать, при этом ей будет передан аргумент arg, а сам вызов будет произведен через delta ТИКОВ.

Ядро производит вызов f n в системном контексте, таким образом функция отложенного вызова не должна обращаться к адресному про странству текущего процесса (поскольку не имеет к нему отношения), а также не должна переходить в состояние сна.

Отложенные вызовы применяются для выполнения многих функций, на пример:

Выполнение ряда функций планировщика и подсистемы управления памятью П Выполнение ряда функций драйверов устройств для событий, веро ятность ненаступления которых относительно велика. Примером может служить модуль протокола TCP, реализующий таким образом повторную передачу сетевых пакетов по тайм ауту Опрос устройств, не поддерживающих прерывания Заметим, что функции отложенных вызовов выполняются в системном контексте, а не в контексте прерывания. Вызов этих функций выполняется не обработчиком прерывания таймера, а отдельным обработчиком отло женных вызовов, который запускается после обработки прс www.books-shop.com Планирование выполнения процессов таймера. При обработке прерывания таймера система проверяет необходимость запуска тех или иных функций отложенного вызова и уста навливает соответствующий флаг для них. В свою очередь обработчик от ложенных вызовов проверяет флаги и запускает необходимые в системном контексте.

Эти функции хранятся в системной таблице отложенных вызовов, органи зация которой отличается для различных версий UNIX. Поскольку про смотр этой таблицы осуществляется каждый тик при обработке высоко приоритетного прерывания, для минимизации влияния этой операции на функционирование системы в целом, организация этой таблицы должна обеспечивать быстрый поиск нужных функций. Например, в и SCO UNIX таблица отложенных вызовов организована в виде списка, от сортированного по времени запуска. Каждый элемент хранит разницу ме жду временем вызова функции и временем вызова функции предыдущего элемента таблицы. На каждом тике значение этой величины уменьшается на единицу для первого элемента таблицы. Когда это значение равным 0, производится вызов соответствующей функции и запись удаля ется. На рис. 3.14 приведена схема организации этой таблицы.

Рис. 3.14. Организация таблицы отложенных вызовов Процесс может запросить ядро отправить сигнал по прошествии опреде ленного интервала времени. Существуют три типа алармов — реального (real time), профилирования (profiling) и виртуального (virtual time). С каждым из этих типов связан таймер интервала timer, или Значение уменьшается на единицу при каждом тике. Когда значение itimer достигает нуля, процессу отправляется соот сигнал.

piracy@books-shop.com 220 Глава 3. управления процессами Указанные таймеры обладают следующими характеристиками:

ITIMER_REAL Этот таймер используется для отсчета реального времени.

Когда значение таймера становится равным нулю, процессу отправляется сигнал ITIMER_PROF Этот таймер уменьшается только когда процесс выполняется в режиме ядра или задачи. Когда значение таймера становится равным нулю, процессу отправляется сигнал Этот таймер уменьшается только когда процесс выполняется в режиме задачи. Когда значение таймера становится равным нулю, процессу отправляется сигнал В версиях BSD UNIX для установки таймеров всех трех типов использует ся системный вызов settimer(2), для которого значение таймера устанавли вается в Ядро системы преобразует это значение в тики, на основании которых и производится уменьшение таймера. Напомним, что тик является максимальным временным разрешением, которое может обеспечить система. В версиях System V для установки таймера реального времени используется вызов позволяющий указать интервал в секундах. UNIX SVR4 позволяет установить таймеры высокого разрешения с помощью системного вызова для которого время указывается в микросекундах. С помощью этого вызова также достигается совместимость с BSD, которая обеспечивается библиотечной функцией Ана логично, в BSD UNIX вызов реализован в виде библиотечной функции.

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

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

Два других типа таймера обладают более высокой точностью, поскольку не имеют отношения к реальному течению времени. Однако их точность для малых временных интервалов может определяться следующим фактором.

системы System V, например SCO UNIX, также имеют в своем распоряжении этот системный вызов.

www.books-shop.com Планирование выполнения процессов При обработке таймера процессу засчитывается тик целиком, даже если, предположим, процесс выполнялся лишь часть тика. Для временных ин тервалов порядка тика это может внести значительную погрешность.

Контекст процесса Каждый процесс UNIX имеет контекст, под которым понимается вся ин формация, требуемая для описания процесса. Эта информация сохраняет ся, когда выполнение процесса простанавливается, и восстанавливается, когда планировщик предоставляет процессу вычислительные ресурсы.

Контекст процесса состоит из нескольких частей:

Адресное пространство процесса в режиме задачи. Сюда входят код, данные и стек процесса, а также другие области, например, разде ляемая память или код и данные динамических библиотек.

Управляющая информация. Ядро использует две основные структуры данных для управления процессом — и user. Сюда же входят данные, необходимые для отображения виртуального адресного про странства процесса в физическое.

Окружение процесса. Переменные окружения процесса представляют собой строки пар вида:

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

Аппаратный контекст. Сюда входят значения общих и ряда систем ных регистров процессора. К системным регистрам, в частности, от носятся:

• указатель инструкций, содержащий адрес следующей инструк ции, которую необходимо выполнить;

• указатель стека, содержащий адрес последнего элемента стека;

• регистры плавающей точки;

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

Переключение между процессами, необходимое для справедливого рас пределения вычислительного ресурса, по существу выражается в переклю чении контекста, когда контекст выполнявшегося процесса запоминается, и восстанавливается контекст процесса, выбранного планировщиком. Пе реключение контекста является достаточно ресурсоемкой операцией. По мимо сохранения состояния регистров процесса, ядро вынуждено выпол нить множество других действий. Например, для систем ядру www.books-shop.com Глава 3. управления процессами необходимо очистить кэш данных, инструкций или адресных трансляций, чтобы предотвратить некорректные обращения нового процесса. Поэтому запущенный процесс сначала вынужден работать по существу без кэша, что также сказывается на производительности.

Существуют четыре ситуации, при которых производится переключение контекста:

1. Текущий процесс переходит в состояние сна, ожидая недоступного ре сурса.

2. Текущий процесс завершает свое выполнение.

После пересчета приоритетов в очереди на выполнение находится бо лее высокоприоритетный процесс.

4. Происходит пробуждение более высокоприоритетного процесса.

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

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

Планирование процессов в UNIX основано на приоритете процесса. Пла нировщик всегда выбирает процесс с наивысшим приоритетом. Приоритет процесса не является фиксированным и динамически изменяется систе мой в зависимости от использования вычислительных ресурсов, времени ожидания запуска и текущего состояния процесса. Если процесс готов к www.books-shop.com Планирование выполнения процессов запуску и имеет наивысший приоритет, планировщик приостановит полнение текущего процесса (с более низким приоритетом), даже если последний не "выработал" свой временной квант.

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

В противном случае система может прервать выполнение процесса только при переходе из режима ядра в режим задачи. Такой подход значительно упрощает решение задач синхронизации и поддержания целостности структур данных ядра.

Каждый процесс имеет два атрибута приоритета: на основании которого происходит планирование, и заказанный ный приоритет, называемый nice number (или просто nice), который зада ется при порождении процесса и влияет на текущий приоритет.

Текущий приоритет варьируется в диапазоне от 0 (низкий приоритет) до 127 (наивысший приоритет). Процессы, в режиме задачи, имеют более низкий приоритет, чем в режиме ядра. Для режима задачи приоритет меняется в диапазоне для режима ядра — (систем ный диапазон).

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

В табл. 3.3 приведены значения приоритетов сна для систем U N I X и SCO UNIX 5.0). Заметим, что направление роста значений приоритета для этих систем различно — в BSD UNIX большему значению соответствует более низкий приоритет.

Схема нумерации приоритетов различна для различных версий UNIX.

более высокому значению текущего приоритета может соответствовать тический приоритет планирования.

между приоритетами режима ядра и задачи также зависит от версии. Здесь мы привели в SCO UNIX, кото рой большему значению высокий www.books-shop.com 224 Глава 3. управления процессами Таблица 3.3. Системные приоритеты сна Приоритет Приоритет 4.3BSD UNIX SCO UNIX Ожидание загрузки в память сегмен 0 (свопинг/страничное замещение) Ожидание индексного дескриптора 10 Ожидание 20 Ожидание буфера 30 Ожидание терминального ввода Ожидание терминального вывода Ожидание завершения выполнения Ожидание события — низкоприоритетное со 40 стояние сна Когда процесс пробуждается, ядро устанавливает значение текущего при оритета процесса равным приоритету сна. Поскольку приоритет такого процесса находится в системном диапазоне и выше, чем приоритет режи ма задачи, вероятность предоставления процессу вычислительных ресурсов весьма велика. Такой подход позволяет, в частности, быстро завершить системный вызов, выполнение которого, в свою очередь, может блокиро вать некоторые системные ресурсы.

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

Текущий приоритет процесса в режиме задачи зависит от двух факторов: значения nice number и степени использования вычислительных ресурсов p_priuser a*p_nice где — постоянная составляющая, зависящая от параметра Задача планировщика разделения времени — справедливо распределить вычислительный ресурс между конкурирующими процессами. Для приня тия решения о выборе следующего запускаемого процесса планировщику необходима информация об использовании процессора. Эта составляющая Мы специально не выделили явно параметр nice по следующей причине. Традиционно, большему значению параметра nice соответствует меньший это уже обсужда лось в главе 1. В данном обсуждении выбрана схема, при которой большему значению р_сри соответствует больший приоритет. Поэтому в простейшем случае коэффициент а является отрицательным, a p_nice равно значению параметра nice (nice number).

www.books-shop.com Планирование выполнения процессов приоритета уменьшается обработчиком прерываний таймера каждый тик.

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

Каждую секунду ядро пересчитывает текущие приоритеты процессов, го товых к запуску (приоритеты которых меньше 65), последовательно увели чивая Это перемещает процессы в более приоритетные очереди и по вышает вероятность их последующего запуска.

Например, UNIX версии SVR3, использует следующую формулу:

p_cpu Эта простая схема проявляет недостаток нивелирования приоритетов при повышении загрузки системы. Это происходит потому, что в этом случае каждый процесс получает незначительный объем вычислительных ресур сов и следовательно имеет малую составляющую которая еще более уменьшается благодаря формуле пересчета р_сри. В результате степень использования процессора перестает оказывать заметное влияние на при оритет, и низкоприоритетные процессы (т. е. процессы с высоким nice number) практически "отлучаются" от вычислительных ресурсов системы.

В 4.3BSD UNIX для пересчета используется другая формула:

= Здесь параметр load равен среднему числу процессов, находившихся в очереди на выполнение за последнюю секунду, и характеризует среднюю загрузку системы за этот период времени. Этот алгоритм позволяет час тично избавиться от недостатка планирования SVR3, поскольку при зна чительной загрузке системы уменьшение р_сри при пересчете будет про исходить медленнее.

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

Ядро последовательно уменьшает отрицательную компоненту времени использования процессора.

www.books-shop.com Глава 3. управления процессами Как правило, очередь на выполнение не одна. Например, SCO UNIX име ет 127 очередей — по одной на каждый приоритет. BSD UNIX использует 32 очереди, каждая из которых обслуживает диапазон приоритетов, на пример и т. д. При выборе следующего процесса на выполнение из одной очереди, т. е. из нескольких процессов с одинаковым текущим приоритетом, используется механизм кругового чередования (round Этот механизм запускается ядром через каждый временной квант для наи более приоритетной очереди. Однако если в системе появляется готовый к запуску процесс с более высоким приоритетом, чем текущий, он будет за пущен, не дожидаясь прошествия временного кванта. С другой стороны, если все процессы, готовые к запуску, находятся в низкоприоритетных по отношению к текущему процессу очередях, последний будет продолжать выполняться и в течение следующего временного кванта.

Создание процесса Как уже обсуждалось, в UNIX проведена четкая грань между программой и процессом. Каждый процесс в конкретный момент времени выполняет ин струкции некоторой программы, которая может быть одной и той же для нескольких Примером может служить командный интерпре татор, с которым одновременно работают несколько пользователей, таким образом инструкции программы shell выполняют несколько различных процессов. Такие процессы могут совместно использовать один сегмент кода в памяти, но в остальном они являются изолированными друг от друга и имеют собственные сегменты данных и стека.

В любой момент процесс может запустить другую программу и начать вы полнять ее инструкции;

такую операцию он может сделать несколько раз.

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

не менее между родительским и дочерним процессом имеется ряд различий:

Дочернему процессу присваивается уникальный идентификатор PID, отличный от родительского.

Round robin означает петицию, подписи под которой располагаются по кругу — чтобы нельзя было определить, кто подписался первым. Отсюда и схемы выбора процессов.

здесь идет о в в ядра вы полняет инструкции ядра системы.

www.books-shop.com Создание процесса Соответственно и идентификатор родительского процесса для родителя и потомка различны.

О Дочерний процесс получает собственную копию и, в частно сти, собственные файловые дескрипторы, хотя он разделяет те же записи файловой таблицы.

Для дочернего процесса очищаются все ожидающие доставки сигналы.

Временная статистика выполнения процесса в режиме ядра и задачи для дочернего процесса обнуляется.

Блокировки памяти и записей, установленные родительским процес сом, потомком не наследуются.

Более подробно наследуемые характеристики представлены в табл. 3.4.

Таблица 3.4, Наследование установок при создании процесса и запуске программы Атрибут Наследование по Сохранение при запус программы Сегмент кода (text) Да, разделяемый Нет Сегмент данных (data) Да, копируется при Нет записи (copy on write) Окружение Возможно Да Аргументы Возможно Да Идентификатор пользова Да Да теля UID Идентификатор группы GID Да Да Эффективный идентифика Да Да тор пользователя EUID (Нет, при вызове Эффективный идентифика Да Да тор группы EGID (Нет, при вызове процесса (PID) Нет Да ID группы процессов Да Да ID родительского процесса Нет Да (PPID) Приоритет nice number Да Да Права доступа к создавае Да Да мому файлу Ограничение на размер Да Да файла Сигналы, обрабатываемые Да Да по умолчанию Игнорируемые сигналы Да Да www.books-shop.com управления процессами 228 Глава 3.

Таблица 3.4 (продолжение) Атрибут Наследование по Сохранение при томком ке программы Перехватываемые сигналы Да Нет Файловые дескрипторы Да, если для файлового де Да скриптора не установлен флаг FD_CLOEXEC (например, с помощью Файловые указатели Да, разделяемые Да, если для файлового де скриптора не установлен флаг FD_CLOEXEC (например, с помощью В общем случае выполняет следующие действия:

П Резервирует место в области свопинга для сегмента данных и стека процесса.

П Размещает новую запись в таблице процессов и присваивает процессу уникальный идентификатор PID.

П Инициализирует структуру (поля структуры подробно рассматривались в разделе "Структуры данных процесса").

П Размещает карты отображения, необходимые для трансляции адреса.

Размещает процесса и копирует ее содержимое с родитель ского.

П Создает соответствующие области процесса, часть из которых совпа дает с родительскими.

Инициализирует аппаратный контекст процесса, копируя его с ро дительского.

Устанавливает в ноль возвращаемое дочернему процессу вызовом fork(2) значение.

П Устанавливает возвращаемое родительскому процессу вызовом fork(2) значение равным PID потомка.

П Помечает процесс готовым к запуску и помещает его в очередь на выполнение.

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

www.books-shop.com Создание процесса Для решения данной проблемы используются два подхода. Первый из них, предложенный в UNIX System V, называется "копирование при записи" или COW). Суть этого подхода заключается в том, что сег менты данных и стека родительского процесса помечаются доступными только для чтения, а дочерний процесс, хотя и получает собственные кар ты отображения, разделяет эти сегменты с родительским. Другими слова ми, сразу после создания процесса и родитель и потомок адресуют одни и те же страницы физической памяти. Если какой либо из двух процессов попытается модифицировать данные или стек, возникнет страничная ошибка, поскольку страница открыта только для чтения, а не для записи.

При этом будет запущен обработчик ошибки ядра, который создаст для процесса копию этой страницы, доступную для записи. Таким образом, фактическому копированию подлежат только модифицируемые страницы, а не все адресное пространство процесса. Если дочерний процесс делает системный вызов ехес(2) или вообще завершает свое выполнение, права доступа к страницам родителя, имеющим флаг COW, возвращаются к их прежним значениям (т. е. до создания дочернего процесса), а флаг COW очищается.

Другой подход используется в BSD UNIX. В этой версии системы был пред ложен новый системный вызов — vfork(2). Использование этого вызова име ет смысл, когда дочерний процесс сразу же выполняет вызов ехес(2) и за пускает новую программу. При вызове vfork(2) родительский процесс пре доставляет свое адресное пространство дочернему и переходит в состояние сна, пока последний не вернет его обратно. Далее дочерний процесс выпол няется в адресном пространстве родителя, пока не делает вызов ехес(2) или exit(2), после чего ядро возвращает адресное пространство родителю и про буждает его. С помощью vfork(2) можно добиться максимального быстродей ствия, т. к. в этом случае мы полностью избегаем копирования, даже для карт отображения. Вместо этого адресное пространство родительского про цесса предоставляется потомку передачей нескольких аппаратных регистров, отвечающих за трансляцию адресов. Однако vfork(2) таит в себе потенциаль ную опасность, поскольку позволяет одному процессу использовать и даже модифицировать адресное пространство другого.

Для управления памятью процесса ядру необходимо соответствующим об разом задать области. При этом структуры pregion дочернего процесса, соответствующие разделяемым областям, указывают на те же структуры region, что и для родителя. Для областей, совместное использование ко торых недопустимо, ядро размещает отдельные структуры region для до чернего процесса (изначально копируя их содержимое с родительского) и устанавливает соответствующие указатели. На рис. 3.15 представлена схема этих операций. Заметим, что совместная работа и дублирование областей являются отдельным механизмом, не связанным с рассмотренными выше подходами, для совместного использования адресного пространства, на пример COW. Так, после создания отдельной копии облас piracy@books-shop.com управления процессами 230 Глава 3, ти она по прежнему будет адресовать те же страницы памяти, что и соот ветствующая область родителя.

Рис. 3.15. Создание областей нового процесса Запуск новой программы Запуск новой программы осуществляется с помощью системного вызова Напомним, что при этом создается не новый процесс, а новое ад ресное пространство процесса, которое загружается содержимым новой программы. Если процесс был создан вызовом старое адресное пространство возвращается родителю, в противном случае оно просто уничтожается. После возврата из вызова ехес(2) процесс продолжает вы полнение кода новой программы.

Операционная система UNIX обычно поддерживает несколько форматов исполняемых файлов. Старейший из них — в разделе "Форматы ис полняемых файлов" главы 2 также были рассмотрены форматы COFF и ELF. В любом случае исполняемый файл содержит заголовок, позволяю щий ядру правильно разместить адресное пространство процесса и загру в него соответствующие фрагменты исполняемого файла.

www.books-shop.com Запуск новой программы Перечислим ряд действий, которые выполняет ехес(2) для запуска новой программы:

Производит трансляцию имени файла. В результате возвращается индексный дескриптор, с помощью которого осуществляется доступ к файлу. При этом проверяются права доступа.

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

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

Резервирует место в области свопинга для сегмента данных и стека.

Освобождает старые области процесса и соответствующие области свопинга. Если процесс был создан вызовом vfork(2), старое адресное пространство возвращается родителю.

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

Поскольку управление памятью процесса построено на механизме страничного по требованию, копирование происходит постранично и только тогда, когда процесс обращается к страницам, отсутствующим в памяти.

Копирует сохраненные аргументы и переменные окружения в новый стек процесса.

Устанавливает обработку всех сигналов на умалчиваемые значения, поскольку процесс теперь не имеет требуемых обработчиков. Установ ки для игнорируемых и заблокированных сигналов не изменяются.

Напомним, что этом случае EUID и EGID не наследуются от родительского процесса, а присваиваются равными идентификаторам и GID исполняемого файла.

www.books-shop.com управления процессами 232 Глава 3.

Инициализирует аппаратный контекст процесса. В частности, после этого указатель инструкций адресует точку входа новой программы.

В случае, когда программа использует динамические библиотеки, соответ ствующий раздел исполняемого файла (для файла формата ELF данный раздел имеет тип INTERP) содержит имя редактора связей динамической библиотеки. В этом случае редактор связей должен быть запущен до нача ла выполнения основной программы для связывания с программами тре буемых динамических библиотек. Таким образом точка входа в программу устанавливается на точку входа в редактор связей. После завершения своей работы редактор связей, в свою очередь, запускает программу самостоя тельно, анализируя заголовок исполняемого файла. Стадии запуска новой программы проиллюстрированы на рис. 3.16.

Рис. 3.16. Запуск новой программы: а) Адресное пространство процесса до вызова б) Уничтожение старого адресного пространства;

в) Новое адресное простран ство процесса;

г) Новое адресное пространство процесса при использовании динами ческих библиотек www.books-shop.com Выполнение режиме Выполнение в режиме ядра Существуют всего три события, при которых выполнение процесса пере ходит в режим ядра — аппаратные прерывания, особые ситуации и сис темные вызовы. Во всех случаях ядро UNIX получает управление и вызы вает соответствующую системную процедуру для обработки события. Пе ред вызовом ядро сохраняет состояние прерванного процесса в системном стеке. После завершения обработки, состояние процесса восстанавливает ся и процесс возвращается в исходный режим выполнения. Чаще всего это режим задачи, но если, например, прерывание возникло, когда процесс уже находился в режиме ядра, после обработки события он останется в этом режиме.

Отметим существенную разницу между прерываниями и особыми ситуа циями. Аппаратные прерывания генерируются периферийными устройст вами при наступлении определенных событий (например, завершение дисковой операции ввода/вывода или поступление данных на последова тельный порт) и имеют асинхронный характер, поскольку невозможно точно сказать, в какой момент наступит то или иное прерывание. Более того, эти прерывания, как правило, не связаны с текущим процессом, а вызваны внешними событиями. Именно поэтому, обработка прерываний происходит в системном контексте, при этом недопустим доступ к адрес ному пространству процесса, например, к его u area. По этой же причине, обработка прерываний не должна блокироваться, поскольку это вызовет блокирование выполнения независимого процесса.

Напротив, особые ситуации вызваны самим процессом, и связаны с вы полнением тех или иных инструкций, например, деление на ноль или об ращение к несуществующей странице памяти. Таким образом, обработка особых ситуаций производится в контексте процесса, при этом может ис пользоваться его адресное пространство, а сам процесс — при необходи мости блокироваться (перемещаться в состояние сна).

Системные вызовы позволяют процессам воспользоваться базовыми услу гами ядра. Интерфейс системных вызовов определяет ограниченный набор точек входа в ядро системы, обращение к которым изменяет режим вы полнения процесса и позволяет выполнять привилегированные инструк ции ядра. Стандартная библиотека С, позволяющая использовать систем ные функции как обычные процедуры, на самом деле содержит заглушки, обеспечивающие фактическую реализацию вызова соответствующей точки входа ядра. Эта реализация существенным образом зависит от аппаратной архитектуры системы. Например, для систем на базе процессоров Intel ис пользуются шлюзы (gate). Имеются два типа шлюзов: шлюзы ловушек (trap gate) и шлюзы вызовов (call gate). Для осуществления вызова через шлюз ловушки процесс выполняет команду прерывания, а при работе шлюз вызова — команду межсегментного вызова.

www.books-shop.com 234 Глава 3. процессами Выполнение системного вызова происходит в режиме ядра, но в контексте процесса, сделавшего системный вызов. Таким образом, открыт доступ к адресному пространству процесса и используется стек ядра процесса.

Сон и пробуждение Процесс обычно переводится в состояние сна при обработке системной функции. Если для завершения обработки запроса требуется недоступный ресурс, процесс снимается с процессора и переводится в состояние сна.

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

Состояние сна — это логическое состояние процесса, при этом он не пе ремещается физически в памяти. Переход в состояние сна в первую оче редь определяется занесением в системную таблицу процессов соответст вующего флага состояния и события, пробуждающего процесс.

События возвещают о доступности того или иного ресурса. Как правило события связаны с работой периферийных устройств, таких как диск, тер минал и принтер, поэтому об их наступлении сигнализируют соответст вующие аппаратные прерывания. Наступления одного и того же события может ожидать несколько процессов. Поскольку переход из состояния в состояние акт скорее логический, то и пробуждаются все эти процессы одновременно. Однако это не означает, что какой либо один из них сразу начнет выполняться. Это лишь приводит к тому, что их состояние меняет ся от "сна" к "готов к выполнению", и они помещаются в очередь на за пуск. Задачу выбора процесса для запуска затем решает планировщик про цессов.

События, в ожидании которых "засыпают" процессы, не являются равно ценными.

Во первых, они различаются по вероятности наступления. Например со бытие, связанное с завершением операции ввода с диска или освобожде нием буфера, имеет высокую вероятность. Как правило, подобные опера ции имеют конечное время выполнения, в противном случае система ока www.books-shop.com Завершение выполнения процесса залась бы заблокированной. С другой стороны, вероятность наступления события, связанного с вводом с терминала, может быть весьма низкой.

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

Во вторых, процессы, разбуженные событием, должны иметь различную вероятность запуска. Это, в первую очередь, связано с тем, что несколько ресурсов могут отображаться на одно событие. Например, процесс А, ожи дающий завершения операции ввода с диска, и процесс В, ожидающий освобождения буфера ввода, будут связаны с одним и тем же событием.

Они оба окажутся "разбуженными" и затем "готовыми к запуску" после за вершения этой операции. Если процесс В будет запущен первым, он все равно не сможет выполняться, так как буфер не освобожден процессом А.

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

Например, освобождение буфера ввода безусловно предпочтительнее за вершения ввода с терминала.

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

Завершение выполнения процесса Процесс завершает свое выполнение с помощью функции exit Эта функция может быть вызвана системным вызовом а если заверше ние процесса вызвано получением сигнала, функцию вызывает само ядро. Функция exit выполняет следующие действия:

Отключает все сигналы.

Закрывает все открытые файлы.

Сохраняет статистику ресурсов и код возврата в записи таблицы процессов.

www.books-shop.com 236 Глава 3. управления процессами Изменяет состояние процесса на "зомби".

Делает процесс родительским для всех потомков данного процесса.

П Освобождает адресное пространство процесса, u area, карты отобра жения и области свопинга, связанные с процессом.

П Отправляет сигнал родительскому процессу, уведомляя его о "смерти" потомка.

П Пробуждает родительский процесс, если тот ожидает завершения по томка.

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

После завершения выполнения функции exit процесс находится в со стоянии "зомби". При этом от процесса остается запись в таблице процессов, содержащая статистику использования вычислительных ресур сов и код возврата. Эта информация может потребоваться родительскому процессу, поэтому освобождение структуры производит родитель с помощью системного вызова возвращающего статистику и код воз врата потомка. Если родительский процесс заканчивает свое выполнение раньше потомка, "родительские права" переходят к процессу В этом случае после смерти потомка делает системный вызов и освобождает структуру Другая ситуация возникает, если потомок заканчивает свое выполнение раньше родителя, а родительский процесс не производит вызова В этом случае структура потомка не освобождается и процесс продол жает находиться в состоянии "зомби" до перезапуска операционной систе мы. Хотя такой процесс (которого, вообще говоря, не существует) не по требляет ресурсов системы, он занимает место в таблице процессов, тем самым уменьшая максимальное число активных задач.

Сигналы В некотором смысле сигналы обеспечивают простейшую форму межпро цессного взаимодействия, позволяя уведомлять процесс или группу про цессов о наступлении некоторого события. Мы уже рассмотрели в преды дущих главах сигналы с точки зрения пользователя и программиста. Те перь мы остановимся на обслуживании сигналов операционной системой.

Группы и сеансы Группы процессов и сеансы уже обсуждались в главе 2. Такое представле ние набора процессов используется в UNIX для управления доступом к www.books-shop.com Сигналы терминалу и поддержки пользовательских сеансов работы в системе. Пере числим еще раз наиболее важные понятия, связанные с группами и сеан сами.

Группа процессов. Каждый процесс принадлежит определенной груп пе процессов. Каждая группа имеет уникальный идентификатор.

Группа может иметь в своем составе лидера группы — процесс, чей идентификатор PID равен идентификатору группы. Обычно процесс наследует группу от родителя, но может покинуть ее и организовать собственную группу.

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

Специальный файл устройства /dev/tty. Этот файл связан с управ ляющим терминалом процесса. Драйвер для этого псевдоустройства по существу перенаправляет запросы на фактический терминальный драйвер, который может быть различным для различных процессов.

Например, два процесса, принадлежащие различным сеансам, от крывая файл /dev/tty, получат доступ к различным терминалам.

Управление сигналами Сигналы обеспечивают механизм вызова определенной процедуры при наступлении некоторого события. Каждое событие имеет свой идентифи катор и символьную константу. Некоторые из этих событий имеют асин хронный характер, например, когда пользователь нажимает клавишу или + для завершения выполнения процесса, другие являются уведомлением об ошибках и особых ситуациях, например, при попытке доступа к недопустимому адресу или вызовы недопустимой инструкции.

Различные события, соответствующие тем или иным сигналам, подробно рассматривались в главе 2.

Говоря о сигналах необходимо различать две фазы этого механизма — ге нерация или отправление сигнала и его доставка и обработка. Сигнал от правляется, когда происходит определенное событие, о наступлении кото рого должен быть уведомлен процесс. Сигнал считается когда процесс, которому был отправлен сигнал, получает его и выполняет его обработку. В промежутке между этими двумя моментами сигнал ожи дает Отправление сигнала Ядро генерирует и отправляет процессу сигнал в ответ на ряд событий, которые могут быть вызваны самим процессом, другим процессом, преры ванием или какими либо внешними событиями. Можно выделить основ ные причины отправки сигнала:

www.books-shop.com 238 Глава 3. управления процессами Особые ситуации Когда выполнение процесса вызывает особую ситуацию, например, деление на ноль, процесс получает соответствующий сигнал.

Терминальные Нажатие некоторых клавиш терминала, напри прерывания мер, + или +<\>, вызы вает отправление сигнала текущему процессу, связанному с терминалом.

Другие процессы Процесс может отправить сигнал другому про цессу или группе процессов с помощью систем ного вызова kill(2). В этом случае сигналы яв ляются элементарной формой межпроцессного взаимодействия.

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

Квоты Когда процесс превышает выделенную ему кво ту вычислительных ресурсов или ресурсов фай ловой системы, ему отправляется соответст вующий сигнал.

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

Если процесс установил таймер, ему будет от правлен сигнал, когда значение таймера станет равным нулю.

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

www.books-shop.com Сигналы Как уже обсуждалось в главе 2, процесс может изменить действие по умолчанию, либо зарегистрировав собственный обработчик сигнала, либо указав, что сигнал следует игнорировать. Процесс также может заблокиро вать сигнал, отложив на некоторое время его обработку. Это возможно не для всех сигналов. Например, для сигналов и SIGSTOP единст венным действием является действие по умолчанию, эти сигналы нельзя ни перехватить, ни заблокировать, ни игнорировать. Для ряда сигналов, преимущественно связанных с аппаратными ошибками и особыми ситуа циями, обработка, отличная от умалчиваемой, не рекомендуется, так как может привести к непредсказуемым (для процесса) результатам.

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

Доставка сигнала происходит после того, как ядро от имени процесса вы зывает системную процедуру которая проверяет, существуют ли ожидающие доставки сигналы, адресованные данному процессу. Функция issig вызывается ядром в трех случаях:

1. Непосредственно перед возвращением из режима ядра в режим задачи после обработки системного вызова или прерывания.

2. Непосредственно перед переходом процесса в состояние сна с приори тетом, допускающим прерывание сигналом.

3. Сразу же после пробуждения после сна с приоритетом, допускающим прерывание сигналом.

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

Рассмотрим типичные ситуации, связанные с отправлением и доставкой сигналов. Допустим, пользователь, работая за терминалом, нажимает кла прерывания ( или + для большинства систем). На жатие любой клавиши вызывает аппаратное прерывание (например, пре рывание от последовательного порта), а драйвер терминала при обработке этого прерывания определяет, что была нажата специальная клавиша, ге нерирующая сигнал, и отправляет текущему процессу, связанному с тер миналом, сигнал SIGINT. Когда процесс будет выбран планировщиком и piracy@books-shop.com 240 Глава 3. процессами запущен на выполнение, при переходе в режим задачи он обнаружит по ступление сигнала и обработает его. Если же в момент генерации сигнала терминальным драйвером процесс, которому был адресован сигнал, уже выполнялся (т. е. был прерван обработчиком терминального прерывания), он также обработает сигнал при возврате в режим задачи после обработки прерывания.

Работа с сигналами, связанными с особыми ситуациями, незначительно отличается от вышеописанной. Особая ситуация возникает при выполне нии процессом определенной инструкции, вызывающей в системе ошибку (например, деление на ноль, обращение к недопустимой области памяти, недопустимая инструкция или вызов и т. д.). Если такое происходит, вы зывается системный обработчик особой ситуации, и процесс переходит в режим ядра, почти так же, как и при обработке любого другого прерыва ния. Обработчик отправляет процессу соответствующий сигнал, который доставляется, когда выполнение возвращается в режим задачи.

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

В первом случае, доставка сигнала будет проверена ядром непосредственно перед переходом процесса в состояние сна. Если такой сигнал поступил, будет вызван обработчик сигнала, а системный вызов, который выполнял ся процессом, будет аварийно с ошибкой EINTR. Если генерация сигнала произошла в течение сна процесса, ядро будет вынуждено разбу дить его и снять прерванный системный вызов (ошибка EINTR). После пробуждения процесса либо вследствие получения сигнала, либо из за на ступления ожидаемого события, ядром будет вызвана функция которая обнаружит поступление сигнала и вызовет соответствующую Взаимодействие между процессами Как уже обсуждалось, в UNIX процессы выполняются в собственном ад ресном пространстве и по существу изолированы друг от друга. Тем самым сведены к минимуму возможности влияния процессов друг на друга, что является необходимым в многозадачных операционных системах. Однако В BSD UNIX были введено понятие перезапускаемых системных вызовов. Суть этого меха низма заключается в том, что прерванный сигналом системный вызов автоматически по вторяется после обработки сигнала, аварийного завершения с ошибкой EINTR. До пускается отключение этой возможности для конкретных сигналов.

www.books-shop.com процессами от одиночного изолированного процесса мало пользы. Сама концепция UNIX заключается в модульности, т. е. основана на взаимодействии между отдельными процессами.

Для реализации взаимодействия требуется:

обеспечить средства взаимодействия между процессами и одновременно П исключить нежелательное влияние одного процесса на другой.

Взаимодействие между процессами необходимо для решения следующих задач:

Передача данных. Один процесс передает данные другому процессу, при этом их объем может варьироваться от десятков байтов до не скольких мегабайтов.

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

О Извещения. Процесс может известить другой процесс или группу процессов о наступлении некоторого события. Это может понадо биться, например, для синхронизации выполнения нескольких про цессов.

Очевидно, что решать данную задачу средствами самих процессов неэффек тивно, а в рамках многозадачной системы — опасно и потому невозможно.

Таким образом, сама операционная система должна обеспечить механизмы межпроцессного взаимодействия Communication, К средствам межпроцессного взаимодействия, присутствующим во всех версиях UNIX, можно отнести:

П сигналы П каналы FIFO (именованные каналы) П сообщения (очереди сообщений) П семафоры П разделяемую память Последние три типа IPC обычно обобщенно называют System V Во многих версиях UNIX есть еще одно средство IPC — впервые предложенные в BSD UNIX (им посвящен отдельный раздел главы).

www.books-shop.com 242 Глава 3. управления процессами Сигналы изначально были предложены как средство уведомления об ошибках, но могут использоваться и для элементарного например, для синхронизации процессов или для передачи простейших команд от одного процесса к Однако использование сигналов в качестве средства ограничено из за того, что сигналы очень ресурсоемки. Отправка сиг нала требует выполнения системного вызова, а его доставка — прерывания процесса получателя и интенсивных операций со стеком процесса для вы зова функции обработки и продолжения его нормального выполнения.

При этом сигналы слабо информативны и их число весьма ограничено.

Поэтому сразу переходим к следующему механизму — каналам.

Каналы Вспомните синтаксис организации программных каналов при работе в ко мандной строке shell:

cat myfile ] При этом (стандартный) вывод программы которая выводит содер жимое файла myfile, передается на (стандартный) ввод программы которая, в свою очередь подсчитывает количество строк, слов и символов.

В результате мы получим что то вроде:

12 45 что будет означать количество строк, слов и символов в файле myfile.

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

Для создания канала используется системный вызов который возвращает два файловых дескриптора — [0] для записи в канал и [1] для чтения из канала. Теперь, если один процесс за писывает данные в другой сможет получить эти данные из fildes Вопрос только в том, как другой процесс сможет получить сам файловый дескриптор [ 1 ] ?

Вспомним наследуемые атрибуты при создании процесса. Дочерний про цесс наследует и разделяет все назначенные файловые дескрипторы роди тельского. То есть доступ к дескрипторам fildes канала может получить сам процесс, pipe(2), и его дочерние процессы. В этом Например, для системы (DNS) таким образом используется сиг нал по существу являющийся командой обновления базы данных.

www.books-shop.com процессами чается серьезный недостаток каналов, поскольку они могут быть исполь зованы для передачи данных только между родственными процессами.

Каналы не могут использоваться в качестве средства межпроцессного взаимодействия между независимыми процессами.

Хотя в приведенном примере может показаться, что процессы и независимы, на самом деле оба этих процесса создаются процессом shell и являются родственными.

Рис. 3.17. Создание канала между задачами cat(1) и FIFO Название каналов FIFO происходит от выражения First In First Out (пер вый вошел — первый вышел). FIFO очень похожи на каналы, поскольку являются однонаправленным средством передачи данных, причем чтение данных происходит в порядке их записи. Однако в отличие от программ ных каналов, FIFO имеют имена, которые позволяют независимым про цессам получить к этим объектам доступ. Поэтому иногда FIFO также на зывают именованными каналами. FIFO являются средством UNIX System V и не используются в BSD. Впервые FIFO были представлены в System III, однако они до сих пор не документированы и поэтому мало используются.

FIFO является отдельным типом файла в файловой системе UNIX покажет символ р в первой позиции, см. раздел "Файлы и файловая систе ма UNIX" главы 1). Для создания FIFO используется системный вызов int int mode, int где pathname — имя файла в файловой системе (имя FIFO), mode — флаги владения, прав доступа и т. д. (см. поле mode файла), dev — при создании FIFO игнорируется.

www.books-shop.com 244 Глава 3. процессами FIFO может быть создан и из командной строки shell:

$ name p После создания FIFO может быть открыт на запись и чтение, причем за пись и чтение могут происходить в разных независимых процессах.

Каналы FIFO и обычные каналы работают по следующим правилам:

1. При чтении меньшего числа байтов, чем находится в канале или FIFO, возвращается требуемое число байтов, остаток сохраняется для последующих чтений.

2. При чтении большего числа байтов, чем находится в канале или FIFO, возвращается доступное число байтов. Процесс, читающий из канала, должен соответствующим образом обработать ситуацию, когда прочи тано меньше, чем заказано.

3. Если канал пуст и ни один процесс не открыл его на запись, при чте нии из канала будет получено 0 байтов. Если один или более процес сов открыли канал для записи, вызов будет заблокирован до появления данных (если для канала или FIFO не установлен флаг от сутствия блокирования O_NDELAY).

4. Запись числа байтов, меньшего емкости канала или FIFO, гарантиро ванно атомарно. Это означает, что в случае, когда несколько процес сов одновременно записывают в канал, порции данных от этих про цессов не перемешиваются.

5. При записи большего числа байтов, чем это позволяет канал или FIFO, вызов блокируется до освобождения требуемого места.

При этом атомарность операции не гарантируется. Если процесс пы тается записать данные в канал, не открытый ни одним процессом на чтение, процессу генерируется сигнал SIGPIPE, а вызов воз вращает 0 с установкой ошибки (если процесс не уста новил обработки сигнала SIGPIPE, производится обработка по умол чанию — процесс завершается).

В качестве примера приведем простейший пример приложения клиент сервер, использующего FIFO для обмена данными. Следуя традиции, кли ент посылает серверу сообщение "Здравствуй, а сервер выводит это сообщение на терминал.

Сервер:

FIFO #define () { www.books-shop.com процессами char /*буфер для чтения данных из /*Создадим специальный файл FIFO с открытыми для всех правами доступа на чтение и if ( S_IFIFO I 0666, 0)<0){ создать } /*Получим доступ к if ( ( < = open(FIFO, открыть } /*Прочитаем сообщение и выведем его на while ( (n = read(readfd, buff, > 0) if buff, n) != n) { printf } /*3акроем FIFO, удаление FIFO — дело close exit(0) Клиент:

об имени FIFO { int writefd, n;

/*Получим доступ к if ( (writefd = open(FIFO, < открыть } /*Передадим сообщение серверу if "Здравствуй, 18) != 18) } /*3акроем /*Удалим if < удалить } exit(0) Идентификаторы и имена в Как было показано, отсутствие имен у каналов делает их недоступными для независимых процессов. Этот недостаток устранен у FIFO, которые имеют имена. Другие средства межпроцессного взаимодействия, являю щиеся более сложными, требуют дополнительных соглашений по именам www.books-shop.com 246 3.

управления процессами и идентификаторам. Множество возможных имен объектов конкретного типа межпроцессного взаимодействия называется пространством имен (name space). Имена являются важным компонентом системы межпро взаимодействия для всех объектов, кроме каналов, поскольку по зволяют различным процессам получить доступ к общему объекту. Так, именем FIFO является имя файла именованного канала. Используя услов ленное имя созданного FIFO два процесса могут обращаться к этому объ екту для обмена данными.

Для таких объектов IPC, как очереди сообщений, семафоры и разделяемая память, процесс назначения имени является более сложным, чем просто указание имени файла. Имя для этих объектов называется ключом (key) и генерируется функцией ftok(3C) из двух компонентов — имени файла и идентификатора проекта:

ftok (char char В качестве filename можно использовать имя некоторого файла, извест ное взаимодействующим процессам. Например, это может быть имя про граммы сервера. Важно, чтобы этот файл существовал на момент создания ключа. Также нежелательно использовать имя файла, который создается и удаляется в процессе работы распределенного приложения, поскольку при генерации ключа используется номер файла. Вновь созданный файл может иметь другой inode и впоследствии процесс, желающий иметь дос туп к объекту, получит неверный ключ.

Пространство имен позволяет создавать и совместно использовать не родственным процессам. Однако для ссылок на уже созданные объекты используются идентификаторы, точно так же, как файловый дескриптор используется для работы с файлом, открытым по имени.

Каждое из перечисленных IPC имеет свой уникальный дескриптор (идентификатор), используемый ОС (ядром) для работы с объектом. Уни кальность дескриптора обеспечивается уникальностью дескриптора для каждого из типов объектов (очереди сообщений, семафоры и разделяемая память), т. е. какая либо очередь сообщений может иметь тот же числен ный идентификатор, что и разделяемая область памяти (хотя любые две очереди сообщений должны иметь различные идентификаторы).

Таблица 3.5. Идентификация объектов IPC Объект IPC Пространство имен Дескриптор Канал — Файловый дескриптор FIFO Имя файла Файловый дескриптор Очередь сообщений Ключ Идентификатор www.books-shop.com процессами Таблица 3. Объект IPC Пространство имен Дескриптор Семафор Ключ Идентификатор Разделяемая память Ключ Идентификатор Работа с объектами IPC System V во многом сходна. Для создания или по лучения доступа к объекту используются соответствующие системные вы зовы get: для очереди сообщений, для семафора и для разделяемой памяти. Все эти вызовы возвращают дескриптор объекта в случае успеха и 1 в случае неудачи. Отметим, что функции get позволяют процессу получить ссылку на объект, которой по существу яв ляется возвращаемый дескриптор, но не позволяют производить конкрет ные операции над объектом (помещать или получать сообщения из ди сообщений, устанавливать семафор или записывать данные в разделяе мую память. Все функции get в качестве аргументов используют ключ key и флажки создания объекта ipcflag. Остальные аргументы зависят от конкретного типа объекта. Переменная ipcflag определяет права к объекту PERM, а также указывает, создается ли новый объект или требу ется доступ к Последнее определяется комбинацией (или отсутствием) флажков и Права доступа к объекту указываются набором флажков доступа, подобно тому, как это делается для файлов:

Значение PERM (в Аналог прав Разрешено восьмеричном виде) доступа для файлов 0400 r Чтение для владельца пользователя w Запись для владельца пользователя Чтение для владельца группы Запись для владельца группы Чтение для всех остальных Запись для всех остальных Комбинацией флажков можно добиться различных результатов:

Значение аргу Результат действия функции мента ipcflag Объект существует Объект не существует Возвращает дескриптор Ошибка: отсутствие объекта (ENOENT) PERM IPC Возвращает дескриптор Создает объект с соответствующими PERM правами доступа PERM I IPC_CREAT Ошибка: уже суще Создает объект с соответствующими ! доступа www.books-shop.com 248 Глава 3. Подсистема управления процессами Работа с объектами System V во многом похожа на работу с файлами в UNIX. Одним из различий является то, что файловые дескрипторы имеют значимость в контексте процесса, в то время как значимость дескрипторов объектов IPC распространяется на всю систему. Так файловый дескриптор 3 одного процесса в общем случае никак не связан с дескриптором 3 дру гого неродственного процесса (т. е. эти дескрипторы ссылаются на раз личные файлы). Иначе обстоит дело с дескрипторами объектов IPC. Все процессы, использующие, скажем, одну очередь сообщений, получат оди наковые дескрипторы этого объекта.

Для каждого из объектов IPC ядро поддерживает соответствующую струк туру данных, отличную для каждого типа объекта (очереди сообще ний, семафора или разделяемой памяти). Общей у этих данных является структура описывающая права доступа к объекту, подобно то му, как это делается для файлов. Основными полями этой структуры яв ляются:

Идентификатор владельца пользователя объекта Идентификатор владельца группы объекта UID создателя объекта cgid создателя объекта Права доступа на чтение и запись для всех классов доступа (9 битов) Ключ объекта Права доступа (как и для файлов) определяют возможные операции, кото рые может выполнять над объектом конкретный процесс (получение дос тупа к существующему объекту, чтение, запись и удаление).

Заметим, что система не удаляет созданные объекты IPC даже тогда, когда ни один процесс не пользуется ими. Удаление созданных объектов являет ся обязанностью процессов, которым для этого предоставляются соответ ствующие функции управления semctl(2), С помощью этих функций процесс может получить и установить ряд полей внутренних структур, поддерживаемых системой для объектов а также удалить созданные объекты. Безусловно, как и во многих других случаях использо вания объектов IPC процессы предварительно должны "договориться", ка кой процесс и когда удалит объект. Чаще всего, таким процессом является сервер.

Сообщения Как уже обсуждалось, очереди сообщений являются составной частью UNIX System V, они обслуживаются операционной системой, размещают ся в адресном пространстве ядра и являются разделяемым системным ре сурсом. Каждая очередь сообщений имеет свой уникальный идентифика тор. Процессы могут записывать и считывать сообщения из различных очередей. Процесс, пославший сообщение в очередь, может не ожидать www.books-shop.com процессами чтения этого сообщения каким либо другим процессом. Он может закон чить свое выполнение, оставив в очереди сообщение, которое будет про читано другим процессом позже.

Данная возможность позволяет процессам обмениваться структурирован ными данными, имеющими следующие атрибуты:

Тип сообщения (позволяет мультиплексировать сообщения в одной очереди) Длина данных сообщения в байтах (может быть нулевой) Собственно данные (если длина ненулевая, могут быть структуриро ванными) Очередь сообщений хранится в виде внутреннего однонаправленного свя занного списка в адресном пространстве ядра. Для каждой очереди ядро создает заголовок очереди где содержится информация о пра вах доступа к очереди ее текущем состоянии (msg_cbytes — число байтов и — число сообщений в очереди), а также указате ли на первое и последнее сообщения, хранящие ся в виде связанного списка (рис. 3.18). Каждый элемент этого списка яв ляется отдельным сообщением.

С о о б щ е н и я Рис. 3.18. Структура очереди сообщений Для создания новой очереди сообщений или для доступа к существующей используется системный вызов #include piracy@books-shop.com 250 3.

управления процессами #include int key_t key, int Функция возвращает дескриптор объекта очереди, либо 1 в случае ошибки.

Подобно файловому дескриптору, этот идентификатор используется процес сом для работы с очередью сообщений. В частности, процесс может:

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

ttinclude int const void msgsz, int int msqid, void *msgp, msgsz, long int Здесь является дескриптором объекта, полученного в результате вы зова Параметр указывает на буфер, содержащий тип сооб щения и его данные, размер которого равен msgsz байт. Буфер имеет сле дующие поля:

long тип сообщения char данные сообщения Аргумент msgtyp указывает на тип сообщения и используется для их вы борочного получения. Если msgtyp равен 0, функция получит первое сообщение из очереди. Если величина msgtyp выше 0, будет полу чено первое сообщение указанного типа. Если msgtyp меньше 0, функция получит сообщение с минимальным значением типа, меньше или равного абсолютному значению msgtyp.

Очереди сообщений обладают весьма полезным свойством — в одной оче реди можно мультиплексировать сообщения от различных процессов. Для демультиплексирования используется атрибут msgtype, на основании ко торого любой процесс может фильтровать сообщения с помощью функции как это было показано выше.

Рассмотрим типичную ситуацию взаимодействия процессов, когда сервер ный процесс обменивается данными с несколькими клиентами. Свойство мультиплексирования позволяет использовать для такого обмена одну оче редь сообщений. Для этого сообщениям, направляемым от любого из кли ентов серверу, будем присваивать значение типа, скажем, равным 1. Если www.books-shop.com между процессами в теле сообщения клиент каким либо образом идентифицирует себя (например, передает свой PID), то сервер сможет передать сообщение конкретному клиенту, присваивая тип сообщения равным этому иденти фикатору.

Поскольку функция msgrcv(2) позволяет принимать сообщения определен ного типа (типов), сервер будет принимать сообщения с типом 1, а клиен ты — сообщения с типами, равными идентификаторам их процессов. Схе ма такого взаимодействия представлена на рис. 3.19.

Очередь сообщений г Рис. 3.19. сообщений в одной очереди Атрибут также можно использовать для изменения порядка из влечения сообщений из очереди. Стандартный порядок получения сооб щений аналогичен принципу FIFO — сообщения получаются в порядке их записи. Однако используя тип, например, для назначения приоритета со общений, этот порядок легко изменить.

Пример приложения "Здравствуй, использующего сообщения:

Файл описания mesg.h MAXBUFF PERM структуру нашего Она может отличаться структуры msgbuf, но должна содержать поле В данном случае структура сообщения состоит из буфера struct our msgbuf { mtype;

www.books-shop.com 252 Глава 3. управления процессами char } Message;

Сервер:

ttinclude ttinclude ttinclude { нашего сообщения (может отличаться от структуры Message message;

key_t key;

msgid, length, if ( (key = < получить ) /*Тип принимаемых очередь if ( (msgid PERM | < создать } n = сообщение поступило, выведем его содержимое на if (n > 0) { if n) != n) { } } else { } чтения /*Удалить очередь поручим exit Клиент:

ttinclude ttinclude ttinclude ttinclude"mesg.h" main { нашего сообщения (может отличаться от структуры Message message;

key_t int msgid, length;

/*Тип посылаемого сообщения, может использоваться для = www.books-shop.com процессами if ( (key = < получить exit(l);

} доступ к очереди сообщений, очередь уже должна быть создана if ( = < получить доступ к } строку в if ( (length = "Здравствуй, < копирования в } if (void *) length, 0) записи сообщения в } очередь if 0) < удаления } } Семафоры Для синхронизации процессов, а точнее, для синхронизации доступа не скольких процессов к разделяемым ресурсам, используются семафоры. Яв ляясь одной из форм IPC, семафоры не предназначены для обмена боль шими объемами данных, как в случае FIFO или очередей сообщений.

Вместо этого, они выполняют функцию, полностью соответствующую сво ему названию — разрешать или запрещать процессу использование того или иного разделяемого ресурса.

Применение семафоров поясним на простом примере. Допустим, имеется некий разделяемый ресурс (например, файл). Необходимо блокировать доступ к ресурсу для других процессов, когда некий процесс производит операцию над ресурсом (например, записывает в файл). Для этого свяжем с данным ресурсом некую целочисленную величину — счетчик, доступный для всех процессов. Примем, что значение 1 счетчика означает доступ ность ресурса, 0 — его недоступность. Тогда перед началом работы с ре сурсом процесс должен проверить значение счетчика. Если оно равно 0 — ресурс занят и операция недопустима — процессу остается ждать. Если значение счетчика равно 1 — можно работать с ресурсом. Для этого, пре жде всего, необходимо заблокировать ресурс, т. е. изменить значение счет чика на 0. После выполнения операции для освобождения ресурса значе ние счетчика необходимо изменить на 1. В приведенном примере счетчик играет роль семафора.

Для нормальной работы необходимо обеспечить выполнение следующих условий:

www.books-shop.com 254 Глава 3. управления процессами 1. Значение семафора должно быть доступно различным процессам. По этому семафор находится не в адресном пространстве процесса, а в адресном пространстве ядра.

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

Таким образом семафоры являются системным ресурсом, действия над которым производятся через интерфейс системных вызовов.

Семафоры в System V обладают следующими характеристиками:

Семафор представляет собой не один счетчик, а группу, состоящую из нескольких счетчиков, объединенных общими признаками (на пример, дескриптором объекта, правами доступа и т. д.).

Каждое из этих чисел может принимать любое неотрицательное значе ние в пределах, определенных системой (а не только значения 0 и 1).

Для каждой группы семафоров (в дальнейшем мы будем называть группу просто семафором) ядро поддерживает структуру данных вклю чающую следующие поля:

struct Описание прав доступа struct Указатель на первый элемент массива семафоров sem_nsems Число семафоров в группе Время последней операции Время последнего изменения Значение конкретного семафора из набора хранится во внутренней струк туре sem:

ushort semval Значение семафора sempid Идентификатор процесса, выполнившего послед нюю операцию над семафором ushort Число процессов, ожидающих увеличения значе ния семафора ushort Число процессов, ожидающих обнуления сема фора Помимо собственно значения семафора, в структуре sem хранится иден тификатор процесса, вызвавшего последнюю операцию над семафором, число процессов, ожидающих увеличения значения семафора, и число www.books-shop.com Взаимодействие процессами процессов, ожидающих, когда значение семафора станет равным нулю.

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

Для получения доступа к семафору (и для его создания, если он не суще ствует) используется системный вызов ttinclude #include ttinclude int int key, int В случае успешного завершения операции функция возвращает дескрип тор объекта, в случае 1. Аргумент задает число семафо ров в группе. В случае, когда мы не создаем, а лишь получаем доступ к существующему семафору, этот аргумент игнорируется. Аргумент semflag определяет права доступа к семафору и флажки для его создания (IPC_CREAT, IPC_EXCL).

После получения дескриптора объекта процесс может производить опера ции над семафором, подобно тому, как после получения файлового деск риптора процесс может читать и записывать данные в файл. Для этого ис пользуется системный вызов ttinclude ttinclude ttinclude int semop(int struct size_t В качестве второго аргумента функции передается указатель на структуру данных, определяющую операции, которые требуется произвести над се мафором с дескриптором semid. Операций может быть несколько, и их число указывается в последнем аргументе nops. Важно, что ядро обеспе чивает атомарность выполнения критических участков операций (например, проверка значения — изменение значения) по отношению к другим процессам.

Каждый элемент набора операций имеет вид:

struct sembuf { short sem /*номер семафора в short short sem UNIX допускает три возможные операции над семафором, определяемые полем semop:

1. Если величина semop положительна, то текущее значение семафора увеличивается на эту величину.

www.books-shop.com 256 Глава 3. управления процессами 2. Если значение semop равно нулю, процесс ожидает, пока семафор не обнулится.

Если величина semop отрицательна, процесс ожидает, пока значение семафора не станет большим или равным абсолютной величине semop. Затем абсолютная величина semop вычитается из значения се мафора.

Можно заметить, что первая операция изменяет значение семафора (безусловное выполнение), вторая операция только проверяет его значение выполнение), а третья — проверяет, а затем изменяет значение семафора (условное выполнение).

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

Таким образом, при работе с семафорами процессы используют различные комбинации из трех операций, определенных системой, по своему трактуя значения семафоров.

В качестве примера рассмотрим два случая использования бинарного сема фора (т. е. значения которого могут принимать только 0 и 1). В первом примере значение 0 является разрешающим, а 1 запирает некоторый разде ляемый ресурс (файл, разделяемая память и т. п.), ассоциированный с се мафором. Определим операции, запирающие ресурс и освобождающие его:

static struct = { О, О, О, обнуления О, 1, 0 /*затем увеличить значение семафора на static struct sembuf sop unlock [1] = { 0, значение Итак, для запирания ресурса процесс вызов:

обеспечивающий атомарное выполнение двух Ядро обеспечивает атомарное выполнение не всего набора операций в целом, а лишь кри тических участков. Так, например, в процессе ожидания освобождения ресурса (ожидание нулевого значения семафора) выполнение процесса будет (и должно быть) прервано про цессом, который освободит ресурс (т. е. установит значение семафора равным 1). Ожида ние семафора соответствует "сна" процесса, допускающим выполнение других процессов в системе. В противном случае, процесс, ожидающий ресурс, остался бы забло кированным навсегда.

www.books-shop.com процессами 1. Ожидание доступности ресурса. В случае, если ресурс уже занят (значение семафора равно 1), выполнение процесса будет приостанов лено до освобождения ресурса (значение семафора равно 0).

2. Запирание ресурса. Значение семафора устанавливается равным Для освобождения ресурса процесс должен произвести вызов:

который уменьшит текущее значение семафора (равное 1) на и оно ста нет равным 0, что соответствует освобождению ресурса. Если какой либо из процессов ожидает ресурса (т. е. произвел вызов операции sop_lock), он будет "разбужен" системой, и сможет в свою очередь запереть ресурс и работать с ним.

Во втором примере изменим трактовку значений семафора: значению семафора соответствует доступность некоторого ассоциированного с сема фором ресурса, а нулевому значению — недоступность. В этом случае содержание операций несколько изменится.

static struct = { О, 1, 0, разрешающего сигнала (1), затем обнулить static struct sembuf sop_unlock [1] = { О, 1, значение семафора на Процесс запирает ресурс вызовом:

1);

а освобождает:

Во втором случае операции получились проще (по крайней мере их код стал компактнее), однако этот подход имеет потенциальную опасность:

при создании семафора, его значения устанавливаются равными 0, и во втором случае он сразу же запирает ресурс. Для преодоления данной си туации процесс, первым создавший семафор, должен вызвать операцию однако в этом случае процесс инициализации семафора пе рестанет быть атомарным и может быть прерван другим процессом, кото рый, в свою очередь, изменит значение семафора. В итоге, значение сема фора станет равным 2, что повредит нормальной работе с разделяемым ресурсом.

Можно предложить следующее решение данной проблемы:

семафор, если он уже существует возвращает ошибку, поскольку указан флаг if ( (semid = semget. ( key, perms IPC_CREAT I ) < 0) www.books-shop.com 258 Глава 3. /правления процессами if (errno = EEXIST) { ошибка вызвана существованием if ( = key, perms ) ) < 0) не хватает системных } else не хватает системных семафор создан нами, else Разделяемая память Интенсивный обмен данными между процессами с использованием рас смотренных механизмов межпроцессного взаимодействия (каналы, FIFO, очереди сообщений) может вызвать падение производительности системы.

Это, в первую очередь, связано с тем, что данные, передаваемые с помо щью этих объектов, копируются из буфера передающего процесса в буфер ядра и затем в буфер принимающего процесса. Механизм разделяемой па мяти позволяет избавиться от накладных расходов передачи данных через ядро, предоставляя двум или более процессам возможность непосредст венного получения доступа к одной области памяти для обмена данными.

Безусловно, процессы должны предварительно "договориться" о правилах использования разделяемой памяти. Например, пока один из процессов производит запись данных в разделяемую память, другие процессы долж ны воздержаться от работы с ней. К счастью, задача кооперативного ис пользования разделяемой памяти, заключающаяся в синхронизации вы полнения процессов, легко решается с помощью семафоров.

Примерный сценарий работы с разделяемой памятью выглядит следую щим образом:

1. Сервер получает доступ к разделяемой памяти, используя семафор.

2. Сервер производит запись данных в разделяемую память.

После завершения записи сервер освобождает разделяемую память с помощью семафора.

4. Клиент получает доступ к разделяемой памяти, запирая ресурс с по мощью семафора.

5. Клиент производит чтение данных из разделяемой памяти и освобож дает ее, используя семафор.

Для каждой области разделяемой памяти, ядро поддерживает структуру данных основными полями которой являются:

struct shm_perm Права доступа, владельца и создателя области (см.

описание выше) shm_segsz Размер выделяемой памяти www.books-shop.com Взаимодействие процессами ushort Число использующих разделяемую па мять Время последнего присоединения к разделяемой памяти Время последнего отключения от разделяемой памяти Время последнего изменения Для создания или для доступа к уже существующей разделяемой памяти используется системный вызов int key, size, int Функция возвращает дескриптор разделяемой памяти в случае успеха, и 1 в случае неудачи. Аргумент size определяет размер создаваемой области па мяти в байтах. аргумента shmflag задают права доступа к объекту и специальные флаги и Заметим, что вызов лишь создает или обеспечивает доступ к разделяемой памяти, но не позво ляет работать с ней. Для работы с разделяемой памятью (чтение и запись) необходимо сначала присоединить (attach) область вызовом ttinclude ttinclude char int shmid, char Вызов возвращает адрес начала области в пространстве процесса размером заданным предшествующем вызовом В этом адресном пространстве взаимодействующие процессы могут разме щать требуемые структуры данных для обмена информацией. Правила по лучения этого адреса следующие:

1. Если аргумент нулевой, то система самостоятельно выбирает адрес.

2. Если аргумент shmaddr отличен от нуля, значение возвращаемого ад реса зависит от наличия флажка SHM RND в аргументе • Если флажок SHM RND не установлен, система присоединяет разделяемую к указанному shmaddr адресу.

• Если флажок SHM_RND установлен, система присоединяет разде ляемую память к адресу, полученному округлением в меньшую сторону shmaddr до некоторой определенной величины SHMLBA.

По умолчанию разделяемая память присоединяется с правами на чтение и запись. Эти права можно изменить, указав флажок в аргумен те shmflag.

piracy@books-shop.com 260 Глава 3.

управления процессами Таким образом, несколько процессов могут отображать область разделяе мой памяти в различные участки собственного виртуального адресного пространства, как это показано на рис. 3.20.

3.20. Совместное использование разделяемой памяти Окончив работу с разделяемой памятью, процесс отключает (detach) об ласть вызовом int При работе с разделяемой памятью необходимо синхронизировать выпол нение взаимодействующих процессов: когда один из процессов записывает данные в разделяемую память, остальные процессы ожидают завершения операции. Обычно синхронизация обеспечивается с помощью семафоров, назначение и число которых определяется конкретным использованием разделяемой памяти.

Можно привести примерную схему обмена данными между двумя процес сами (клиентом и сервером) с использованием разделяемой памяти. Для синхронизации процессов использована группа из двух семафоров. Пер вый семафор служит для блокирования доступа к разделяемой памяти, его разрешающий сигнал — 0, а 1 является запрещающим сигналом. Второй семафор служит для сигнализации серверу о том, что клиент начал работу.

Необходимость применения второго семафора обусловлена следующими обстоятельствами: начальное состояние семафора, синхронизирующего работу с памятью, является открытым (0), и вызов сервером операции заблокирует обращение к памяти для клиента. Таким образом, www.books-shop.com Взаимодействие сервер должен вызвать операцию только после того, как разде ляемую память заблокирует клиент. второго семафора заклю чается в уведомлении сервера, что клиент начал работу, заблокировал раз деляемую память и начал записывать данные в эту область. Теперь, при вызове сервером операции mem_lock его выполнение будет приостановле но до освобождения памяти клиентом, который делает это после оконча ния записи строки "Здравствуй, ttdefine ttdefine PERM /*Структура данных в разделяемой typedef struct int segment;

char } Message;

/*0жидание начала выполнения static struct [1 ] = { 1, 1, сервера о том, что клиент начал static struct sembuf = { 1, 1, /*Блокирование разделяемой static struct sembuf = { О, О, О, 0 } /*0свобождение static struct sembuf { О, 1, Сервер:

"shmem.h" { Message key_t key;

int shmid, semid;

/*Получим Один и тот же ключ можно использовать как для семафора, так и для разделяемой www.books-shop.com 262 Глава 3. процессами if ( (key = < printf } получить область разделяемой if ( (Message.), PERM | < 0) { создать область } if ( (msgptr (Message 0, < } группу из двух Первый семафор — для синхронизации работы с Второй семафор — для синхронизации выполнения if ( 2, PERM | < = создать } пока клиент начнет работу и заблокирует разделяемую if 1) < выполнить } /*Ждем, пока клиент закончит запись в разделяемую память и освободит ее. После этого заблокируем if 2) < printf ( "Невозможно } сообщение на /*0свободим разделяемую if 1) < выполнить } /*0тключимся от if < } остальную работу по удалению объектов сделает exit(0) } Клиент:

ttinclude ttinclude #include #include { Message *msgptr;

www.books-shop.com key_t key;

semid;

Один и тот же ключ можно использовать как для семафора, так и для разделяемой if ( (key < получить } /*Получим доступ к разделяемой if ( (shmid = < } if ( 0, < = (Message *) } доступ к if ( (semid = 2, < } /*3аблокируем разделяемую if (semop(semid,, 2) < выполнить } сервер о начале if 1) < выполнить } /*3апишем в разделяемую память "Здравствуй, /*0свободим разделяемую if 1) < выполнить } /*Ждем, пока сервер в свою очередь не освободит разделяемую память if 2) < выполнить } от if < } /*Удалим созданные объекты if IPC_RMID, 0) < удалить ) if < 0) { (semid, 0, удалить } www.books-shop.com 264 Глава 3. Подсистема управления процессами Межпроцессное взаимодействие в BSD UNIX.

Разработчики системы межпроцессного взаимодействия BSD UNIX руко водствовались рядом соображений:

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

Для обозначения коммуникационного узла, обеспечивающего прием и передачу данных для объекта (процесса), был предложен специальный объект — (socket). Сокеты создаются в рамках определенного ком муникационного домена, подобно тому как файлы создаются в рамках файловой системы. Сокеты имеют соответствующий интерфейс доступа в файловой системе UNIX, и так же как обычные файлы, адресуются неко торым целым числом — дескриптором. Однако в отличие от обычных файлов, представляют собой виртуальный объект, который сущест вует, пока на него ссылается хотя бы один из процессов.

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

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

Поддержка передачи экстренных сообщений предполагает возможность доставки данных вне нормального потока. Как правило, это сообщения, www.books-shop.com процессами связанные с некоторыми срочными событиями, требующими немедленной реакции.

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

В BSD UNIX реализованы следующие основные типы сокетов:

(datagram socket), через который осуществляется теоретически ненадежная, несвязная передача пакетов.

Сокет потока (stream socket), через который осуществляется надеж ная передача потока байтов без сохранения границ сообщений. Этот тип сокетов поддерживает передачу экстренных данных.

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

Сокет низкого уровня (raw socket), через который осуществляется не посредственный доступ к коммуникационному протоколу.

Наконец, для того чтобы независимые процессы имели возможность взаи модействовать друг с другом, для сокетов должно быть определено про странство имен. Имя сокета имеет смысл только в рамках коммуникаци онного домена, в котором он создан. Если для System V используются ключи, то имена сокетов представлены адресами.

Программный интерфейс сокетов Итак, являются коммуникационным интерфейсом взаимодействую щих процессов. Конкретный характер взаимодействия зависит от типа ис пользуемых сокетов, а коммуникационный домен, в рамках которого создан сокет, определяет базовые свойства этого взаимодействия. В табл. 3.6 приве дены типы сокетов и их названия.

Таблица 3.6. Типы сокетов в системе BSD UNIX Название Тип Сокет датаграмм Сокет потока SOCK_SEQPACKET Сокет пакетов Сокет низкого уровня www.books-shop.com 266 Глава 3. процессами Для создания сокета процесс должен указать тип и коммуникаци онный домен, в рамках которого будет использоваться сокет. Поскольку коммуникационный домен может поддерживать использование нескольких протоколов, процесс может также указать конкретный коммуникационный протокол для взаимодействия. Если таковой не указан, система выберет наиболее подходящий из списка протоколов, доступных для данного ком муникационного домена. Если же в рамках указанного домена создание сокета данного типа невозможно, т. е. отсутствует соответствующий ком муникационный протокол, запрос процесса завершится неудачно.

Для создания сокета используется системный вызов имеющий следующий вид:

int domain, int type, Здесь аргумент domain определяет коммуникационный домен, type — тип сокета, a protocol — используемый протокол (может быть не указан, т. е.

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

По существу коммуникационный домен определяет семейство протоколов (protocol family), допустимых в рамках данного домена. Возможные значе ния аргумента domain включают:

Домен локального межпроцессного взаимодействия в пределах единой операционной системы UNIX. Внутренние протоколы.

Домен взаимодействия процессов удаленных систем. Протоколы Internet (TCP/IP).

Домен взаимодействия процессов удаленных систем. Протоколы Xerox NS.

Поскольку домен и семейство протоколов определяют адресное простран ство взаимодействия (допустимые адреса и их формат), то в названиях до менов присутствует префикс AF (от address family — семейство адресов).

Допустимыми также являются названия с префиксом PF (protocol family) PF UNIX, PF И Т. Д.

частью BSD в системах этой ветви Поскольку являются функции, связанные с этими объектами, в частности socket(2) и рассмотренные ниже, представляют собой системные вызовы. В UNIX ветви System V интерфейс сокетов сохра нен для совместимости, но имеет совершенно отличную от принятой в BSD архитектуру (основанную на подсистеме STREAMS). Поэтому все его функции являются библиотеч ными и описываются, соответственно в разделе 3 электронного справочника. Однако, ос тавляя пальму первенства в этом вопросе за BSD UNIX, в этом разделе будем считать эти функции системными вызовами и связывать с ними раздел 2 справочника www.books-shop.com Взаимодействие между процессами Заметим, что домен может не поддерживать определенные типы Для сравнения в табл. 3.7 приведены два основных коммуникационных домена — внутренний домен UNIX, предназначенный для взаимодействия процессов одной операционной системы, и домен TCP/IP, используемый в сетевых распределенных приложениях.

Таблица 3.7. Поддержка различных типов сокетов в доменах Домен: AF UNIX Тип сокета SOCK STREAM Да Да SOCK Да Да SOCK SEQPACKET Нет Нет SOCK RAW Нет Да Также допустимы не все комбинации типа сокета и используемого комму никационного протокола (если таковой явно указан в запросе). Так для домена AF_INET возможны следующие комбинации:

Сокет Протокол SOCK_STREAM (TCP) (UDP) (IP) Указанные протоколы принадлежат семейству сетевых протоколов TCP/IP и будут подробно рассмотрены в главе 6.

Создание сокета не означает создания коммуникационного узла. Для одно значной идентификации сокета его необходимо позиционировать в про странстве имен данного коммуникационного домена. В общем случае каж дый коммуникационный канал определяется двумя узлами — источником и получателем данных, и может быть охарактеризован пятью параметрами:

1. Коммуникационным протоколом 2. Локальным адресом 3. Локальным процессом 4. Удаленным адресом 5. Удаленным процессом Как правило, адрес определяет операционную систему (или хост сети), а процесс — конкретное приложение, получающее или передающее данные.

Однако конкретные значения и формат этих параметров определяются коммуникационным доменом.

www.books-shop.com 268 Глава 3. управления процессами Поскольку при создании сокета указывается только один параметр — коммуникационный протокол, прежде чем передача данных между взаи модействующими процессами станет возможной необходимо указать четы ре дополнительных параметра для коммуникационного канала. Очевидно, что взаимодействующие стороны должны делать это согласованно, исполь зуя либо заранее определенные адреса, либо договариваясь о них в про цессе установления связи. Процедура установки этих параметров сущест венным образом зависит и от типа создаваемого канала, определяемого типом используемого сокета и коммуникационного протокола.

Иллюстрация взаимодействия между процессами при виртуальном комму никационном канале с предварительным установлением связи приведена на рис. 3.21, а взаимодействие, основанное на датаграммах без установле ния связи показано на рис. 3.22.

Рис. 3.21. Взаимодействие между процессами при создании виртуального канала (с предварительным установлением соединения) www.books-shop.com между процессами Рис. 3.22. Взаимодействие между процессами, основанное на датаграммах (без предварительного установления соединения) Как видно из рисунков, фактической передаче данных предшествует началь ная фаза связывания (binding) сокета, когда устанавливается дополнительная информация, необходимая для определения коммуникационного узла. Связы вание может быть осуществлено с помощью системного вызова int bind(int sockfd, struct sockaddr *localaddr, int Здесь sockfd является дескриптором сокета, полученным при его созда нии;

аргумент определяет локальный адрес, с которым необхо димо связать сокет;

параметр addrlen определяет размер адреса. Заметим, что речь идет о связывании с локальным адресом, в общем случае опреде ляющим два параметра коммуникационного канала (коммуникационный узел): локальный адрес и локальный процесс.

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

piracy@books-shop.com 270 Глава 3. управления процессами struct { char Поле sa_family определяет коммуникационный домен (семейство прото колов), a.— содержит собственно адрес, формат которого опреде лен для каждого домена.

Например, для внутреннего домена UNIX адрес выглядит следующим об разом (определен в struct sockaddr_un { short /* */ char Поскольку в данном домене взаимодействующие процессы выполняются под управлением одной операционной системы на одном и том же хосте, коммуникационный узел может быть однозначно определен одним пара метром — локальным процессом. В качестве адреса в домене UNIX ис пользуются имена файлов.

В отличие от локального межпроцессного взаимодействия, для сетевого обмена данными необходимо указание как локального процесса, так и хоста, на котором выполняется данный процесс. Для домена Internet (се мейство протоколов TCP/IP) используется следующий формат адреса (определен в файле ):

struct { short /* ==AF_INET */ struct in_addr char Адреса этого домена (IP адреса) будут рассмотрены подробнее в главе 6.

Пока лишь заметим, что адрес хоста представляет собой 32 разрядное це лое число sin_addr, а процесс (приложение) адресуется 16 разрядным номером порта sin_port.

На рис. 3.23 показаны рассмотренные форматы адресов сокетов.

Итак, связывание необходимо для присвоения сокету локального адреса и, таким образом, для определения коммуникационного узла. Можно выде лить три случая использования для этого функции 1. Сервер регистрирует свой адрес. Этот адрес должен быть заранее из вестен клиентам, желающим "общаться" с сервером. Связывание необ ходимо, прежде чем сервер будет готов к приему запросов от клиентов.

2. При взаимодействии без предварительного установления связи и соз дания виртуального канала клиент также должен предварительно за www.books-shop.com регистрировать свой адрес. Этот адрес должен быть уникальным в рамках коммуникационного домена. В случае домена UNIX об этом должно позаботиться само приложение. Этот адрес не должен быть за ранее известен серверу, поскольку запрос всегда инициирует клиент, автоматически передавая вместе с ним свой адрес. Полученный адрес удаленного узла затем используется сервером для мультиплексирова ния сообщений, отправляемым различным клиентам.

3. Даже в случае взаимодействия с использованием виртуального канала клиент может пожелать зарегистрировать собственный адрес, не по лагаясь при этом на систему.

UNIX домен Internet домен un sockaddr in т AF_UNIX 2 байта 1s port 2 байта IP адрес )йта Имя файла до He используется 86айт Рис. 3.23. Адреса сокетов Назначение адреса для клиента также можно выполнить с помощью сис темного вызова устанавливающего связь с сервером и автомати чески связывающего сокет клиента с локальным коммуникационным уз лом. Вызов имеет вид:

ttinclude ttinclude int sockfd, struct sockaddr *servaddr, int Характер этого вызова предполагает создание виртуального канала и, та ким образом, используется для предварительного установления связи меж ду коммуникационными узлами. В этом случае клиенту нет необходимости www.books-shop.com 272 Глава 3. управления процессами явно связывать с помощью системного вызова Локальный узел коммуникационного канала указывается дескриптором сокета sockfd, для которого система автоматически выбирает приемлемые значе ния локального адреса и процесса. Удаленный узел определяется аргумен том servaddr, который указывает на адрес сервера, a addrlen задает его длину.

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

Следующие два вызова используются сервером только при взаимодейст вии, основанном на предварительном создании виртуального канала меж ду сервером и клиентом.

Системный вызов listen(2) информирует систему, что сервер готов прини мать запросы. Он имеет следующий вид:

int (int sockfd, int Здесь параметр sockfd определяет сокет, который будет использоваться для получения запросов. Предполагается, что сокет был предварительно связан с известным адресом. Параметр backlog указывает максимальное число запросов на установление связи, которые могут ожидать обработки Фактическую обработку запроса клиента на установление связи произво дит системный вызов int sockfd, struct sockaddr int Вызов accept(2) извлекает первый запрос из очереди и создает новый со кет, характеристики которого не отличаются от сокета sockfd, и таким Если в момент получения запроса на установление связи очередь ожидающих запросов достигла своего максимального значения, вызов клиента завершится с ошибкой для UNIX (AF_UNIX). Для других доменов результат зависит от то го, поддерживает ли протокол повторную передачу запроса. Например, протокол TCP (домен AF_INET) будет передавать повторные запросы, пока число запросов в очереди не уменьшится, либо не произойдет тайм аут, определенный для протокола. В последнем случае вызов клиента завершится с ошибкой www.books-shop.com между процессами образом завершает создание виртуального канала со стороны сервера. Од новременно accept(2) возвращает параметры удаленного коммуникацион ного узла — адрес клиента clntaddr и его размер Новый сокет используется для обслуживания созданного виртуального канала, а полу ченный адрес клиента исключает анонимность последнего. Дальнейший типичный сценарий взаимодействия имеет вид:

= Создать сокет Связать его с известным локальным..

адресом Организовать очередь запросов for ( ;

Pages:     | 1 |   ...   | 2 | 3 || 5 | 6 |   ...   | 8 |



© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.