IPDL/Shmem

From MozillaWiki
Jump to navigation Jump to search

Introduction

IPDL provides a built-in Shmem type. Shmem represents a segment of memory mapped into both a parent's and child's address space. Shmems are used to avoid copying large amounts of data across the IPC pipe.

Ownership model

The model is very simple: at any given time, a Shmem is owned by either the parent or the child. Only the owner has read/write privileges; the other side has no privileges. One side transfers ownership of a Shmem to the other by sending the Shmem in an IPDL message, or returning it in a reply to a synchronous message.

It's illegal for C++ code to read/write a Shmem it doesn't own. We enforce ownership semantics by mapping segments with full read/write access in the owning process, and mapping them with no access in the other process. C++ code that violates the ownership model will die from a SEGFAULT.

Using Shmem in protocols

sync protocol UsesShmem {
child:
  // transfers ownership of |s| from parent to child
  HereYouGo(Shmem s);

parent:
  // transfers ownership of |s| from child to parent, then back to child
  GiveAndGetBack(Shmem s) returns (Shmem ss);
  // transfers ownership of |s| from child to parent
  ThanksDone(Shmem s);
};

WARNING: there's currently a bug in the IPDL compiler that needs to be worked around (the bug should be fixed "soon"). If you use Shmem in a managed (i.e. not top-level) protocol, then the top-level protocol needs to use Shmem as well. You can work around this with the following hack

protocol TopLevel {
  parent:  Dummy(Shmem _);
  // etc.
};

Using Shmem in C++

class Foo : public UsesShmemParent {
  using mozilla::ipc::Shmem;

  Shmem mShmem;

  bool Init() {
    // this may fail; always check return value
    if (!AllocShmem(&mShmem, 10000))
      return false;

    // get() and Size() check for proper alignment of the segment
    memset(mShmem.get<char>(), 0, mShmem.Size<char>());
  }

  bool Foo() {
    // [do stuff]

    char* p = mShmem.get<char>();
    if (!SendHereYouGo(mShmem))
      return false;

    // mShmem is now unusable; both of the following would fail:
    //   *p = 1;
    //   mShmem.get<char>();
  } 
  NS_OVERRIDE virtual bool
  RecvGiveAndGetBack(Shmem& s, Shmem* ss) {
    // we own |s| again

    // [do stuff with |s|]

    *ss = s;
    // when this method returns, we don't own |s| anymore
  }

  NS_OVERRIDE virtual bool
  RecvThanksDone(Shmem& s) {
    // we own |s| again
    mShmem = s;
  }
};

Shmems are automatically managed by IPDL-generated code. When your protocol tree is deleted, all Shmems still open are unmapped and deleted.

Aside: it's not necessary to know this, but Shmems are actually just handles to other objects managed by IPDL-generated code.