Андрей Робачевский - Операционная система UNIX
- Название:Операционная система UNIX
- Автор:
- Жанр:
- Издательство:BHV - Санкт-Петербург
- Год:1997
- Город:Санкт-Петербург
- ISBN:5-7791-0057-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Андрей Робачевский - Операционная система UNIX краткое содержание
Книга посвящена семейству операционных систем UNIX и содержит информацию о принципах организации, идеологии и архитектуре, объединяющих различные версии этой операционной системы.
В книге рассматриваются: архитектура ядра UNIX (подсистемы ввода/вывода, управления памятью и процессами, а также файловая подсистема), программный интерфейс UNIX (системные вызовы и основные библиотечные функции), пользовательская среда (командный интерпретатор shell, основные команды и утилиты) и сетевая поддержка в UNIX (протоколов семейства TCP/IP, архитектура сетевой подсистемы, программные интерфейсы сокетов и TLI).
Для широкого круга пользователей
Операционная система UNIX - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Процесс передает данные потоку с помощью системных вызовов write(2) и putmsg(2) . Системный вызов write(2) , представляющий собой унифицированный интерфейс передачи данных любым устройствам, позволяет производить передачу простых данных в виде потока байтов, не сохраняя границы логических записей. Системный вызов putmsg(2) , предназначенный специально для работы с потоками, позволяет процессу за один вызов передать управляющее сообщение и данные. Головной модуль преобразует эту информацию в единое сообщение с сохранением границ записи.
Системный вызов putmsg(2) имеет вид:
#include
int putmsg(int fildes, const struct strbuf *ctlptr,
const struct strbuf* dataptr, int flags);
С помощью этого вызова головной модуль формирует сообщение, состоящее из управляющей части M_PROTO
и данных, передаваемых в блоках M_DATA
. Содержимое сообщения передается с помощью указателей на структуру strbuf
— ctlptr
для управляющего блока и dataptr
для блоков данных.
Структура strbuf
имеет следующий формат:
struct strbuf {
int maxlen;
int len;
void *buf;
}
где maxlen
не используется, len
— размер передаваемых данных, buf
— указатель на буфер.
С помощью аргумента flags
процесс может передавать экстренные сообщения, установив флаг RS_HIPRI
.
В обоих случаях головной модуль формирует сообщение и с помощью функции canput(9F) проверяет, способен ли следующий вниз по потоку модуль, обеспечивающий механизм управления передачей, принять его. Если canput(9F) возвращает истинный ответ, сообщение передается вниз по потоку с помощью функции putnext(9F) , а управление возвращается процессу. Если canput(9F) возвращает ложный ответ, выполнение процесса блокируется, и он переходит в состояние сна, пока не рассосется образовавшийся затор. Заметим, что возврат системного вызова еще не гарантирует, что данные получены устройством. Возврат из write(2) или putmsg(2) свидетельствует лишь о том, что данные были успешно скопированы в адресное пространство ядра, и в виде сообщения направлены вниз по потоку.
Процесс может получить данные из потока с помощью системных вызовов read(2) и getmsg(2) . Стандартный вызов read(2) позволяет получать только обычные данные без сохранения границ сообщений. [63] С помощью сообщения M_SETOPTS можно дать указания головному модулю обрабатывать сообщения M_PROTO как обычные данные. В этом случае вызов read(2) будет возвращать содержимое как сообщений M_DATA , так и M_PROTO . Однако информация о типе сообщения (данных) и границы сообщений сохранены не будут.
В отличие от этого вызова getmsg(2) позволяет получать данные сообщений типов M_DATA
и M_PROTO
, при этом сохраняются границы сообщений. Например, если полученное сообщение состоит из блока M_PROTO
и нескольких блоков M_DATA
, вызов getmsg(2) корректно разделит сообщение на две части: управляющую информацию и собственно данные.
Вызов getmsg(2) имеет вид:
#include
int getmsg(int fildes, struct strbuf *ctlptr,
struct strbuf *dataptr, int *flagsp);
С помощью вызова getmsg(2) прикладной процесс может получить сообщение, причем его управляющие и прикладные данные будут помещены в буферы, адресуемые ctlptr
и dataptr
соответственно. Так же как и в случае putmsg(2) эти указатели адресуют структуру strbuf
, которая отличается только тем, что поле maxlen
определяет максимальный размер буфера, a len
устанавливается равным фактическому числу полученных байтов. По умолчанию getmsg(2) получает первое полученное сообщение, однако с помощью флага RS_HIPRI
, установленного в переменной, адресуемой аргументом flagsp
, процесс может потребовать получение только экстренных сообщений.
В обоих случаях, если данные находятся в головном модуле, ядро извлекает их из сообщения, копирует в адресное пространство процесса и возвращает управление последнему. Если же в головном модуле отсутствуют сообщения, ожидающие получения, выполнение процесса блокируется, и он переходит в состояние сна до прихода сообщения.
Когда головной модуль получает сообщение, ядро проверяет, ожидает ли его какой-либо процесс. Если такой процесс имеется, ядро пробуждает процесс, копирует данные в пространство задачи и производит возврат из системного вызова. Если ни один из процессов не ожидает получения сообщения, оно буферизуется в очереди чтения головного модуля.
Доступ к потоку
Как и для обычных драйверов устройств, рассмотренных ранее, прежде чем процесс сможет получить доступ к драйверу STREAMS, необходимо встроить драйвер в ядро системы и создать специальный файл устройства — файловый интерфейс доступа. Независимо от того, как именно осуществляется встраивание (статически с перекомпиляцией ядра, или динамически), для этого используются три структуры данных, определенных для любого драйвера или модуля STREAMS: module_info
, qinit
и streamtab
. Связь между ними представлена на рис. 5.21.

Рис. 5.21. Конфигурационные данные драйвера (модуля) STREAMS
Структура streamtab
используется ядром для доступа к точкам входа драйвера или модуля — к процедурам его очередей xx open()
, xx close()
, xx put()
и xx service()
. Для этого streamtab
содержит два указателя на структуры qinit
, соответственно, для обработки сообщений очереди чтения и записи. Два других указателя, также на структуры qinit
, используются только для мультиплексоров для обработки команды I_LINK
, используемой при конфигурации мультиплексированного потока. Каждая структура qinit
определяет процедуры, необходимые для обработки сообщений вверх и вниз по потоку (очередей чтения и записи). Функции xx open()
и xx close()
являются общими для всего модуля и определены только для очереди чтения. Все очереди модуля имеют ассоциированную с ними процедуру xx put()
, в то время как процедура xx service()
определяется только для очередей, реализующих управление передачей. Каждая структура qinit
также имеет указатель на структуру module_info
, которая обычно определяется для всего модуля и хранит базовые значения таких параметров, как максимальный и минимальный размеры передаваемых пакетов данных ( mi_maxpsz
, mi_minpsz
), значения ватерлиний ( mi_hiwat
, mi_lowait
), а также идентификатор и имя драйвера (модуля) ( mi_idnum
, mi_idname
).
Доступ к драйверам STREAMS осуществляется с помощью коммутатора символьных устройств — таблицы cdevsw[]
. Каждая запись этой таблицы имеет поле d_str
, которое равно NULL
для обычных символьных устройств. Для драйверов STREAMS это поле хранит указатель на структуру streamtab
драйвера. Таким образом, через коммутатор устройств ядро имеет доступ к структуре streamtab
драйвера, а значит и к его точкам входа. Для обеспечения доступа к драйверу из прикладного процесса необходимо создать файловый интерфейс — т.е. специальный файл символьного устройства, старший номер которого был бы равен номеру элемента cdevsw[]
, адресующего точки входа драйвера.
Интервал:
Закладка: