UNIX: взаимодействие процессов
Шрифт:
15.3. Функция door_create
Процесс-сервер определяет некоторую функцию как процедуру сервера вызовом door_create:
Здесь мы добавили наше собственное определение типа, что упрощает прототип функции. Это определение утверждает, что процедуры сервера (например, servproc в листинге 15.2) вызываются с пятью аргументами и ничего не возвращают.
Когда сервер вызывает door_create, первый аргумент (proc) указывает адрес процедуры сервера, которая будет вызываться через дескриптор двери, возвращаемый этим вызовом. При вызове процедуры сервера ее аргумент cookie содержит значение, передаваемое в качестве второго аргумента door_create. Это дает серверу возможность передавать процедуре какой-либо указатель каждый раз, когда эта процедура вызывается клиентом. Следующих четыре аргумента процедуры сервера — dataptr, datasize, descptr и ndesc — описывают аргументы-данные и аргументы-дескрипторы клиента. Они соответствуют первым четырем полям структуры door_arg_t, описанной в предыдущем разделе.
Последний аргумент door_create(attr) описывает специальные атрибуты процедуры сервера и может быть равен либо 0, либо логической сумме двух констант:
■ DOOR_PRIVATE — библиотека дверей автоматически создает новые потоки в процессе-сервере при поступлении запросов от клиентов. По умолчанию эти потоки помещаются в пул потоков и могут использоваться для обслуживания запросов клиентов по всем дверям данного процесса.
Указание атрибута DOOR_PRIVATE говорит библиотеке, что для данной двери следует создать собственный пул потоков, отдельный от пула потоков процесса.
■ DOOR_UNREF — когда количество дескрипторов, открытых для данной двери, изменяется с двух до одного, процедура сервера вызывается со вторым аргументом, имеющим значение DOOR_UNREF_DATA. При этом аргумент descptr представляет собой нулевой указатель, а аргументы datasize и ndesc равны нулю. Мы приведем пример использования этого атрибута в листинге 15.13.
Возвращаемое сервером значение имеет тип void, поскольку процедура сервера никогда не завершает работу вызовом return. Вместо этого процедура должна вызывать door_return (функция описана в следующем разделе).
В листинге 15.2 мы видели, что после получения дескриптора двери вызовом door_create сервер должен вызвать fattach для связывания этого дескриптора с некоторым файлом. Клиент затем может открыть этот файл для получения дескриптора двери, который впоследствии может быть использован при вызове door_call.
ПРИМЕЧАНИЕ
Функция fattach не включена в стандарт Posix.1, но ее наличие требуется стандартом Unix 98. Кроме того, этот стандарт определяет также функцию fdetach, отключающую связь дескриптора и файла, и программу fdetach, вызывающую эту функцию.
Для дескрипторов дверей, создаваемых door_create, устанавливается бит FD_CLOEXEC. Это означает, что дескриптор закрывается при вызове процессом функций типа exec. Что касается вызова fork, несмотря на то что открытые родительским процессом дескрипторы используются дочерним процессом совместно с ним, только родительский процесс будет принимать вызовы от клиентов. Дочерним процессам вызовы не передаются, хотя дескриптор, возвращаемый door_create, и будет в них открыт.
ПРИМЕЧАНИЕ
Если мы учтем, что дверь идентифицируется с помощью PID и адреса процедуры сервера (что
мы узнаем из структуры door_info_t в разделе 15.6), ограничения на вызовы exec и fork станут понятны. Дочерний процесс не будет принимать вызовов, поскольку его идентификатор процесса отличается от идентификатора, связанного с дверью. Дескриптор должен быть закрыт при вызове exec, потому что хотя идентификатор при этом и не меняется, адрес процедуры сервера уже не будет иметь никакого смысла в той программе, которая будет запущена после вызова exec.15.4. Функция door_return
После завершения работы процедуры сервера возврат из нее осуществляется вызовом door_return. Это приводит к возврату из door_call соответствующего клиента.
Возвращаемые данные задаются аргументами dataptr и datasize, а возвращаемые дескрипторы — descptr и ndesc.
15.5. Функция door_cred
Интерфейс дверей предусматривает полезную возможность получения информации о клиенте при каждом вызове. Это осуществляется функцией door_cred:
Структура, на которую указывает аргумент cred, имеет тип door_cred_t, определяемый как
В эту структуру помещается информация о клиенте при возвращении из вызова door_cred. В разделе 4.4 [21] подробно рассказывается о различиях между действующими и реальными идентификаторами пользователя и группы, а пример использования этой функции приведен в листинге. 15.5.
Обратите внимание, что эта функция не принимает никаких дескрипторов. Она возвращает информацию о клиенте, осуществившем конкретный вызов через дверь, и поэтому должна вызываться из процедуры сервера или другой функции, вызываемой из процедуры сервера.
15.6. Функция door_info
Только что описанная функция door_cred предоставляет серверу информацию о клиенте. Клиент же может получить информацию о сервере, вызвав doo_info:
Дескриптор fd указывает на открытую дверь. Структура типа door_info_t, на которую указывает info, после возвращения из функции содержит информацию о сервере: