Next | Prev | Up | Top | Contents | Index

Controlling Message Queues: msgctl()

This section gives a detailed description of using the msgctl() system call and an example program that exercises its capabilities. The prototype of msgctl() is as follows (see also the msgctl(2) reference page):

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

On successful completion, the function returns zero; when unsuccessful, it returns a -1.

The msqid variable must be a nonnegative, integer value previously established as a message queue by using msgget().

The cmd argument can be replaced by one of the following control commands (flags):

IPC_STATReturn the status information contained in the associated data structure for the specified msqid, and place it in the data structure pointed to by the *buf pointer in the user memory area.
IPC_SETFor the specified msqid, set the effective user and group identification, operation permissions, and the number of bytes for the message queue.
IPC_RMIDRemove the specified msqid along with its associated message queue and data structure.

A process must have an effective user identification of OWNER/CREATOR or superuser to perform an IPC_SET or IPC_RMID control command. Read permission is required to perform the IPC_STAT control command.

The details of this system call are discussed in the example program for it. If you have trouble understanding the logic manipulations in this program, read the "Getting Message Queues With msgget()" section of this chapter; it goes into more detail than would be practical to do for every system call.


Example Program

The example program in this section (Example 2-5) is a menu-driven program that exercises all possible combinations of the msgctl() system call.

From studying this program, you can observe the method of passing arguments and receiving return values. The user-written program requirements are pointed out.

This program begins (lines 5-9) by including the required header files as specified by the msgctl(2) reference page. Note in this program that errno is declared as an external variable, and therefore, the errno.h header file does not have to be included.

Variable and structure names have been chosen to be as close as possible to those in the synopsis for the system call. Their declarations are self-explanatory. The variables declared for this program and their purposes are as follows:

uid The IPC_SET value for the effective user identification
gidThe IPC_SET value for the effective group identification
modeThe IPC_SET value for the operation permissions
bytesThe IPC_SET value for the number of bytes in the message queue (msg_qbytes)
rtrnThe return integer value from the system call
msqidThe message queue identifier
commandThe code for the desired control command
choiceA variable used to determine which member is to be changed for the IPC_SET control command
msqid_dsA variable that receives the specified message queue identifier's data structure when an IPC_STAT control command is performed
buf A variable that bases the data structure in the user memory area where the IPC_STAT control command is to place its return values or where the IPC_SET command gets the values to set

Note that the msqid_ds data structure in this program (line 16) uses the data structure located in the msg.h header file of the same name as a template for its declaration. This is a perfect example of the advantage of local variables.

The next important thing to observe is that although the *buf pointer is declared to be a pointer to a data structure of the msqid_ds type, it must also be initialized to contain the address of the user memory area data structure (line 17). Now that all of the required declarations have been explained for this program, this is how it works.

First, the program prompts for a valid message queue identifier, which is stored in the msqid variable (lines 19, 20). This is required for every msgctl() system call.

Then the code for the desired control command must be entered (lines 21-27), and it is stored in the command variable. The code is tested to determine the control command for subsequent processing.

If the IPC_STAT control command is selected (case 1), the system call is performed (lines 37, 38) and the status information returned is printed out (lines 39-46); only the members that can be set are printed out in this program. Note that if the system call is unsuccessful (line 106), the status information of the last successful call is printed out. In addition, an error message is displayed and the errno variable is printed out (lines 108, 109). If the system call is successful, a message indicates this along with the message queue identifier used (lines 111-114).

If the IPC_SET control command is selected (case 2), the first thing done is to get the current status information for the message queue identifier specified (lines 50-52). This is necessary because this example program provides for changing only one member at a time, and the system call changes all of them. Also, if an invalid value happened to be stored in the user memory area for one of these members, it would cause repetitive failures for this control command until corrected. The next thing the program does is to prompt for a code corresponding to the member to be changed (lines 53-59). This code is stored in the choice variable (line 60). Now, depending upon the member picked, the program prompts for the new value (lines 66-95). The value is placed in the appropriate member in the user memory area data structure, and the system call is made (lines 96-98). Depending upon success or failure, the program returns the same messages as for IPC_STAT above.

If the IPC_RMID control command (code 3) is selected, the system call is performed (lines 100-103), and the msqid along with its associated message queue and data structure are removed from the UNIX operating system. Note that the *buf pointer is not required as an argument to perform this control command, and its value can be zero or NULL. Depending upon the success or failure, the program returns the same messages as for the other control commands.

The example program for the msgctl() system call follows in Example 2-5.

Example 2-5 : msgctl() System Call Example

1  /*This is a program to illustrate 
2  *the message control, msgctl(), 
3  *system call capabilities. 
4  */
5  /*Include necessary header files.*/ 
6  #include <stdio.h> 
7  #include <sys/types.h>
8  #include <sys/ipc.h>
9  #include <sys/msg.h>
10  /*Start of main C language program*/
11  main()
12  {
13    extern int errno; 
14    int uid, gid, mode, bytes; 
15    int rtrn, msqid, command, choice; 
16    struct msqid_ds msqid_ds, *buf;
17    buf = &msqid_ds;
18    /*Get the msqid, and command.*/ 
19    printf("Enter the msqid = "); 
20    scanf("%d", &msqid); 
21    printf("\nEnter the number for\n"); 
22    printf("the desired command:\n");
23    printf("IPC_STAT = 1\n"); 24 printf("IPC_SET = 2\n");
25    printf("IPC_RMID = 3\n"); 
26    printf("Entry = ");
27    scanf("%d", &command);
28    /*Check the values.*/
29   printf (\nmsqid =%d, command = %\n", 30 msqid, command);
31    switch (command)
32    { 
33    case 1: /*Use msgctl() to duplicate
34      the data structure for
35        msqid in the msqid_ds area pointed 
36        to by buf and then print it out.*/ 
37      rtrn = msgctl(msqid, IPC_STAT,
38       buf);
39      printf ("\nThe USER ID = %d\n",
40        buf->msg_perm.uid);
41      printf ("The GROUP ID = %d\n", 
42        buf->msg_perm.gid); 
43      printf ("The operation permissions = 0%o\n", 
44        buf->msg_perm.mode); 
45      printf ("The msg_qbytes = %d\n", 
46        buf->msg_qbytes); 
47      break; 
48     case 2: /*Select and change the desired
49           member(s) of the data structure.*/ 
50        /*Get the original data for this msqid 
51           data structure first.*/
52        rtrn = msgctl(msqid, IPC_STAT, buf); 
53        printf("\nEnter the number for the\n"); 
54        printf("member to be changed:\n");
55        printf("msg_perm.uid = 1\n"); 
56        printf("msg_perm.gid = 2\n"); 
57        printf("msg_perm.mode = 3\n"); 
58        printf("msg_qbytes = 4\n"); 
59        printf("Entry = ");
60        scanf("%d", &choice);
61        /*Only one choice is allowed per pass 
62           as an illegal entry will
63           cause repetitive failures until 
64           msqid_ds is updated with 
65           IPC_STAT.*/
66        switch(choice){
67        case 1: 
68          printf("\nEnter USER ID = "); 
69          scanf ("%d", &uid); 
70          buf->msg_perm.uid = uid; 
71          printf("\nUSER ID = %d\n", 
72            buf->msg_perm.uid); 
73          break; 
74        case 2: 
75          printf("\nEnter GROUP ID = ");
76          scanf("%d", &gid); 
77          buf->msg_perm.gid = gid;
78          printf("\nGROUP ID = %d\n",
79            buf->msg_perm.gid); 
80          break; 
81        case 3: 
82          printf("\nEnter MODE = "); 
83          scanf("%o", &mode); 
84          buf->msg_perm.mode = mode; 
85          printf("\nMODE = 0%o\n", 
86            buf->msg_perm.mode); 
87          break;
88        case 4: 
89          printf("\nEnter msq_bytes = "); 
90          scanf("%d", &bytes); 
91          buf->msg_qbytes = bytes; 
92          printf("\nmsg_qbytes = %d\n", 
93          buf->msg_qbytes); 
94          break;
95        }
96        /*Do the change.*/ 
97        rtrn = msgctl(msqid, IPC_SET, 
98          buf); 
99        break;
100     case 3: /*Remove the msqid along with its 
101         associated message queue 
102         and data structure.*/ 
103       rtrn = msgctl(msqid, IPC_RMID, NULL); 
104     } 
105     /*Perform the following if call is unsuccessful.*/ 
106     if(rtrn == -1) 
107     { 
108       printf ("\nThe msgctl system call failed!\n"); 
109       printf ("The error number = %d\n", errno); 
110     } 
111     /*Return the msqid upon successful completion.*/ 
112     else 
113       printf ("\nMsgctl was successful for msqid = %d\n", 
114         msqid);
115     exit (0); 
116  }

Next | Prev | Up | Top | Contents | Index