Creating a Message Queue

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

EXERCISE

Run Program 6.2 several times in rapid succession. Look at the message queue identifiers that are produced. What appears to be the numbering scheme the system is using? Hint : Look in the header file . Can you find any rationale for this approach? Now add the statement sleep(5); after the statement pclose(fin); on line 28. Recompile the program and invoke the program twice, placing it in the background each time. Assuming the program is still called p6.2 , this can be accomplished by

linux$ p6.2 & p6.2 &

Count the number of message queues generated and explain why there are not 10 present.

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.

Категории