Once we have the queue identifier, we can begin performing operations on it. To deliver a message to a queue, you use the msgsnd system call:
SYSTEM CALL: msgsnd(); PROTOTYPE: int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz, int msgflg ); RETURNS: 0 on success -1 on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted) EACCES (permission denied, no write permission) EFAULT (msgp address isn't accessable - invalid) EIDRM (The message queue has been removed) EINTR (Received a signal while waiting to write) EINVAL (Invalid message queue identifier, nonpositive message type, or invalid message size) ENOMEM (Not enough memory to copy message buffer) NOTES:
The msgflg argument can be set to 0 (ignored), or:
If the message queue is full, then the message is not written to the queue, and control is returned to the calling process. If not specified, then the calling process will suspend (block) until the message can be written.
Let's create another wrapper function for sending messages:
int send_message( int qid, struct mymsgbuf *qbuf ) { int result, length; /* The length is essentially the size of the structure minus sizeof(mtype) */ length = sizeof(struct mymsgbuf) - sizeof(long); if((result = msgsnd( qid, qbuf, length, 0)) == -1) { return(-1); } return(result); }
#include <stdio.h> #include <stdlib.h> #include <linux/ipc.h> #include <linux/msg.h> main() { int qid; key_t msgkey; struct mymsgbuf { long mtype; /* Message type */ int request; /* Work request number */ double salary; /* Employee's salary */ } msg; /* Generate our IPC key value */ msgkey = ftok(".", 'm'); /* Open/create the queue */ if(( qid = open_queue( msgkey)) == -1) { perror("open_queue"); exit(1); } /* Load up the message with arbitrary test data */ msg.mtype = 1; /* Message type must be a positive number! */ msg.request = 1; /* Data element #1 */ msg.salary = 1000.00; /* Data element #2 (my yearly salary!) */ /* Bombs away! */ if((send_message( qid, &msg )) == -1) { perror("send_message"); exit(1); } }
Now that we have a message on our queue, try the ipcs command to view the status of your queue. Now let's turn the discussion to actually retrieving the message from the queue. To do this, you use the msgrcv() system call:
SYSTEM CALL: msgrcv(); PROTOTYPE: int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz, long mtype, int msgflg ); RETURNS: Number of bytes copied into message buffer -1 on error: errno = E2BIG (Message length is greater than msgsz, no MSG_NOERROR) EACCES (No read permission) EFAULT (Address pointed to by msgp is invalid) EIDRM (Queue was removed during retrieval) EINTR (Interrupted by arriving signal) EINVAL (msgqid invalid, or msgsz less than 0) ENOMSG (IPC_NOWAIT asserted, and no message exists in the queue to satisfy the request) NOTES:
msgsz = sizeof(struct mymsgbuf) - sizeof(long);
If IPC_NOWAIT is passed as a flag, and no messages are available, the call returns ENOMSG to the calling process. Otherwise, the calling process blocks until a message arrives in the queue that satisfies the msgrcv() parameters. If the queue is deleted while a client is waiting on a message, EIDRM is returned. EINTR is returned if a signal is caught while the process is in the middle of blocking, and waiting for a message to arrive.
Let's examine a quick wrapper function for retrieving a message from our queue:
int read_message( int qid, long type, struct mymsgbuf *qbuf ) { int result, length; /* The length is essentially the size of the structure minus sizeof(mtype) */ length = sizeof(struct mymsgbuf) - sizeof(long); if((result = msgrcv( qid, qbuf, length, type, 0)) == -1) { return(-1); } return(result); }
The MSG_NOERROR bit in the msgflg argument provides some additional capabilities. If the size of the physical message data is greater than msgsz, and MSG_NOERROR is asserted, then the message is truncated, and only msgsz bytes are returned. Normally, the msgrcv() system call returns -1 (E2BIG), and the message will remain on the queue for later retrieval. This behavior can used to create another wrapper function, which will allow us to ``peek'' inside the queue, to see if a message has arrived that satisfies our request:
int peek_message( int qid, long type ) { int result, length; if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT)) == -1) { if(errno == E2BIG) return(TRUE); } return(FALSE); }