Luca Guarro
Luca Guarro

Reputation: 1168

msgrcv not waiting for a message with a specific message type with errno 22 (EINVAL)

I am trying to use the msgsnd and msgrcv system calls in the standard C library and am not getting the expected/desired performance.

My problem is that when I call msgrcv, it is not waiting for a message with the specified mtype (4).

I first send a message with an mtype of 1. The idea is that another process would then receive this message and send an acknowledgement message back with an mtype of 4. From the documentation, I expect that "if msgtyp is greater than zero, the first message of type msgtyp is received".
I also expect it to wait until a message with message type msgtyp is in the queue. From the documentation:

My msgrcv function does not wait. I have created a minimal, complete, and verifiable example below.

(Also note that I am not running any other of its companion programs that could be intercepting this message with mtype = 1 and sending back another message with mtype = 4 when testing this program).

#include <sys/msg.h>
#include <iostream>
using namespace std;

int main() {
    int qid = msgget(ftok(".",'u'), IPC_EXCL|IPC_CREAT|0600);
    struct buf {
        long mtype; // required
        int message; // mesg content
    };
    buf msg;
    int size = sizeof(msg)-sizeof(long);

    msg.mtype = 1;
    msgsnd(qid, (struct msgbuf *)&msg, size, 0); // sending
    cout << msg.message << endl;
    //Get acknowledgement from receiverA
    msgrcv(qid, (struct msgbuf *)&msg, size, 4, 0); // read mesg
    cout << msg.message << endl;
}

UPDATE:

The msgrcv function is returning an errno value of 22 (EINVAL) which according to the documentation means "The MessageQueueID parameter is not a valid message queue identifier."

So I went ahead and checked what the errno value of my msgget function is. The msgget function returns a value of 17 (EEXIST). Not sure what to do with this but the documentation for msgget(), says "If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST."

Just from messing around with the msgget function, if I change the 2nd parameter, in the ftok function to generate a different identifier, it works but only when I run it once, if I try to run it a second time with the same identifier, the error returns. So I guess my question can be simplified to: How can I get the qid of the message queue I want to use but not try to generate it if it already exists?

Upvotes: 0

Views: 3382

Answers (2)

Monk
Monk

Reputation: 786

From man page:

If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST.

When I tried to execute your code for the first time it blocked on msgrcv() but when I re-executed it didn't. Because in next iteration msgget() failed with EXIST and qid filled with -1. Due to this msgsnd() as well as msgrcv() failed with invalid argument.

Solution to above problem is to remove message queue, use msgctl() to remove message queue id before returning from test program as follows:

msgctl(qid, IPC_RMID, NULL);

Advise: Always check return value of system calls.

Hope this will help you.

Upvotes: 1

hgminh
hgminh

Reputation: 1268

Try to remove IPC_EXCL from when calling msgget.

From https://www.tldp.org/LDP/lpg/node34.html

IPC_EXCL

When used with IPC_CREAT, fail if queue already exists.

Upvotes: 1

Related Questions