Архитектура операционной системы UNIX
Шрифт:
11.2.1 Сообщения
С сообщениями работают четыре системных функции: msgget, которая возвращает (и в некоторых случаях создает) дескриптор сообщения, определяющий очередь сообщений и используемый другими системными функциями, msgctl, которая устанавливает и возвращает связанные с дескриптором сообщений параметры или удаляет дескрипторы, msgsnd, которая посылает сообщение, и msgrcv, которая получает сообщение.
Синтаксис вызова системной функции msgget:
msgqid = msgget(key, flag);
где msgqid — возвращаемый функцией дескриптор, а key и flag имеют ту же семантику, что и в системной функции
• Указатели на первое и последнее сообщение в списке;
• Количество сообщений и общий объем информации в списке в байтах;
• Максимальная емкость списка в байтах;
• Идентификаторы процессов, пославших и принявших сообщения последними;
• Поля, указывающие время последнего выполнения функций msgsnd, msgrcv и msgctl.
Когда пользователь вызывает функцию msgget для того, чтобы создать новый дескриптор, ядро просматривает массив очередей сообщений в поисках существующей очереди с указанным идентификатором. Если такой очереди нет, ядро выделяет новую очередь, инициализирует ее и возвращает идентификатор пользователю. В противном случае ядро проверяет наличие необходимых прав доступа и завершает выполнение функции.
Для посылки сообщения процесс использует системную функцию msgsnd:
msgsnd(msgqid, msg, count, flag);
где msgqid — дескриптор очереди сообщений, обычно возвращаемый функцией msgget, msg — указатель на структуру, состоящую из типа в виде назначаемого пользователем целого числа и массива символов, count — размер информационного массива, flag — действие, предпринимаемое ядром в случае переполнения внутреннего буферного пространства.
Рисунок 11.4. Алгоритм посылки сообщения
Ядро проверяет (Рисунок 11.4), имеется ли у посылающего сообщение процесса разрешения на запись по указанному дескриптору, не выходит ли
Рисунок 11.5. Структуры данных, используемые в организации сообщений
Рассмотрим программу, представленную на Рисунке 11.6. Процесс вызывает функцию msgget для того, чтобы получить дескриптор для записи с идентификатором MSGKEY. Длина сообщения принимается равной 256 байт, хотя используется только первое поле целого типа, в область текста сообщения копируется идентификатор процесса, типу сообщения присваивается значение 1, после чего вызывается функция msgsnd для посылки сообщения. Мы вернемся к этому примеру позже.
Процесс получает сообщения, вызывая функцию msgrcv по следующему формату:
count = msgrcv(id, msg, maxcount, type, flag);
где id — дескриптор сообщения, msg — адрес пользовательской структуры, которая будет содержать полученное сообщение, maxcount — размер структуры msg, type — тип считываемого сообщения, flag — действие, предпринимаемое ядром в том случае, если в очереди сообщений нет. В переменной count пользователю возвращается число прочитанных байт сообщения.
Ядро проверяет (Рисунок 11.7), имеет ли пользователь необходимые права доступа к очереди сообщений. Если тип считываемого сообщения имеет нулевое значение, ядро ищет первое по счету сообщение в связном списке. Если его размер меньше или равен размеру, указанному пользователем, ядро копирует текст сообщения в пользовательскую структуру и соответствующим образом настраивает свои внутренние структуры: уменьшает счетчик сообщений в очереди и суммарный объем информации в байтах, запоминает время получения сообщения и идентификатор процесса-получателя, перестраивает связный список и освобождает место в системном пространстве, где хранился текст сообщения. Если какие-либо процессы, ожидавшие получения сообщения, находились в состоянии приостанова из-за отсутствия свободного места в списке, ядро выводит их из этого состояния. Если размер сообщения превышает значение maxcount, указанное пользователем, ядро посылает системной функции уведомление об ошибке и оставляет сообщение в очереди. Если, тем не менее, процесс игнорирует ограничения на размер (в поле flag установлен бит MSG_NOERROR), ядро обрезает сообщение, возвращает запрошенное количество байт и удаляет сообщение из списка целиком.