title: Condition Variable in Shared Memory - is this code POSIX-conformant?
body: <p>Does the POSIX standard allow a <strong>named</strong> shared memory block to contain a mutex and condition variable?</p>
  <p>We've been trying to use a mutex and condition variable to synchronise access to named shared memory by two processes on a <a href="http://www.lynuxworks.com/rtos/rtos-se.php" rel="nofollow noreferrer">LynuxWorks LynxOS-SE system</a> (POSIX-conformant).</p>
  <p>One shared memory block is called <code>&quot;/sync&quot;</code> and contains the mutex and condition variable, the other is <code>&quot;/data&quot;</code> and contains the actual data we are syncing access to.</p>
  <p>We're seeing failures from <code>pthread_cond_signal()</code> if both processes don't perform the <code>mmap()</code> calls in <strong>exactly the same order</strong>, or if one process mmaps in <em>some other</em> piece of shared memory before it mmaps the <code>&quot;/sync&quot;</code> memory.</p>
  <p>This example code is about as short as I can make it:</p>
  <pre class="lang-c prettyprint-override"><code>#include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;sys/mman.h&gt;
  #include &lt;sys/file.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;pthread.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  using namespace std;
  
  static const string shm_name_sync(&quot;/sync&quot;);
  static const string shm_name_data(&quot;/data&quot;);
  
  struct shared_memory_sync
  {
    pthread_mutex_t mutex;
    pthread_cond_t condition;
  };
  
  struct shared_memory_data
  {
    int a;
    int b;
  };
  
  
  //Create 2 shared memory objects
  // - sync contains 2 shared synchronisation objects (mutex and condition)
  // - data not important 
  void create()
  {
    // Create and map 'sync' shared memory
    int fd_sync = shm_open(shm_name_sync.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
    ftruncate(fd_sync, sizeof(shared_memory_sync));
    void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
    shared_memory_sync* p_sync = static_cast&lt;shared_memory_sync*&gt; (addr_sync);
  
      // init the cond and mutex
    pthread_condattr_t cond_attr;
      pthread_condattr_init(&amp;cond_attr);
      pthread_condattr_setpshared(&amp;cond_attr, PTHREAD_PROCESS_SHARED);
      pthread_cond_init(&amp;(p_sync-&gt;condition), &amp;cond_attr);
      pthread_condattr_destroy(&amp;cond_attr);
  
      pthread_mutexattr_t m_attr;
      pthread_mutexattr_init(&amp;m_attr);
      pthread_mutexattr_setpshared(&amp;m_attr, PTHREAD_PROCESS_SHARED);
      pthread_mutex_init(&amp;(p_sync-&gt;mutex), &amp;m_attr);
      pthread_mutexattr_destroy(&amp;m_attr);
  
    // Create the 'data' shared memory   
    int fd_data = shm_open(shm_name_data.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
    ftruncate(fd_data, sizeof(shared_memory_data));
    
    void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
    shared_memory_data* p_data = static_cast&lt;shared_memory_data*&gt; (addr_data);
  
    // Run the second process while it sleeps here.
    sleep(10);
  
    int res = pthread_cond_signal(&amp;(p_sync-&gt;condition));
    assert(res==0);  // &lt;--- !!!THIS ASSERT WILL FAIL ON LYNXOS!!!
  
    munmap(addr_sync, sizeof(shared_memory_sync));
    shm_unlink(shm_name_sync.c_str());
    munmap(addr_data, sizeof(shared_memory_data));
    shm_unlink(shm_name_data.c_str());
  }
  
  //Open the same 2 shared memory objects but in reverse order
  // - data
  // - sync 
  void open()
  {
    sleep(2);
    int fd_data = shm_open(shm_name_data.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
    void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
    shared_memory_data* p_data = static_cast&lt;shared_memory_data*&gt; (addr_data);
  
    int fd_sync = shm_open(shm_name_sync.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
    void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
    shared_memory_sync* p_sync = static_cast&lt;shared_memory_sync*&gt; (addr_sync);
  
    // Wait on the condvar
    pthread_mutex_lock(&amp;(p_sync-&gt;mutex));
    pthread_cond_wait(&amp;(p_sync-&gt;condition), &amp;(p_sync-&gt;mutex));
    pthread_mutex_unlock(&amp;(p_sync-&gt;mutex));
    
    munmap(addr_sync, sizeof(shared_memory_sync));
    munmap(addr_data, sizeof(shared_memory_data));
  }
  
  int main(int argc, char** argv) 
  {
    if(argc&gt;1)
    {
      open(); 
    }
    else
    {
      create();
    }
  
      return (0);
  }
  </code></pre>
  <p>Run this program with no args, then another copy with args, and the first one will fail at the assert checking the <code>pthread_cond_signal()</code>.
  But change the order of the <code>open()</code> function to <code>mmap()</code> the <code>&quot;/sync</code>&quot; memory before the <code>&quot;/data&quot;</code> and it will all work fine.</p>
  <p>This seems like a major bug in LynxOS to me, but LynuxWorks claim that using mutex and condition variable within named shared memory in this way is not covered by the POSIX standard, so they are not interested.</p>
  <p>Can anyone determine if this code does actually violate POSIX?<br />
  Or does anyone have any convincing documentation that it is POSIX compliant?</p>
  <p><strong>Edit</strong>: we know that <code>PTHREAD_PROCESS_SHARED</code> is POSIX and is supported by LynxOS. The area of contention is whether mutexes and semaphores can be used within named shared memory (as we have done) or if POSIX only allows them to be used when one process creates and mmaps the shared memory and then forks the second process.</p>