ChannelCreate(), ChannelCreate_r()

Создать канал связи

Прототип:

#include <sys/neutrino.h>
int ChannelCreate( unsigned flags );
int ChannelCreate_r( unsigned flags );

Аргументы:

flags
Флаги, используемые для запросов импульсов уведомлений от ядра или запросов иных изменений в поведении; комбинация следующих значений:

Библиотека:

libc

Описание:

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

Эти функции идентичны за исключением способа оповещения об ошибке.

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


Note: Если процесс хочет, чтобы другие процессы взаимодействовали с ним, он обычно использует 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 импульса описаны ниже.

_NTO_CHF_COID_DISCONNECT

Код импульса:
_PULSE_CODE_COIDDEATH
Значение импульса:
Идентификатор соединения (coid), которое было связано с уничтоженным каналом.

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


Note: Если для канала установлен один или оба флага _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 */
}
}
}

_NTO_CHF_DISCONNECT

Код импульса:
_PULSE_CODE_DISCONNECT
Значение импульса:
Отсутствует

Доставляет импульс, когда все соединения процесса отсоединены (например, с помощью close(), ConnectDetach() или name_close()). Если процесс завершается без отсоединения всех своих соединений, ядро отсоединяет их от него. Если данный флаг установлен, сервер должен вызвать ConnectDetach( scoid ), где scoid - идентификатор соединения сервера в сообщении импульса. В противном случае остается некорректный идентификатор соединения сервера, который не может быть переиспользован. Со временем у сервера могут закончиться доступные идентификаторы. Если данный флаг не установлен, ядро удаляет идентификатор соединения сервера автоматически, делая его доступным для переиспользования.

_NTO_CHF_FIXED_PRIORITY

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

_NTO_CHF_NET_MSG

Зарезервировано для менеджера ресурсов io-pkt-*.

_NTO_CHF_REPLY_LEN

Запрос о размещении длины ответа в поле dstmsglen структуры struct _msg_info, которую заполняет вызов MsgReceivev(). Поле dstmsglen действительно только в случае, если данный флаг был установлен при создании канала.

_NTO_CHF_SENDER_LEN

Запрос о размещении длины исходного сообщения в поле srcmsglen структуры struct _msg_info, которую заполняет вызов MsgReceivev(). Поле srcmsglen действительно только в случае, если данный флаг был установлен при создании канала.

_NTO_CHF_THREAD_DEATH

Код импульса:
_PULSE_CODE_THREADDEATH
Значение импульса:
Идентификатор потока (tid)

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


Note: Если для канала установлен один или оба флага _NTO_CHF_COID_DISCONNECT или _NTO_CHF_THREAD_DEATH, ни один флаг не может быть установлен для любого другого канала в процессе.

_NTO_CHF_UNBLOCK

Код импульса:
_PULSE_CODE_UNBLOCK
Значение импульса:
Идентификатор получателя (rcvid)


Note: В большинстве случаев будет установлен флаг _NTO_CHF_UNBLOCK.

Доставляет импульс, когда поток, заблокированный на REPLY на канале, пытается разблокироваться до того, как на его сообщение будет дан ответ. Это происходит между MsgReceivev() и MsgReplyv() на сервере. Отправляющий поток может быть разблокирован из-за сигнала или таймаута ядра.

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

Установка бита _NTO_CHF_UNBLOCK в flags предотвращает ситуацию, когда поток, заблокированный на состоянии REPLY, разблокируется. Вместо этого в канал отправляется импульс, уведомляющий менеджер, что клиент желает разблокироваться. В случае сигнала, он будет отложен для клиентского потока. Когда менеджер отвечает, клиент разблокируется, в этом момент происходит обработка отложенных сигналов. С точки зрения клиента, вызов MsgSendv() нормально завершается, и любой сигнал может прийти после успешного вызова ядра.

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

Состояния блокировки

Данные вызовы не блокируются.

Возвращаемое значение:

ChannelCreate()
Идентификатор вновь созданного канала. При возникновении ошибки функция возвращает -1 и устанавливает errno.
ChannelCreate_r()
Идентификатор вновь созданного канала. Данная функция НЕ устанавливает errno. Если возникла ошибка, функция возвращает отрицательное значение из раздела ошибок.

Коды ошибок:

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

Классификация:

ЗОСРВ «Нейтрино»

Безопасность использования
Точка остановки потока
Нет
Обработчик прерываний
Нет
Обработчик сигналов
Да
В потоке
Да

Тематические ссылки:

ChannelDestroy(), close(), ConnectAttach(), ConnectDetach(), struct _msg_info, MsgReceivev(), MsgReplyv(), MsgSendv(), MsgSendPulse(), name_attach(), name_close(), name_open(), struct _pulse




Предыдущий раздел: Описание API системной библиотеки