title: Shared memory across processes on Linux/x86_64
body: <p>I have a few questions on using shared memory with processes. I looked at several previous posts and couldn't glean the answers precisely enough. Thanks in advance for your help.</p>
  
  <ol>
  <li><p>I'm using shm_open + mmap like below. This code works as intended with parent and child alternating to increment g_shared->count (the synchronization is not portable; it works only for certain memory models, but good enough for my case for now). However, when I change MAP_SHARED to MAP_ANONYMOUS | MAP_SHARED, the memory isn't shared and the program hangs since the 'flag' doesn't get flipped. Removing the flag confirms what's happening with each process counting from 0 to 10 (implying that each has its own copy of the structure and hence the 'count' field). Is this the expected behavior? I don't want the memory to be backed by a file; I really want to emulate what might happen if these were threads instead of processes (they need to be processes for other reasons).</p></li>
  <li><p>Do I really need shm_open? Since the processes belong to the same hierarchy, can I just use mmap alone instead? I understand this would be fairly straightforward if there wasn't an 'exec,' but how do I get it to work when there is an 'exec' following the 'fork?'</p></li>
  <li><p>I'm using kernel version 3.2.0-23 on x86_64 (Intel i7-2600). For this implementation, does mmap give the same behavior (correctness as well as performance) as shared memory with pthreads sharing the same global object? For example, does the MMU map the segment with 'cacheable' MTRR/TLB attributes? </p></li>
  <li><p>Is the cleanup_shared() code correct? Is it leaking any memory? How could I check? For example, is there an equivalent of System V's 'ipcs?'</p></li>
  </ol>
  
  <p>thanks,
  /Doobs</p>
  
  <p>shmem.h:</p>
  
  <pre><code>#ifndef __SHMEM_H__
  #define __SHMEM_H__
  
  //includes
  
  #define LEN 1000
  #define ITERS 10
  
  #define SHM_FNAME "/myshm"
  
  typedef struct shmem_obj {
      int count;
      char buff[LEN];
      volatile int flag;
  } shmem_t;
  
  extern shmem_t* g_shared;
  extern char proc_name[100];
  extern int fd;
  
  void cleanup_shared() {
      munmap(g_shared, sizeof(shmem_t));
      close(fd);
      shm_unlink(SHM_FNAME);
  }
  
  static inline 
  void init_shared() {
      int oflag;
  
      if (!strcmp(proc_name, "parent")) {
          oflag = O_CREAT | O_RDWR;
      } else {
          oflag = O_RDWR;
      }
  
      fd = shm_open(SHM_FNAME, oflag, (S_IREAD | S_IWRITE));
      if (fd == -1) {
          perror("shm_open");
          exit(EXIT_FAILURE);
      }
  
      if (ftruncate(fd, sizeof(shmem_t)) == -1) {
          perror("ftruncate");
          shm_unlink(SHM_FNAME);
          exit(EXIT_FAILURE);
      }
  
      g_shared = mmap(NULL, sizeof(shmem_t), 
                      (PROT_WRITE | PROT_READ), 
                      MAP_SHARED, fd, 0);
      if (g_shared == MAP_FAILED) {
          perror("mmap");
          cleanup_shared();
          exit(EXIT_FAILURE);
      }
  }
  
  static inline 
  void proc_write(const char* s) {
      fprintf(stderr, "[%s] %s\n", proc_name, s);
  }
  
  #endif // __SHMEM_H__
  </code></pre>
  
  <p>shmem1.c (parent process):</p>
  
  <pre><code>#include "shmem.h"
  
  int fd;
  shmem_t* g_shared;
  char proc_name[100];
  
  void work() {
      int i;
      for (i = 0; i &amp;lt ITERS; ++i) {
          while (g_shared-&gt;flag);
          ++g_shared-&gt;count;
          sprintf(g_shared-&gt;buff, "%s: %d", proc_name, g_shared-&gt;count);
          proc_write(g_shared-&gt;buff);
          g_shared-&gt;flag = !g_shared-&gt;flag;
      }
  }
  
  int main(int argc, char* argv[], char* envp[]) {
      int status, child;
      strcpy(proc_name, "parent");
      init_shared(argv);
      fprintf(stderr, "Map address is: %p\n", g_shared);
  
      if (child = fork()) { 
          work();
          waitpid(child, &amp;status, 0);
          cleanup_shared();
          fprintf(stderr, "Parent finished!\n");
      } else { /* child executes shmem2 */
          execvpe("./shmem2", argv + 2, envp);
      } 
  }
  </code></pre>
  
  <p>shmem2.c (child process):</p>
  
  <pre><code>#include "shmem.h"
  
  int fd;
  shmem_t* g_shared;
  char proc_name[100];
  
  void work() {
      int i;
      for (i = 0; i &amp;lt ITERS; ++i) {
          while (!g_shared-&gt;flag);
          ++g_shared-&gt;count;
          sprintf(g_shared-&gt;buff, "%s: %d", proc_name, g_shared-&gt;count);
          proc_write(g_shared-&gt;buff);
          g_shared-&gt;flag = !g_shared-&gt;flag;
      }
  }
  
  int main(int argc, char* argv[], char* envp[]) {
      int status;
      strcpy(proc_name, "child");
      init_shared(argv);
      fprintf(stderr, "Map address is: %p\n", g_shared);
      work();
      cleanup_shared();
      return 0;
  }
  </code></pre>