linux ipc. Why is msgrcv always blocking?

492 views Asked by At

client readline write to shared memory.and send a msg to server. server get msg and read from shared memrory.

But the server cannot output correctly, The server did not output anything,I do not know why.

the man pages says that: If no message of the requested type is available and IPC_NOWAIT isn't specified in msgflg, the calling process is blocked until one of the following conditions occurs

but the server is always blocked.

I use gdb to debug it,find out that std::cout does not work

debug context

Breakpoint 1, main () at shared_mem_server.cpp:35
35      sem_init(reinterpret_cast<sem_t*>(shm),0,1);
(gdb) p shm
$1 = 0x7ffff7ff6000 ""
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 0   0   0   0
0x7ffff7ff6010: 0   0   0   0
0x7ffff7ff6020: 0   0
(gdb) s
__new_sem_init (sem=0x7ffff7ff6000, pshared=0, value=1) at sem_init.c:31
31  sem_init.c: No such file or directory.
(gdb) return
Make __new_sem_init return now? (y or n) n
Not confirmed
(gdb) finish
Run till exit from #0  __new_sem_init (sem=0x7ffff7ff6000, pshared=0, value=1)
    at sem_init.c:31
main () at shared_mem_server.cpp:37
37          msgrcv(msgid,&msg,256,ret_type,0);
Value returned is $2 = 0
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 1   0   0   0
0x7ffff7ff6010: 0   0   0   0
0x7ffff7ff6020: 0   0
(gdb) p sem_sz
$3 = 32
(gdb) n
38          sem_p(reinterpret_cast<sem_t*>(shm));
(gdb) n
39          if(shm + sem_sz == "q")
(gdb) x/10w 0x7ffff7ff6000
0x7ffff7ff6000: 0   0   0   0
0x7ffff7ff6010: 0   0   0   0
0x7ffff7ff6020: 3355185 0
(gdb) x/12w 0x7ffff7ff6000
0x7ffff7ff6000: 0   0   0   0
0x7ffff7ff6010: 0   0   0   0
0x7ffff7ff6020: 3355185 0   0   0
(gdb) n
41          std::cout << "shared memory " << shm + sem_sz;
(gdb) n
42          sem_v(reinterpret_cast<sem_t*>(shm));
(gdb) q

Below is the code

server code:

#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>

#include "error.h"
#include "sempv.h"

const int SHM_SIZE=1024;

struct msg_form{
    long  msg_type;
    char msg_text[256];
};

int main(){
    key_t key;
    int shmid,msgid,ret_type = 888,sem_sz = sizeof(sem_t);
    char *shm;
    

    msg_form msg;

    if((key = ftok(".",'v')) < 0)
        unix_error("ftok error");
    
    if((shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666)) == -1)
        unix_error("create shared memory error");

    if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
        unix_error("attach shared memeory error");
    }
    if((msgid = msgget(key,IPC_CREAT|07777)) == -1)
        unix_error("msgget error");
    sem_init(reinterpret_cast<sem_t*>(shm),0,1);
    while(true){
        msgrcv(msgid,&msg,256,ret_type,0);
        sem_p(reinterpret_cast<sem_t*>(shm));
        if(shm + sem_sz == "q")
            break;
        std::cout << "shared memory " << shm + sem_sz;
        sem_v(reinterpret_cast<sem_t*>(shm));
    }
    shmdt(shm);
   
    shmctl(shmid,IPC_RMID,0);
    shmctl(msgid,IPC_RMID,0);
    return 0;
}


client code

#include <iostream>
#include <sys/shm.h>
#include <sys/msg.h>

#include "error.h"
#include "sempv.h"
#include <string>

using std::string;

const int SHM_SIZE=1024;

struct msg_form{
    long  msg_type;
    char msg_text[256];
};

int main(){
    key_t key;
    int shmid,msgid,sem_sz = sizeof(sem_t);
    char *shm;
    
    int err;

    msg_form msg;
    string s;

    if((key = ftok(".",'v')) < 0)
        unix_error("ftok error");
    
    if((shmid = shmget(key,SHM_SIZE,0)) == -1)
        unix_error("shmget error");
    if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
        unix_error("attach shared memeory error");
    }
    if((msgid = msgget(key,0777)) == -1)
        unix_error("msgget error");
    std::cout << "key is " << key << std::endl;
    
    while(getline(std::cin,s)){
        sem_p(reinterpret_cast<sem_t*>(shm));
        memset(shm+sem_sz,0,SHM_SIZE-sem_sz);
        memcpy(shm+sem_sz,s.c_str(),s.size());
       
        msg.msg_type = 888;
        sprintf(msg.msg_text,"shared memory write signal");

        if((err =  msgsnd(msgid,&msg,sizeof(msg.msg_text),0)) == -1)
            unix_error("msgsnd error");
         sem_v(reinterpret_cast<sem_t*>(shm));
        //std::cout << "message send\n";
    }
    return 0;
}
1

There are 1 answers

8
Rachid K. On BEST ANSWER

General remarks:

  • System V IPC are deprecated, for any new project, it is advised to use the POSIX counterparts (man 7 shm_overview and man 7 mq_overview)

  • The client/server synchronization is weak: the client may overwrite the shared memory segment while the server is reading it. You should use a mutex to read/write into the shared memory segment (when one is reading/writing the other is blocked): cf. man 7 sem_overview

  • As you don't make any cleanup in the server, make sure to remove the queue and shared memory identifiers with ipcs/ipcrm under the shell between each tries of your application

In the server:

  • The error checking is wrong: if shmget()/msgget return -1 and errno is equal to EEXIST, you continue but you didn't get any shm/msg identifier as it is -1!

In the client:

  • For the sake of robustness, use preferably snprintf() instead of sprintf() to force the check of the bounds of the buffer

  • The client should not use IPC_CREAT for msgget(). Generally, it is the role of server to create the resources in a server/client application

Here is the C version of your modified code:

Server:

#include <stdio.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <semaphore.h>


const int SHM_SIZE=1024;

struct msg_form{
    long  msg_type;
    char msg_text[256];
};


static void unix_error(const char *str)
{

  fprintf(stderr, "%s\n", str);

  exit(1);
}


int main(){
    key_t key;
    int shmid,msgid,ret_type = 888,sem_sz = sizeof(sem_t);
    char *shm;
    

    struct msg_form msg;

    if((key = ftok(".",'v')) < 0)
        unix_error("ftok error");
    
    if((shmid = shmget(key,SHM_SIZE,IPC_CREAT|0666)) == -1)
        unix_error("create shared memory error");

    if((shm = (char *)shmat(shmid,0,0)) == (void*)-1){
        unix_error("attach shared memory error");
    }
    if((msgid = msgget(key,IPC_CREAT|07777)) == -1)
        unix_error("msgget error");
    sem_init((sem_t *)(shm),1,1);
    while(1){
        msgrcv(msgid,&msg,256,ret_type,0);
        sem_wait((sem_t *)(shm));
        if (*(shm + sem_sz) == 'q' && *(shm + sem_sz + 1) == '\n') {
            sem_post((sem_t *)(shm));
            break;
        }
        printf("shared memory: %s", shm + sem_sz);
        sem_post((sem_t *)(shm));
    }
    shmdt(shm);
   
    shmctl(shmid,IPC_RMID,0);
    msgctl(msgid,IPC_RMID,0);
    return 0;
}

Client:

#include <stdio.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>


const int SHM_SIZE=1024;

struct msg_form{
    long  msg_type;
    char msg_text[256];
};


static void unix_error(const char *str)
{

  fprintf(stderr, "%s\n", str);

  exit(1);
}


int main(){
    key_t key;
    int shmid,msgid,sem_sz = sizeof(sem_t);
    char *shm;
    
    int err;

    struct msg_form msg;
    char s[256];

    if((key = ftok(".",'v')) < 0)
        unix_error("ftok error");
    
    if((shmid = shmget(key,SHM_SIZE,0)) == -1)
        unix_error("shmget error");
    if((shm = (char*)shmat(shmid,0,0)) == (void*)-1){
        unix_error("attach shared memeory error");
    }
    if((msgid = msgget(key,0777)) == -1)
        unix_error("msgget error");
    printf("key is 0x%x\n", (int)key);
    
    while(fgets(s, sizeof(s) - 1, stdin)) {
        sem_wait((sem_t *)(shm));
        memset(shm+sem_sz,0,SHM_SIZE-sem_sz);
        memcpy(shm+sem_sz,s, strlen(s));
       
        msg.msg_type = 888;
        snprintf(msg.msg_text, 256, "shared memory write signal");

        if((err =  msgsnd(msgid,&msg,sizeof(msg.msg_text),0)) == -1) {
            sem_post((sem_t *)(shm));
            unix_error("msgsnd error");
        }
        sem_post((sem_t *)(shm));
    }
    return 0;
}