title: Reading a C struct from POSIX shared memory in Python 3
body: <p>There exists a block of shared memory containing a C <code>struct</code> which itself contains an array of <code>struct</code>s. What I'm after is deeper in that array. The layout in source looks roughly like the following:</p>
  
  <p>(tl;dr - how would you do this?)</p>
  
  <pre class="lang-c prettyprint-override"><code>struct proc_data
  {
    pid_t proc_id;
    bool initialized;
    bool suppress;
    bool only;
    bool halt;
  
    pthread_mutex_t mutex_a;
    int64_t total_a;
    bool total_a_flag;
  
    pthread_mutex_t mutex_b;
    int64_t total_b;
    int64_t long_b;
    bool total_b_flag;
  
    pthread_mutex_t mutex_c;
    int64_t total_c;
    bool total_c_flag;
  
    pthread_mutex_t mutex_d;
    int64_t total_d;
    bool total_d_flag;
  
    std::atomic&lt;int&gt; garbage;
    std::atomic&lt;bool&gt; garbage2;
  };
  
  struct gloabl_data
  {
    bool initialized;
    bool global_suppress;
    bool global_only;
    bool global_halt;
  
    uint p_proc_data[50];   //offsets for the following array
    struct proc_data proc_data_arr[50];
  };
  </code></pre>
  
  <p>Pardon the anonymized naming conventions, but you know how it goes.</p>
  
  <p>I'm successfully able to read into this shared memory block using <code>sysv_ipc</code> and can even get so far as to read each program's PID as the first member of each array element. Neat. The code below is functional for me:</p>
  
  <pre class="lang-py prettyprint-override"><code>segment = SharedMemory(ftok(shm_keyfile, ord("r"), silence_warning = True))
  
  offsets = list()
  
  for i in range(0,50): #the hardcoded limit
      offsets.append(int.from_bytes(segment.read(byte_count=4, offset=4+4*i), byteorder='little'))
  
  for offset in offsets:
      pid = int.from_bytes(segment.read(byte_count=4, offset=offset), byteorder='little')
      if(pid == 0): continue
  
      proc = Process(pid)
      print(str(pid)+" "+str(proc.cmdline()))
  </code></pre>
  
  <p>However, once I get to the <code>pthread_mutex_t</code>s, it seems to all come apart. <code>sizeof(pthread_mutex_t)</code> is 40 bytes on my platform (x86_64), but of course there is probably some padding going on.</p>
  
  <p>The code below continues on within the <code>for offset in offsets</code> loop:</p>
  
  <pre class="lang-py prettyprint-override"><code>intra_offset = offset + 4
  
  initialized = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  suppress = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  only = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  halt = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little'))+"\n")
  intra_offset += 1
  
  intra_offset += sizeof_pthread_mutex_t # mutex_a
  total_a = int.from_bytes(segment.read(byte_count=8, offset=intra_offset), byteorder='little')))
  intra_offset += 8
  total_a_flag = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  
  intra_offset += sizeof_pthread_mutex_t # mutex_b
  total_b = int.from_bytes(segment.read(byte_count=8, offset=intra_offset), byteorder='little')))
  intra_offset += 8
  long_b = int.from_bytes(segment.read(byte_count=8, offset=intra_offset), byteorder='little')))
  intra_offset += 8
  total_b_flag = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  
  intra_offset += sizeof_pthread_mutex_t # mutex_c
  total_c = int.from_bytes(segment.read(byte_count=8, offset=intra_offset), byteorder='little')))
  intra_offset += 8
  c_flag = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  
  intra_offset += sizeof_pthread_mutex_t # open pnl mutex
  total_d = int.from_bytes(segment.read(byte_count=8, offset=intra_offset), byteorder='little')))
  intra_offset += 8
  total_d_flag = int.from_bytes(segment.read(byte_count=1, offset=intra_offset), byteorder='little')))
  intra_offset += 1
  </code></pre>
  
  <p>And, of course, the values I get from that are just junk after the first mutex. I adjust my presumed size of the mutexes and add some padding here and there, but can't quite seem to get a good, sensible output.</p>
  
  <p>My actual question here is - is there a simpler way to do this? I haven't seen a suitable way to do this via Python's <code>ctypes</code>, though I'd love to go that route.</p>
  
  <p>Any and all feedback is welcome. =)</p>