'Question about sharing mmapped area between 2 different processes

I'm trying to share mmapped area in 2 processes. In my program, I create memory_update() process and memory_read() process. This memory_update() process update mmapped area and tried to read that area in memory_read() process. But I got when I tried to read the mmapped area. So far, I don't have good luck to find a solution for this problem.

If you have any idea, please leave your comments. Here is the source code.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define COLUMN 80
#define ROW 10
#define BUFSIZE 80

#define SHM_KEY 0x9998

struct _row {
   int32_t flag;
   unsigned char *buffer;
};

typedef enum {
   DATA_READY,
   DATA_RESET
} msg_type_t;

struct _ipc_message {
   msg_type_t type;
   int32_t value;
};
typedef struct _ipc_message ipc_message_t;

typedef struct _row row_t;

int32_t format_number_string(char *buf, int32_t num)
{
   sprintf(buf, "%02d", num);
   return 0;
}

int32_t update_row(char *buf, char *str)
{
   strncpy(buf, str, 80);

   return 0;
}

int32_t print_row(char *buf)
{
   printf("print_row buf = %p\n", (void *)buf);
   printf("%s\n", buf);
   return 0;
}

int32_t memory_update(int32_t sk)
{
   row_t *p_row;
   ipc_message_t msg;
   unsigned char *shared_mem;
   unsigned char *ptr;
   char rbuf[BUFSIZE];
   char nbuf[3];
   int32_t shmid;
   int32_t i;
   int32_t ret;
   int32_t fd;

   shmid = shmget(SHM_KEY, ROW * sizeof(row_t), 0644 | IPC_CREAT);
   if (shmid == -1)
   {
      perror("Shared Memory Error");
      return -1;
   }

   /* Attach Shared Memory */
   shared_mem = shmat(shmid, NULL, 0);
   if (shared_mem == (void *)-1)
   {
      perror("Shared Memory Attach Error");
      return -1;
   }

   fd = open("testfile", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
   if (fd < 0)
   {
      perror("File Open Error");
   }

   ptr = mmap(
            NULL,
            COLUMN * ROW,
            PROT_READ | PROT_WRITE,
            MAP_SHARED,
            fd,
            0);

   printf("ptr = %p\n", (void *)ptr);
   for (i = 0 ; i < ROW ; i++)
   {
      format_number_string(nbuf, i);
      memset(rbuf, 0x20, BUFSIZE);
      sprintf(rbuf, "LINE %s :", nbuf);
      rbuf[strlen(rbuf)] = ' ';
      rbuf[BUFSIZE-1] = 0x0;
      update_row(&ptr[i * COLUMN], rbuf);
   }

   for (i = 0 ; i < ROW ; i++)
   {
      p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
      p_row->flag = 0x99;
      p_row->buffer = &ptr[i * COLUMN];
//    print_row(p_row->buffer);
   }

   msg.type = DATA_READY;
   msg.value = 0;
   send(sk, (void *)&msg, sizeof(ipc_message_t), 0);

   i = 0;
   for ( ; i < ROW ; i++)
   {
      p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
      if (p_row->flag == 0x0)
      {
         printf("row[%d] has processed\n", i);
      }
      else
      {
         i--;
         sleep(1);
      }
   }

   /* Detach Shared Memory */
   ret = shmdt(shared_mem);
   if (ret == -1)
   {
      perror("Shared Memory Detach Error");
      return -1;
   }

   ret = munmap(ptr, COLUMN * ROW);
   if (ret != 0)
   {
      printf("UnMapping Failed\n");
      return -1;
   }
   close(fd);

   return 0;
}

int32_t memory_read(int32_t sk)
{
   row_t *p_row;
   ipc_message_t msg;
   unsigned char *shared_mem;
   int32_t shmid;
   int32_t ret;
   int32_t i;

   while (1)
   {
      ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
      if (ret < 0)
      {
         perror("recv error");
         return -1;
      }
      if (msg.type != DATA_READY)
      {
         continue;
      }
      else
      {
         break;
      }
   }

   shmid = shmget(SHM_KEY, ROW * sizeof(row_t), 0644 | IPC_CREAT);
   if (shmid == -1)
   {
      perror("Shared Memory Error");
      return -1;
   }

   /* Attach Shared Memory */
   shared_mem = shmat(shmid, NULL, 0);
   if (shared_mem == (void *)-1)
   {
      perror("Shared Memory Attach Error");
      return -1;
   }

   for (i = 0 ; i < ROW ; i++)
   {
      p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
      printf("memory_read process [%d]\n", i);
      print_row(p_row->buffer);
      p_row->flag = 0x0;
      sleep(1);
   }

   /* Detach Shared Memory */
   ret = shmdt(shared_mem);
   if (ret == -1)
   {
      perror("Shared Memory Detach Error");
      return -1;
   }

   return 0;
}

int32_t main(void)
{
   pid_t pid;
   int32_t sp[2];
   int32_t ret;

   static const int32_t ps = 0;
   static const int32_t cs = 1;

   ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
   if (ret == -1)
   {
      perror("socketpair");
      return -1;
   }

   pid = fork();
   if (pid == 0)
   {
      close(sp[ps]);
      memory_update(sp[cs]);
   }
   else
   {
      close(sp[cs]);
      memory_read(sp[ps]);
   }

   return 0;
}

And this is the output.

$ ./mmm
ptr = 0x7fdc214a8000
memory_read process [0]
print_row buf = 0x7fdc214a8000
Segmentation fault (core dumped)

Modifed code to mmap before forking. And it is working as expected.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define COLUMNS 80
#define ROWS 60
#define BUFSIZE 80

typedef enum {
   DATA_PRODUCED,
   DATA_CONSUMED
} msg_type_t;

struct _ipc_message {
   msg_type_t type;
   int32_t value;
};
typedef struct _ipc_message ipc_message_t;

int32_t memory_update(int32_t sk, char *buf)
{
   ipc_message_t msg;
   int32_t ret;
   char *msg2 = "updated buffer";

   printf("memory_update : 1.buf = %s\n", buf);
   memset(buf, 0, 80);
   strncpy(buf, msg2, strlen(msg2));
   buf[strlen(msg2)] = 0;

   printf("memory_update : 2.buf = %s\n", buf);
   printf("memory_update : send message from memory_update process\n");
   msg.type = DATA_PRODUCED;
   msg.value = 0;
   send(sk, (void *)&msg, sizeof(ipc_message_t), 0);

   while (1)
   {
      printf("memory_update : receive message from memory_read process\n");
      ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
      if (ret < 0)
      {
         perror("recv error");
         return -1;
      }
      if (msg.type != DATA_CONSUMED)
      {
         continue;
      }
      else
      {
         break;
      }
   }

   printf("memory_update : 3.buf = %s\n", buf);
   return 0;
}

int32_t memory_read(int32_t sk, char *buf)
{
   ipc_message_t msg;
   int32_t ret;
   int32_t i;
   char *msg3 = "buffer processed";

   printf("memory_read : 1.buf = %s\n", buf);

   while (1)
   {
      printf("memory_read : receive message from memory_update process\n");
      ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
      if (ret < 0)
      {
         perror("recv error");
         return -1;
      }
      if (msg.type != DATA_PRODUCED)
      {
         continue;
      }
      else
      {
         break;
      }
   }
   printf("memory_read : 2.buf = %s\n", buf);

   memset(buf, 0, 80);
   strncpy(buf, msg3, strlen(msg3));
   buf[strlen(msg3)] = 0;

   printf("memory_read : 3.buf = %s\n", buf);
   printf("memory_read : send message from memory_update process\n");
   msg.type = DATA_CONSUMED;
   msg.value = 0;
   send(sk, (void *)&msg, sizeof(ipc_message_t), 0);

   return 0;
}

int32_t main(void)
{
   pid_t pid;
   int32_t sp[2];
   int32_t ret;
   int32_t fd;
   int32_t i;
   char *ptr;
   char *msg1 = "initial message";

   static const int32_t ps = 0;
   static const int32_t cs = 1;

   fd = open("80bytes", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
   if (fd < 0)
   {
      perror("File Open Error");
   }

   ptr = mmap(
            NULL,
            80,
            PROT_READ | PROT_WRITE,
            MAP_SHARED,
            fd,
            0);

   memset(ptr, 0, 80);
   strncpy(ptr, msg1, strlen(msg1));
   ptr[strlen(msg1)] = 0;
   printf("ptr = %s\n", ptr);

   ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
   if (ret == -1)
   {
      perror("socketpair");
      return -1;
   }

   pid = fork();
   if (pid == 0)  /* child process */
   {
      close(sp[ps]);
      memory_update(sp[cs], ptr);
   }
   else  /* parent process */
   {
      close(sp[cs]);
      memory_read(sp[ps], ptr);

      ret = munmap(ptr, 80);
      if (ret != 0)
      {
         printf("UnMapping Failed\n");
         return -1;
      }
      close(fd);
   }

   return 0;
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source