Member Avatar for Member #250647

Hey, so i'm having some problems with my message passing code.
Ultimately, what i'm trying to do is use the msgget/snd/rcv commands to send the pid of the parent to the child, and visa versa. However, i'm getting an invalid argument error fr my msgsnd in the child process. My code is a bit messy, but here's what I have:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>



int main(void)
{
    struct msgbuf {
        long priority;
        int temp;
        int pid;
    } buf;
    
    int msqid, result;
    pid_t pid, myPid;
    size_t size = sizeof(buf);

        
    msqid = msgget(2345, 0600|IPC_CREAT); //create message sending
    
    printf("msqid: %d\n", msqid);      
    
    
    pid = fork();
    switch (pid) {
        case -1:
            printf("fork failed");
            exit(-1);
            
        case 0: 
         
            
            
                //msqid = msgget(key, 0600|IPC_CREAT); //create message sending
            
                //printf("%d\n", msqid);
            myPid = getpid();
            buf.pid = myPid;
            printf("pid child/sender:%d\n... Sending\n", buf.pid);
            
            result = msgsnd(msqid, &buf, sizeof(buf)-sizeof(long), 0); //Send process id
            if (result==-1) {
                perror("msgsnd:");
                exit(-1);
            }
                //printf("%d\n",result);
                //wait(NULL); //wait for child to finish sending pid back
            result = msgrcv(msqid, &buf, sizeof(buf)-sizeof(long), 2, 0);
            
            if (result==-1) {
                perror("msgrcv:");
                exit(-1);
            }
            printf("Received reply from: %d\n", buf.pid);
            
            exit(0); 
                      
            
            
            
            
            
        default:

            
                //wait(NULL);
                //msqid = msgget(key, 0666|IPC_CREAT); //create message sending
                //printf("%d\n", msqid);
            printf("pid parent/receiver: %d\n... Receiving\n", getpid());
            msgrcv(msqid, &buf, sizeof(buf)-sizeof(long), 2, 0);
            printf("Serving for sender: %d\n", buf.pid);
    
            buf.pid = getpid();
            msgsnd(msqid, &buf, sizeof(buf)-sizeof(long), 0); //Send process id
                        
    }
    
    
    
        //struct msqid_ds dummyParam;
    msgctl(msqid, IPC_RMID, 0);

    exit(0);
}

Any idea on what's going on? My output is:
msqid: 65536
pid parent/receiver: 1200
... Receiving
pid child/sender:1203
... Sending
msgsnd:: Invalid argument
Serving for sender: 0


I was outputting the msqid to make sure that the child and parent were connected to the same memory

Dani AI

Generated

Good catch by : a SysV message must have a positive mtype before you call msgsnd, otherwise the kernel returns EINVAL. Also remember how the msgrcv type argument works: if it is greater than 0, the call only returns a message whose type equals that value. If you send with type 1 and receive with type 2, you will block (or get ENOMSG with IPC_NOWAIT). Pick a single type for the handshake, or use 0 on receive when you do not care about type ordering. One more pitfall in this thread: always check the return value of msgrcv on the parent; printing buf.pid after a failed receive can show garbage.

For a simple PID handshake, keep the payload explicit and use pid_t. The size you pass to msgsnd/msgrcv is the size of the payload only, not including the long mtype.

struct pid_msg { long mtype; pid_t pid; } msg;

/* create a real key and queue */
key_t key = ftok(".", 'Q');
int msqid = msgget(key, 0600 | IPC_CREAT);

/* send our pid with type 1 */
msg.mtype = 1;
msg.pid = getpid();
if (msgsnd(msqid, &msg, sizeof(msg.pid), 0) == -1) perror("msgsnd");

/* receive a reply of the same type */
if (msgrcv(msqid, &msg, sizeof(msg.pid), 1, 0) == -1) perror("msgrcv");

A few reliability tips tied to this code:

  • Use waitpid(child, NULL, 0) before msgctl(msqid, IPC_RMID, NULL) so the parent does not remove the queue while the child is still receiving (otherwise you may see EIDRM).
  • Prefer pid_t over int for PIDs, and keep mtype as long and first in the struct.
  • If you need strict one-way ordering, keep distinct types (e.g., 1 for child->parent, 2 for parent->child) and match them on both ends.

: msqid is the message queue identifier returned by msgget. It is how the kernel refers to a specific queue after you create/open it; it is different from the key you pass to msgget.

Recommended Answers

All 3 Replies

You didn't initialize buf.priority (mtype in the msgsnd terms). msgsnd requires it to be positive, thus EINVAL. Adding

buf.priority = 2;

at around line 43 heals everything.
PS: Why 2? Because of 2 at line 76...

Member Avatar for Member #250647

Thanks man. I had a few other problems with ordering, but it's all working.

sir ? wat does msqid mean >? because the program when i try it, it does RUN.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.