parameter determine the order in which msgrcv removes messages from the queue.

Team-FLY

15.4 POSIX:XSI Message Queues

The message queue is a POSIX:XSI interprocess communication mechanism that allows a process to send and receive messages from other processes. The data structures for message queues are defined in sys/msg.h . The major data structure for message queues is msqid_ds , which has the following members .

 struct ipc_perm msg_perm; /* operation permission structure */ msgqnum_t msg_qnum;       /* number of messages currently in queue */ msglen_t msg_qbytes;      /* maximum bytes allowed in queue */ pid_t msg_lspid;          /* process ID of msgsnd */ pid_t msg_lrpid;          /* process ID of msgrcv */ time_t msg_stime;         /* time of last msgsnd */ time_t msg_rtime;         /* time of last msgrcv */ time_t msg_ctime;         /* time of last msgctl */ 

The msgqnum_t data type holds the number of messages in the message queue; the msglen_t type holds the number of bytes allowed in a message queue. Both types must be at least as large as an unsigned short .

15.4.1 Accessing a message queue

The msgget function returns the message queue identifier associated with the key parameter. It creates the identifier if either the key is IPC_PRIVATE or msgflg & IPC_CREAT is nonzero and no message queue or identifier is already associated with key .

  SYNOPSIS  #include <sys/msg.h>     int msgget(key_t key, int msgflg);  POSIX:XSI  

If successful, msgget returns a nonnegative integer corresponding to the message queue identifier. If unsuccessful , msgget returns 1 and sets errno . The following table lists the mandatory errors for msgget .

errno

cause

EACCES

message queue exists for key , but permission denied

EEXIST

message queue exists for key , but ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) != 0

ENOENT

message queue does not exist for key , but (msgflg & IPC_CREAT) == 0

ENOSPC

systemwide limit on message queues would be exceeded

Example 15.14

Create a new message queue.

 #define PERMS (S_IRUSR  S_IWUSR) int msqid; if ((msqid = msgget(IPC_PRIVATE, PERMS)) == -1)    perror("Failed to create new private message queue"); 

After obtaining access to a message queue with msgget , a program inserts messages into the queue with msgsnd . The msqid parameter identifies the message queue, and the msgp parameter points to a user -defined buffer that contains the message to be sent, as described below. The msgsz parameter specifies the actual size of the message text. The msgflg parameter specifies actions to be taken under various conditions.

  SYNOPSIS  #include <sys/msg.h>    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);  POSIX:XSI  

If successful, msgsnd returns 0. If unsuccessful, msgsnd returns 1 and sets errno . The following table lists the mandatory errors for msgsnd .

errno

cause

EACCES

operation is denied to the caller

EAGAIN

operation would block the process, but (msgflg & IPC_NOWAIT) != 0

EIDRM

msqid has been removed from the system

EINTR

msgsnd was interrupted by a signal

EINVAL

msqid is invalid, the message type is < 1, or msgsz is out of range

The msgp parameter points to a user-defined buffer whose first member must be a long specifying the type of message, followed by space for the text of the message. The structure might be defined as follows .

 struct mymsg{    long mtype;    /* message type */    char mtext[1]; /* message text */ } mymsg_t; 

The message type must be greater than 0. The user can assign message types in any way appropriate to the application.

Here are the steps needed to send the string mymessage to a message queue.

  1. Allocate a buffer, mbuf , which is of type mymsg_t and size

     sizeof(mymsg_t) + strlen(mymessage). 
  2. Copy mymessage into the mbuf->mtext member.

  3. Set the message type in the mbuf->mtype member.

  4. Send the message.

  5. Free mbuf .

Remember to check for errors and to free mbuf if an error occurs. Code for this is provided in Program 15.9, discussed later.

A program can remove a message from a message queue with msgrcv . The msqid parameter identifies the message queue, and the msgp parameter points to a user-defined buffer for holding the message to be retrieved. The format of msgp is as described above for msgsnd . The msgsz parameter specifies the actual size of the message text. The msgtyp parameter can be used by the receiver for message selection. The msgflg specifies actions to be taken under various conditions.

  SYNOPSIS  #include <sys/msg.h>    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz,                   long msgtyp, int msgflg);  POSIX:XSI  

If successful, msgrcv returns the number of bytes in the text of the message. If unsuccessful, msgrcv returns (ssize_t) 1 and sets errno . The following table lists the mandatory errors for msgrcv .

errno

cause

E2BIG

value of the mtext member of msgp is greater than msgsize and (msgflg & MSG_NOERROR) == 0

EACCES

operation is denied to the caller

EIDRM

msqid has been removed from the system

EINTR

msgrcv was interrupted by a signal

EINVAL

value of msqid is invalid

ENOMSG

queue does not contain a message of requested type and (msgflg & IPC_NOWAIT) != 0

Table 15.4 shows how msgrcv uses the msgtyp parameter to determine the order in which it removes messages from the queue.

Use msgctl to deallocate or change permissions for the message queue identified by msqid . The cmd parameter specifies the action to be taken as listed in Table 15.5. The msgctl function uses its buf parameter to write or read state information, depending on cmd .

Table 15.4. The POSIX:XSI values for the msgtyp parameter determine the order in which msgrcv removes messages from the queue.

msgtyp

action

remove first message from queue

> 0

remove first message of type msgtyp from the queue

< 0

remove first message of lowest type that is less than or equal to the absolute value of msgtyp

Table 15.5. POSIX:XSI values for the cmd parameter of msgctl .

cmd

description

IPC_RMID

remove the message queue msqid and destroy the corresponding msqid_ds

IPC_SET

set members of the msqid_ds data structure from buf

IPC_STAT

copy members of the msqid_ds data structure into buf

  SYNOPSIS  #include <sys/msg.h>     int msgctl(int msqid, int cmd, struct msqid_ds *buf);  POSIX:XSI  

If successful, msgctl returns 0. If unsuccessful, msgctl returns 1 and sets errno . The following table lists the mandatory errors for msgctl .

errno

cause

EACCES

cmd is IPC_STAT and the caller does not have read permission

EINVAL

msqid or cmd is invalid

EPERM

cmd is IPC_RMID or IPC_SET and caller does not have privileges

Program 15.9 contains utilities for accessing a message queue similar to that of Program 15.6, but simpler because no initialization or synchronization is needed. Each process should call the initqueue function before accessing the message queue. The msgprintf function has syntax similar to printf for putting formatted messages in the queue. The msgwrite function is for unformatted messages. Both msgprintf and msgwrite allocate memory for each message and free this memory after calling msgsnd . The removequeue function removes the message queue and its associated data structures. The msgqueuelog.h header file contains the prototypes for these functions. If successful, these functions return 0. If unsuccessful, these functions return 1 and set errno .

Program 15.9 msgqueuelog.c

Utility functions that access and output to a message queue .

 #include <errno.h> #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <sys/msg.h> #include <sys/stat.h> #include "msgqueuelog.h" #define PERM (S_IRUSR  S_IWUSR) typedef struct {    long mtype;    char mtext[1]; } mymsg_t; static int queueid; int initqueue(int key) {                    /* initialize the message queue */    queueid = msgget(key, PERM  IPC_CREAT);    if (queueid == -1)       return -1;    return 0; } int msgprintf(char *fmt, ...) {               /* output a formatted message */    va_list ap;    char ch;    int error = 0;    int len;    mymsg_t *mymsg;    va_start(ap, fmt);                       /* set up the format for output */    len = vsnprintf(&ch, 1, fmt, ap);              /* how long would it be ? */    if ((mymsg = (mymsg_t *)malloc(sizeof(mymsg_t) + len)) == NULL)       return -1;    vsprintf(mymsg->mtext, fmt, ap);                 /* copy into the buffer */    mymsg->mtype = 1;                            /* message type is always 1 */    if (msgsnd(queueid, mymsg, len + 1, 0) == -1)       error = errno;    free(mymsg);    if (error) {       errno = error;       return -1;    }    return 0; } int msgwrite(void *buf, int len) {     /* output buffer of specified length */    int error = 0;    mymsg_t *mymsg;    if ((mymsg = (mymsg_t *)malloc(sizeof(mymsg_t) + len - 1)) == NULL)       return -1;    memcpy(mymsg->mtext, buf, len);    mymsg->mtype = 1;                            /* message type is always 1 */    if (msgsnd(queueid, mymsg, len, 0) == -1)       error = errno;    free(mymsg);    if (error) {       errno = error;       return -1;    }    return 0; } int remmsgqueue(void) {    return msgctl(queueid, IPC_RMID, NULL); } 
Example 15.15

Why does the msgprintf function of Program 15.9 use len in malloc and len+1 in msgsnd ?

Answer:

The vsnprintf function returns the number of bytes to be formatted, not including the string terminator, so len is the string length. We need one extra byte for the string terminator. One byte is already included in mymsg_t .

Program 15.10, which outputs the contents of a message queue to standard output, can save the contents of a message queue to a file through redirection. The msgqueuesave program takes a key that identifies the message queue as a command-line argument and calls the initqueue function of Program 15.9 to access the queue. The program then outputs the contents of the queue to standard output until an error occurs. Program 15.10 does not deallocate the message queue when it completes.

Program 15.11 reads lines from standard input and sends each to the message queue. The program takes a key as a command-line argument and calls initqueue to access the corresponding message queue. Program 15.11 sends an informative message containing its process ID before starting to copy from standard input.

You should be able to run multiple copies of Program 15.11 along with a single copy of Program 15.10. Since none of the programs call removequeue , be sure to execute the ipcrm command when you finish.

Example 15.16

Why does Program 15.10 use r_write from the restart library even though the program does not catch any signals?

Answer:

In addition to restarting when interrupted by a signal (which is not necessary here), r_write continues writing if write did not output all of the requested bytes.

Example 15.17

How would you modify these programs so that messages from different processes could be distinguished?

Answer:

Modify the functions in Program 15.9 to send the process ID as the message type. Modify Program Program 15.10 to output the message type along with the message.

Program 15.10 msgqueuesave.c

A program that copies messages from a message queue to standard output.

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/msg.h> #include "msgqueuelog.h" #include "restart.h" #define MAXSIZE 4096 typedef struct {    long mtype;    char mtext[MAXSIZE]; } mymsg_t; int main(int argc, char *argv[]) {    int id;    int key;    mymsg_t mymsg;    int size;    if (argc != 2) {       fprintf(stderr, "Usage: %s key\n", argv[0]);       return 1;    }    key = atoi(argv[1]);    if ((id = initqueue(key)) == -1) {       perror("Failed to initialize message queue");       return 1;    }    for (; ;) {       if ((size = msgrcv(id, &mymsg, MAXSIZE, 0, 0)) == -1) {          perror("Failed to read message queue");          break;       }       if (r_write(STDOUT_FILENO, mymsg.mtext, size) == -1) {          perror("Failed to write to standard output");          break;       }    }    return 1; } 
Program 15.11 msgqueuein.c

A program that sends standard input to a message queue .

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/msg.h> #include <unistd.h> #include "msgqueuelog.h" #include "restart.h" #define MAXLINE 1024 int main(int argc, char *argv[]) {    char buf[MAXLINE];    int key;    int size;    if (argc != 2) {       fprintf(stderr, "Usage: %s key\n", argv[0]);       return 1;    }    key = atoi(argv[1]);    if (initqueue(key) == -1) {       perror("Failed to initialize message queue");       return 1;    }    if (msgprintf("This is process %ld\n", (long)getpid()) == -1) {       perror("Failed to write header to message queue");       return 1;    }    for (; ;) {       if ((size = readline(STDIN_FILENO, buf, MAXLINE)) == -1) {          perror("Failed to read from standard input");          break;       }       if (msgwrite(buf, size) == -1) {          perror("Failed to write message to standard output");          break;       }    }    return 0; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net