Cинтаксис системного вызова msgget выглядит так:
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget ( key_t key,int msgflg);
Целочисленное значение, возвращаемое в случае успешного завершения системного вызова, есть идентификатор очереди сообщений (msqid). В случае неудачи результат равен -1.
Новый идентификатор msqid, очередь сообщений и ассоциированная с ней структура данных выделяются в каждом из двух случаев:
Права на операции | Восьмеричное значение |
Чтение для владельца | 0400 |
Запись для владельца | 0200 |
Чтение для группы | 0040 |
Запись для группы | 0020 |
Чтение для остальных | 0004 |
Запись для остальных | 0002 |
В каждом конкретном случае нужная комбинация прав задается как результат операции побитного ИЛИ для значений, соответствующих элементарным правам. Так, например, правам на чтение и запись для владельца и на чтение для членов группы и прочих пользователей соответствует восьмеричное число 0644. Следует отметить полную аналогию с правами доступа к файлам.
Флаги определены во включаемом файле <sys/ipc.h>. В табл. 3 сведены мнемонические имена флагов и соответствующие им восьмеричные значения:
Значение аргумента msgflg в целом является, следовательно, результатом операции побитного ИЛИ (операция | в языке C) для прав на выполнение операций и флагов, например:
msqid = msgget (key, (IPC_CREAT | IPC_EXCL | 0400));
msqid = msgget (IPC_PRIVATE, msgflg);
приведет к попытке выделения нового идентификатора очереди сообщений
и ассоциированной информации, независимо от значения аргумента msgflg.
Попытка может быть неудачной только из-за превышения системного лимита
на общее число очередей сообщений, задаваемого настраиваемым параметром
MSGMNI.
При использовании флага IPC_EXCL в сочетании с IPC_CREAT системный вызов msgget завершается неудачей в том и только в том случае, когда с указанным ключом key уже ассоциирован идентификатор. Флаг IPC_EXCL необходим, чтобы предотвратить ситуацию процесса, когда надежда получить новый (уникальный) идентификатор очереди сообщений не сбывается. Иными словами, когда используются и IPC_CREAT и IPC_EXCL, при успешном завершении системного вызова обязательно возвращается новый идентификатор msqid.
В файле справки по msgget описывается начальное значение ассоциированной структуры данных, формируемое после успешного завершения системного вызова. Там же содержится перечень условий, приводящих к ошибкам, и соответствующих им мнемонических имен для значений переменной errno.
Программа-пример для msgget, приведенная ниже, управляется посредством меню. Она позволяет поупражняться со всевозможными комбинациями системного вызова msgget, проследить, как передаются аргументы и получаются результаты. Имена переменных выбраны максимально близкими к именам, используемым в спецификации синтаксиса системного вызова, что облегчает чтение программы.
Выполнение программы начинается с приглашения ввести шестнадцатеричный ключ key, восьмеричный код прав на операции и, наконец, выбираемую при помощи меню комбинацию флагов. В меню предлагаются все возможные комбинации, даже бессмысленные, что позволяет при желании проследить за реакцией на ошибку. Затем выбранные флаги комбинируются с правами на операции, после чего выполняется системный вызов, результат которого заносится в переменную msqid. Если значение msqid равно -1, выдается сообщение об ошибке и выводится значение внешней переменной errno. Если ошибки не произошло, выводится значение полученного идентификатора очереди сообщений:
возможности системного вызова msgget()
(получение идентификатора очереди сообщений) */
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
main ()
{
key_t key; /* Тип описан как целое */
int opperm, flags; /* Права на операции и флаги */
int msgflg, msqid;
/* Ввести требуемый ключ */
printf ("\nВведите шестнадцатеричный ключ: ");
scanf ("%x", &key);
/* Ввести права на операции */
printf ("\nВведите права на операции ");
printf ("в восьмеричной записи: ");
scanf ("%o", &opperm);
/* Установить требуемые флаги */
printf ("\nВведите код, соответствущий ");
printf ("нужной комбинации флагов:\n");
printf (" Нет флагов = 0\n");
printf (" IPC_CREAT = 1\n");
printf (" IPC_EXCL = 2\n");
printf (" IPC_CREAT и IPC_EXCL = 3\n");
printf (" Выбор = ");
/* Получить флаги, которые нужно установить */
scanf ("%d", &flags);
/* Проверить значения */
printf ("\nключ = 0x%x, права = 0%o, флаги = %d\n",
key, opperm, flags);
/* Объединить флаги с правами на операции */
switch (flags) {
case 0: /* Флаги не устанавливать */
msgflg = (opperm | 0);
break;
case 1: /* Установить флаг IPC_CREAT */
msgflg = (opperm | IPC_CREAT);
break;
case 2: /* Установить флаг IPC_EXCL */
msgflg = (opperm | IPC_EXCL);
break;
case 3: /* Установить оба флага */
msgflg = (opperm | IPC_CREAT | IPC_EXCL);
}
/* Выполнить системный вызов msgget */
msqid = msgget (key, msgflg);
if (msqid == -1) {
/* Сообщить о неудачном завершении */
printf ("\nmsgget завершился неудачей!\n"
printf ("Код ошибки = %d\n", errno);
}
else
/* При успешном завершении сообщить msqid */
printf ("\nИдентификатор msqid = %d\n", msqid);
exit (0);
}