next up previous contents
Next: Операции над очередями сообщений Up: Очереди сообщений. Previous: Создание очередей сообщений   Contents

Управление очередями сообщений

В справочной статье msgctl синтаксис данного системного вызова описан так:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgctl ( int msqid, int cmd, struct msqid_ds *buf);

При успешном завершении результат равен нулю; в случае неудачи возвращается -1.

В качестве аргумента msqid должен выступать идентификатор очереди сообщений, предварительно полученный при помощи системного вызова msgget.

Управляющее действие определяется значением аргумента cmd. Допустимых значений три:

Чтобы выполнить управляющее действие IPC_SET или IPC_RMID, процесс должен иметь действующий идентификатор пользователя, равный либо идентификаторам создателя или владельца очереди, либо идентификатору суперпользователя. Чтобы выполнить действие IPC_STAT, требуется право на чтение.

Ниже приведена программа-пример (рис. 18), иллюстрирующая управление очередью. В программе использованы следующие переменные:

Программа ведет себя следующим образом. Прежде всего предлагается ввести допустимый идентификатор очереди сообщений, который заносится в переменную msqid. Это значение требуется в каждом системном вызове msgctl. Затем нужно ввести код выбранного управляющего действия, который заносится в переменную command.

Если выбрано действие IPC_STAT (код 1), выполняется системный вызов и распечатывается информация о состоянии очереди; в программе распечатываются только те поля структуры, которые могут быть переустановлены. Если системный вызов завершается неудачей, распечатывается информация о состоянии очереди на момент последнего успешного выполнения системного вызова. Кроме того, выводится сообщение об ошибке и распечатывается значение переменной errno. Если системный вызов завершается успешно, выводится сообщение, уведомляющее об этом, и значение использованного идентификатора очереди сообщений.

Если выбрано действие IPC_SET (код 2), программа прежде всего получает информацию о текущем состоянии очереди сообщений с заданным идентификатором. Это необходимо, поскольку пример обеспечивает изменение только одного поля за один раз, в то время как системный вызов изменяет всю структуру целиком. Кроме того, если в одно из полей структуры, находящейся в области памяти пользователя, будет занесено некорректное значение, это может вызвать неудачи в выполнении управляющих действий, повторяющиеся до тех пор, пока значение поля не будет исправлено. Затем программа предлагает ввести код, соответствующий полю структуры, которое должно быть изменено. Этот код заносится в переменную choice. Далее, в зависимости от указанного поля, программа предлагает ввести то или иное новое значение. Значение заносится в соответствующее поле структуры данных, расположенной в области памяти пользователя, и выполняется системный вызов.

Если выбрано действие IPC_RMID (код 3), выполняется системный вызов, удаляющий из системы идентификатор msqid, очередь сообщений и ассоциированную с ней структуру данных. Отметим, что для выполнения этого управляющего действия аргумент buf не требуется, поэтому его значение может быть заменено нулем (NULL).

/* Программа иллюстрирует

возможности системного вызова msgctl()

(управление очередями сообщений) */

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

 

main ()

{

  extern int errno;

  int msqid, command, choice, rtrn;

  struct msqid_ds msqid_ds, *buf;

  buf = &msqid_ds;

  

  /* Ввести идентификатор и действие */

  printf ("Введите идентификатор msqid: ");

  scanf ("%d", &msqid);

  printf ("Введите номер требуемого действия:\n");

  printf (" IPC_STAT = 1\n");

  printf (" IPC_SET = 2\n");

  printf (" IPC_RMID = 3\n");

  printf (" Выбор = ");

  scanf ("%d", &command);

  

  /* Проверить значения */

  printf ("идентификатор = %d, действие = %d\n",

          msqid, command);

  switch (command) {

  case 1: /* Скопировать информацию

          о состоянии очереди сообщений

          в пользовательскую структуру

          и вывести ее */

          rtrn = msgctl (msqid, IPC_STAT, buf);

          printf ("\n Идентификатор пользователя = %d\n",

                  buf->msg_perm.uid);

          printf ("\n Идентификатор группы = %d\n",

                  buf->msg_perm.gid);

          printf ("\n Права на операции = 0%o\n",

                  buf->msg_perm.mode);

          printf ("\n Размер очереди в байтах = %d\n",

                  buf->msg_qbytes);

          break;

  case 2: /* Выбрать и изменить поле (поля)

          ассоциированной структуры данных */

          /* Сначала получить исходное значение

          структуры данных */

          rtrn = msgctl (msqid, IPC_STAT, buf);

          printf ("\nВведите номер поля, ");

          printf ("которое нужно изменить:\n");

          printf (" msg_perm.uid = 1\n");

          printf (" msg_perm.gid = 2\n");

          printf (" msg_perm.mode = 3\n");

          printf (" msg_qbytes = 4\n");

          printf (" Выбор = ");

          scanf ("%d", &choice);

          switch (choice) {

             case 1:

                     printf ("\nВведите ид-р пользователя: ");

                     scanf ("%d", &buf->msg_perm.uid);

                     printf ("\nИд-р пользователя = %d\n",

                             buf->msg_perm.uid);

                     break;

             case 2:

                     printf ("\nВведите ид-р группы: ");

                     scanf ("%d", &buf->msg_perm.gid);

                     printf ("\nИд-р группы = %d\n",

                             buf->msg_perm.uid);

                     break;

             case 3:

                     printf ("\nВведите восьмеричный код прав: ");

                     scanf ("%o", &buf->msg_perm.mode);

                     printf ("\nПрава на операции = 0%o\n",

                             buf->msg_perm.mode);

                     break;

             case 4:

                     printf ("\nВведите размер очереди = ");

                     scanf ("%d", &buf->msg_qbytes);

                     printf ("\nЧисло байт в очереди = %d\n",

                             buf->msg_qbytes);

                      break;

          }

 

          /* Внести изменения */

          rtrn = msgctl (msqid, IPC_SET, buf);

          break;

  case 3: /* Удалить идентификатор и

          ассоциированные с ним очередь

          сообщений и структуру данных */

          rtrn = msgctl (msqid, IPC_RMID, NULL);

}

  if (rtrn == -1) {

  /* Сообщить о неудачном завершении */

  printf ("\nmsgctl завершился неудачей!\n");

  printf ("\nКод ошибки = %d\n", errno);

  }

  else {

  /* При успешном завершении сообщить msqid */

  printf ("\nmsgctl завершился успешно,\n");

  printf ("идентификатор = %d\n", msqid);

  }

  exit (0);

}

Рис. 18. Пример управления очередью.


next up previous contents
Next: Операции над очередями сообщений Up: Очереди сообщений. Previous: Создание очередей сообщений   Contents
2003-12-09