Создать канал связи
#include <sys/neutrino.h>int ChannelCreate( unsigned flags );int ChannelCreate_r( unsigned flags );
libc
Вызовы ядра ChannelCreate() и ChannelCreate_r() создают канал, который может использоваться для получения сообщений и импульсов. После создания канал принадлежит процессу и никак не связан с потоком, создавшим его.
Эти функции идентичны за исключением способа оповещения об ошибке.
Потоки, желающие связаться с каналом, присоединяются к нему посредством вызова ConnectAttach(). Потоки могут находиться в том же процессе или в другом процессе того же узла (или удаленного узла, если запущен сетевой менеджер).
Если процесс хочет, чтобы другие процессы взаимодействовали с ним, он обычно использует name_attach() для создания канала и связывания с ним имени, процесс-отправитель же использует name_open() для определения этого имени и создания соединения с ним. |
После присоединения потоки используют MsgSendv() или MsgSendPulse() для помещения сообщений и импульсов в канал. Сообщения и импульсы помещаются в очередь в порядке приоритета.
Для извлечения и чтения сообщений и импульсов из канала используется MsgReceivev(). Любое количество потоков может вызвать MsgReceivev() в одно и то же время, в этом случае они блокируются и помещаются в очередь (если нет ожидающих сообщений или импульсов) для получения сообщения или импульса. Многопоточный менеджер ввода/вывода обычно создает несколько потоков и устанавливает их в состояние RECEIVE
-блокировки на канале.
Значение, возвращаемое ChannelCreate() - идентификатор канала, целочисленное значение, взятое из вектора канала в процессе. Большинство менеджеров использует один канал для большинства, если не для всех, взаимодействий с клиентами. Дополнительные каналы могут использоваться как специальные информационные каналы.
По умолчанию, когда сообщение получено из канала, приоритет потока получателя устанавливается в соответствии с приоритетом потока отправителя. Это наследование базового приоритета используется для предотвращения инверсии приоритета. Если сообщение приходит в канал и ожидающие потоки-получатели отсутствуют, ситема увеличивает приоритет (при необходимости) для всех потоков процесса, которые ранее получали сообщение из канала. Это увеличение приоритета предотвращает инверсию приоритета клиента в случае, если все потоки в текущий момент работают от имени других клиентов, вероятно, с более низким приоритетом. Когда поток только создан, он не связан с каналом до тех пор, пока не выполнит MsgReceivev() для него. В случае нескольких каналов поток связывается с последним каналом, из которого он получил сообщение.
После получения сообщения поток может отсоединить себя от канала путем вызова MsgReceivev() с a -1
для идентификатора канала. Наследование приоритетов может быть отключено с помощью установки _NTO_CHF_FIXED_PRIORITY
в аргументе flags. В этом случае на приоритет потока не влияют сообщения, получаемые через канал.
Менеджер обычно использует следующий цикл. В цикле одновременно может быть один или несколько потоков. Следует заметить, что программа (а не каждый поток) должна вызвать ChannelCreate() только раз.
iov_t iov;...SETIOV( &iov, &msg, sizeof( msg ) );...chid = ChannelCreate( flags );...for ( ; ; ){/** Here's a one-part message; you could just as easily receive a 20-part message* by filling in the iov appropriately.*/rcvid = MsgReceivev( chid, &iov, 1, &info );/* msg is filled in by MsgReceivev() */switch( msg.type ){...}/* iov could be filled in again to point to a new message */MsgReplyv( rcvid, iov, 1 );}
Некоторые из флагов канала в аргументе flags запрашивают изменения поведения относительно стандартного; другие запрашивают импульсы уведомлений от ядра. Импульсы принимаются с помощью MsgReceivev() через канал и описываются структурой struct _pulse.
Флаги канала и (где необходимо) связанные значения для code и value импульса описаны ниже.
_PULSE_CODE_COIDDEATH
Доставляет импульс в канал для каждого соединения, принадлежащего вызывающему процессу, когда канал, с которым связано соединение, завершен. Только один канал на процесс может установить этот флаг.
Если для канала установлен один или оба флага _NTO_CHF_COID_DISCONNECT или _NTO_CHF_THREAD_DEATH , ни один флаг не может быть установлен для любого другого канала в процессе. |
Если сервер завершается или закрывает канал примерно в то же время, что и клиент закрывает соединение с каналом, ядро может послать, а может и не послать импульс a _PULSE_CODE_COIDDEATH
клиенту. Если в дальнейшем клиент открывает новое соединение с другим сервером до получения этого импульса, импульс будет указывать, что именно новый сервер был завершен. Код для обработки импульса _PULSE_CODE_COIDDEATH
должен содержать что-то вроде этого:
void got_pulse( struct _pulse *pulse ){if ( pulse->type == _PULSE_CODE_COIDDEATH ){int coid = pulse->value.sival_int;if ( ConnectServerInfo( 0, coid, NULL ) != coid ){/* server's really gone, so clean up the connection state */} else {/* stale pulse; probably can ignore it */}}}
_PULSE_CODE_DISCONNECT
Доставляет импульс, когда все соединения процесса отсоединены (например, с помощью close(), ConnectDetach() или name_close()). Если процесс завершается без отсоединения всех своих соединений, ядро отсоединяет их от него. Если данный флаг установлен, сервер должен вызвать ConnectDetach( scoid ), где scoid - идентификатор соединения сервера в сообщении импульса. В противном случае остается некорректный идентификатор соединения сервера, который не может быть переиспользован. Со временем у сервера могут закончиться доступные идентификаторы. Если данный флаг не установлен, ядро удаляет идентификатор соединения сервера автоматически, делая его доступным для переиспользования.
Подавить наследование приоритета при получении сообщений. Принимающие потоки не меняют свои приоритеты на приоритеты отправляющих потоков. При использовании адаптивного разбиения потоки-получатели не могут работать в разделах потоков-отправителей.
Зарезервировано для менеджера ресурсов io-pkt-*.
Запрос о размещении длины ответа в поле dstmsglen структуры struct _msg_info, которую заполняет вызов MsgReceivev(). Поле dstmsglen действительно только в случае, если данный флаг был установлен при создании канала.
Запрос о размещении длины исходного сообщения в поле srcmsglen структуры struct _msg_info, которую заполняет вызов MsgReceivev(). Поле srcmsglen действительно только в случае, если данный флаг был установлен при создании канала.
_PULSE_CODE_THREADDEATH
Доставляет импульс в случае завершения любого потока в процессе, которому принадлежит канал. Только один канал на процесс может установить данный флаг.
Если для канала установлен один или оба флага _NTO_CHF_COID_DISCONNECT или _NTO_CHF_THREAD_DEATH , ни один флаг не может быть установлен для любого другого канала в процессе. |
_PULSE_CODE_UNBLOCK
В большинстве случаев будет установлен флаг _NTO_CHF_UNBLOCK . |
Доставляет импульс, когда поток, заблокированный на REPLY
на канале, пытается разблокироваться до того, как на его сообщение будет дан ответ. Это происходит между MsgReceivev() и MsgReplyv() на сервере. Отправляющий поток может быть разблокирован из-за сигнала или таймаута ядра.
Если отправляющий поток разблокируется, MsgReplyv() завершается с ошибкой. Менеджер может быть не в состоянии справиться с этой ошибкой. Также возможно, что клиент завершается из-за сигнала и больше никогда не отправит сообщение. Если менеджер удерживает ресурсы для клиента (например, открытый файл), он может хотеть получить уведомление, что клиент желает завершить вызов MsgSendv().
Установка бита _NTO_CHF_UNBLOCK
в flags предотвращает ситуацию, когда поток, заблокированный на состоянии REPLY
, разблокируется. Вместо этого в канал отправляется импульс, уведомляющий менеджер, что клиент желает разблокироваться. В случае сигнала, он будет отложен для клиентского потока. Когда менеджер отвечает, клиент разблокируется, в этом момент происходит обработка отложенных сигналов. С точки зрения клиента, вызов MsgSendv() нормально завершается, и любой сигнал может прийти после успешного вызова ядра.
Когда менеджер получает импульс, он выполняет одно из следующих действий:
Данные вызовы не блокируются.
-1
и устанавливает errno.
ЗОСРВ «Нейтрино»
ChannelDestroy(), close(), ConnectAttach(), ConnectDetach(), struct _msg_info, MsgReceivev(), MsgReplyv(), MsgSendv(), MsgSendPulse(), name_attach(), name_close(), name_open(), struct _pulse
Предыдущий раздел: Описание API системной библиотеки