Основы операционных систем. Практикум

       

Реализация примитивов send и receive. Системные вызовы msgsnd() и msgrcv()


Для выполнения примитива send используется системный вызов msgsnd(), копирующий пользовательское сообщение в очередь сообщений, заданную IPC-дескриптором. При изучении описания этого вызова обратите особое внимание на следующие моменты:

  • Тип данных struct msgbuf не является типом данных для пользовательских сообщений, а представляет собой лишь шаблон для создания таких типов. Пользователь сам должен создать структуру для своих сообщений, в которой первым полем должна быть переменная типа long, содержащая положительное значение типа сообщения.
  • В качестве третьего параметра – длины сообщения – указывается не вся длина структуры данных, соответствующей сообщению, а только длина полезной информации, т. е. информации, располагающейся в структуре данных после типа сообщения. Это значение может быть и равным 0 в случае, когда вся полезная информация заключается в самом факте прихода сообщения (сообщение используется как сигнальное средство связи).
  • В материалах семинаров мы, как правило, будем использовать нулевое значение флага системного вызова, которое приводит к блокировке процесса при отсутствии свободного места в очереди сообщений.

Системный вызов msgsnd()

Прототип системного вызова

#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h>

int msgsnd(int msqid, struct msgbuf *ptr, int length, int flag);

Описание системного вызова

Системный вызов msgsnd предназначен для помещения сообщения в очередь сообщений, т. е. является реализацией примитива send.

Параметр msqid является дескриптором System V IPC для очереди, в которую отправляется сообщение, т. е. значением, которое вернул системный вызов msgget() при создании очереди или при ее поиске по ключу.

Структура struct msgbuf описана в файле <sys/msg.h> как

struct msgbuf { long mtype; char mtext[1]; };

Она представляет собой некоторый шаблон структуры сообщения пользователя. Сообщение пользователя – это структура, первый элемент которой обязательно имеет тип long и содержит тип сообщения, а далее следует информативная часть теоретически произвольной длины (практически в Linux она ограничена размером 4080 байт и может быть еще уменьшена системным администратором), содержащая собственно суть сообщения. Например:

struct mymsgbuf { long mtype; char mtext[1024]; } mybuf;

При этом информация вовсе не обязана быть текстовой, например:

struct mymsgbuf { long mtype; struct { int iinfo; float finfo; } info; } mybuf;

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

Параметр flag может принимать два значения: 0 и IPC_NOWAIT. Если значение флага равно 0, и в очереди не хватает места для того, чтобы поместить сообщение, то системный вызов блокируется до тех пор, пока не освободится место. При значении флага IPC_NOWAIT системный вызов в этой ситуации не блокируется, а констатирует возникновение ошибки с установлением значения переменной errno, описанной в файле <errno.h>, равным EAGAIN.

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



Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

<
Примитив receive реализуется системным вызовом msgrcv(). При изучении описания этого вызова нужно обратить особое внимание на следующие моменты:

  • Тип данных struct msgbuf, как и для вызова msgsnd(), является лишь шаблоном для пользовательского типа данных.
  • Способ выбора сообщения (см. раздел "Очереди сообщений в UNIX как составная часть System V IPC" текущего семинара) задается нулевым, положительным или отрицательным значением параметра type. Точное значение типа выбранного сообщения можно определить из соответствующего поля структуры, в которую системный вызов скопирует сообщение.
  • Системный вызов возвращает длину только полезной части скопированной информации, т. е. информации, расположенной в структуре после поля типа сообщения.
  • Выбранное сообщение удаляется из очереди сообщений.
  • В качестве параметра length указывается максимальная длина полезной части информации, которая может быть размещена в структуре, адресованной параметром ptr.
  • В материалах семинаров мы будем, как правило, пользоваться нулевым значением флагов для системного вызова, которое приводит к блокировке процесса в случае отсутствия в очереди сообщений с запрошенным типом и к ошибочной ситуации в случае, когда длина информативной части выбранного сообщения превышает длину, специфицированную в параметре length.


Системный вызов msgrcv()

Прототип системного вызова

#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h>

int msgrcv(int msqid, struct msgbuf *ptr, int length, long type, int flag);

Описание системного вызова

Системный вызов msgrcv предназначен для получения сообщения из очереди сообщений, т. е. является реализацией примитива receive.

Способ выборкиЗначение параметра type
В порядке FIFO, независимо от типа сообщения0
В порядке FIFO для сообщений с типом n n
Первым выбирается сообщение с минимальным типом, не превышающим значения n, пришедшее ранее всех других сообщений с тем же типом-n
Параметр msqid является дескриптором System V IPC для очереди, из которой должно быть получено сообщение, т. е. значением, которое вернул системный вызов msgget() при создании очереди или при ее поиске по ключу.

Параметр type определяет способ выборки сообщения из очереди следующим образом

Структура struct msgbuf описана в файле <sys/msg.h> как

struct msgbuf { long mtype; char mtext[1]; };

Она представляет собой некоторый шаблон структуры сообщения пользователя. Сообщение пользователя – это структура, первый элемент которой обязательно имеет тип long и содержит тип сообщения, а далее следует информативная часть теоретически произвольной длины (практически в Linux она ограничена размером 4080 байт и может быть еще уменьшена системным администратором), содержащая собственно суть сообщения. Например:

struct mymsgbuf { long mtype; char mtext[1024]; } mybuf;

При этом информация вовсе не обязана быть текстовой, например:

struct mymsgbuf { long mtype; struct { int iinfo; float finfo; } info; } mybuf;

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

В случае удачи системный вызов копирует выбранное сообщение из очереди сообщений по адресу, указанному в параметре ptr, одновременно удаляя его из очереди сообщений.

Параметр flag может принимать значение 0 или быть какой-либо комбинацией флагов IPC_NOWAIT и MSG_NOERROR. Если флаг IPC_NOWAIT не установлен и очередь сообщений пуста или в ней нет сообщений с заказанным типом, то системный вызов блокируется до появления запрошенного сообщения. При установлении флага IPC_NOWAIT системный вызов в этой ситуации не блокируется, а констатирует возникновение ошибки с установлением значения переменной errno, описанной в файле <errno.h>, равным EAGAIN. Если действительная длина полезной части информации в выбранном сообщении превышает значение, указанное в параметре length и флаг MSG_NOERROR не установлен, то выборка сообщения не производится, и фиксируется наличие ошибочной ситуации. Если флаг MSG_NOERROR установлен, то в этом случае ошибки не возникает, а сообщение копируется в сокращенном виде.

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

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

ipcs -l


Содержание раздела