A message queue is created using the msgget system call (Table 6.5).
Table 6.5. Summary of the msgget System Call.
Include File(s) |
|
Manual Section |
2 |
|
Summary |
int msgget (key_t key,int msgflg); |
|||
Return |
Success |
Failure |
Sets errno |
|
Nonnegative message queue identifierassociated with key |
1 |
Yes |
If the msgget system call is successful, a nonnegative integer is returned. This value is the message queue identifier and can be used in subsequent calls to reference the message queue. If the msgget system call fails, the value 1 is returned and the global variable errno is set appropriately to indicate the error (see Table 6.6). The value for the argument key can be specified directly by the user or generated using the ftok library function (as covered in the previous discussion). The value assigned to key is used by the operating system to produce a unique message queue identifier. The low-order bits of the msgflg argument are used to determine the access permissions for the message queue. Additional flags (e.g., IPC_CREAT, IPC_EXCL) may be OR ed with the permission value to indicate special creation conditions.
A new message queue is created if the defined constant IPC_PRIVATE is used as the key argument or if the IPC_CREAT flag is OR ed with the access permissions and no previously existing message queue is associated with the key value. If IPC_CREAT is specified (without IPC_EXCL) and the message queue already exists, msgget will not fail but will return the message queue identifier that is associated with the key value (Table 6.6).
Table 6.6. msgget Error Messages.
# |
Constant |
perror Message |
Explanation |
---|---|---|---|
2 |
EOENT |
No such file or directory |
Message queue identifier does not exist for this key and IPC_CREAT was not set. |
12 |
ENOMEM |
Cannot allocate memory |
Insufficient system memory to allocate the message queue. |
13 |
EACCES |
Permission denied |
Message queue identifier exits for this key , but requested operation is not allowed by current access permissions. |
17 |
EEXIST |
File exists |
Message queue identifier exists for this key , but the flags IPC_CREAT and IPC_EXCL are both set. |
28 |
ENOSPC |
No space left on device |
System imposed limit (MSGMNI) for the number of message queues has been reached. |
43 |
EIDRM |
Identifier removed |
Specified message queue is marked for removal. |
Program 6.2 generates five message queues with read/write access, uses the ipcs command (via a pipe) to display message queue status, and then removes the message queues.
Program 6.2 Generating message queues.
File : p6.2.cxx /* Message queue generation */ #define _GNU_SOURCE #include + #include #include #include #include #include 10 using namespace std; const int MAX=5; int <-- 1 main( ){ FILE *fin; + char buffer[PIPE_BUF], proj = 'A'; int i, n, mid[MAX]; key_t key; for (i = 0; i < MAX; ++i, ++proj) { key = ftok(".", proj); 20 if ((mid[i] = msgget(key, IPC_CREAT 0660)) == -1) { perror("Queue create"); return 1; } } + fin = popen("ipcs", "r"); <-- 2 while ((n = read(fileno(fin), buffer, PIPE_BUF)) > 0) write(fileno(stdout), buffer, n); pclose(fin); for (i = 0; i < MAX; ++i ) <-- 3 30 msgctl(mid[i], IPC_RMID, (struct msqid_ds *) 0); return 0; }
(1) Create five message queues.
(2) Use a named pipe to execute the ipcs command.
(3) Remove the five message queues.
When run on our system, this program produces the output in Figure 6.4, indicating that five message queues have been generated.
Figure 6.4 Output of Program 6.2.
linux$ p6.2 ------ Shared Memory Segments ------ key shmid owner perms bytes nattch status 0x00000000 25198594 root 666 247264 3 ------ Semaphore Arrays ------ key semid owner perms nsems status 0x00000000 65537 root 666 4 0x00000000 98306 root 666 16 0x00000000 131075 root 666 16 0x00000000 163844 root 666 16 ------ Message Queues ------ key msqid owner perms used-bytes messages 0x41153384 2260992 gray 660 0 0 0x42153384 2293761 gray 660 0 0 0x43153384 2326530 gray 660 0 0 0x44153384 2359299 gray 660 0 0 0x45153384 2392068 gray 660 0 0
When a message queue is created, a system message-queue data structure called msqid_ds is generated. This structure, maintained by the system, is defined in the system-dependent header file , which in turn is included by the header file . The msqid_ds structure for Linux is defined as
struct msqid_ds { struct ipc_perm msg_perm; /* structure describing operation permission */ __time_t msg_stime; /* time of last msgsnd command */ unsigned long int __unused1; __time_t msg_rtime; /* time of last msgrcv command */ unsigned long int __unused2; __time_t msg_ctime; /* time of last change */ unsigned long int __unused3; unsigned long int __msg_cbytes; /* current number of bytes on queue */ msgqnum_t msg_qnum; /* number of messages currently on queue */ msglen_t msg_qbytes; /* max number of bytes allowed on queue */ __pid_t msg_lspid; /* pid of last msgsnd() */ __pid_t msg_lrpid; /* pid of last msgrcv() */ unsigned long int __unused4; unsigned long int __unused5; };
However, conceptually (and in keeping with its original definition), the msqid_ds structure is considered to be as found in the header file :
struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue, unused */ struct msg *msg_last; /* last message in queue, unused */ __kernel_time_t msg_stime; /* last msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ unsigned long msg_lqbytes; /* ditto */ unsigned short msg_cbytes; /* current # of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ };
But, if we investigate even further, we find that what is actually implemented by the kernel is different still. A check of the kernel source code msg.c (usually found in /usr/src/linux-XX.XX.XX/ipc where XX are the version numbers for the particular operating system) for message queue implementation defines a kernel structure called msg_queue :
struct msg_queue { struct kern_ipc_perm q_perm; time_t q_stime; /* last msgsnd time */ time_t q_rtime; /* last msgrcv time */ time_t q_ctime; /* last change time */ unsigned long q_cbytes; /* current number of bytes on queue */ unsigned long q_qnum; /* number of messages in queue */ unsigned long q_qbytes; /* max number of bytes on queue */ pid_t q_lspid; /* pid of last msgsnd */ pid_t q_lrpid; /* last receive pid */ struct list_head q_messages; struct list_head q_receivers; struct list_head q_senders; };
While this all may seem a bit confusing at first, there is some commonality (e.g., the permission structure and reference to the message queue list). The discussion that follows is based on the conceptual definition as found in the header file .
The first member of the msqid_ds structure is the IPC permission structure discussed earlier. When the resource is allocated, the system sets, respectively, the msg_perm.cuid , msg_perm.uid , msg_perm.cgid , and msg_perm.gid members to the effective user and group ID of the invoking process. The low-order nine bits of msgflg (taken from the msgget call) are used to set the value in msg_perm.mode .
Next , in the msqid_ds structure are two pointers to the first and last messages in the queue. From a conceptual standpoint, the individual messages in the queue are structures of type msg , defined as
struct msg { struct msg *msg_next; /* ptr to next message on q */ long msg_type; /* message type */ ushort msg_ts; /* message text size */ short msg_spot; /* address of text message */ };
Individual messages are placed in a linked list by the system. Each msg structure contains four members: a reference to the next msg in the list, a long integer, user-assigned value denoting the message type, a short integer value indicating the size in bytes of the message (maximum 8192 bytes), and a reference to the actual message. When the message queue is created the system sets the msqid_ds members msg_qnum , msg_lspid , msg_lrpid , msg_stime , and msg_rtime to 0. The member msg_ctime is set to the current time, and msg_qbytes is set to the system limit. Thus, conceptually , we can envision a message queue with N items as being similar to Figure 6.5.
Figure 6.5. A message queue with N items.
Programs and Processes
Processing Environment
Using Processes
Primitive Communications
Pipes
Message Queues
Semaphores
Shared Memory
Remote Procedure Calls
Sockets
Threads
Appendix A. Using Linux Manual Pages
Appendix B. UNIX Error Messages
Appendix C. RPC Syntax Diagrams
Appendix D. Profiling Programs