LCOV - code coverage report
Current view: top level - ipc/glue - Shmem.h (source / functions) Hit Total Coverage
Test: output.info Lines: 45 52 86.5 %
Date: 2017-07-14 16:53:18 Functions: 12 19 63.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_ipc_Shmem_h
       8             : #define mozilla_ipc_Shmem_h
       9             : 
      10             : #include "mozilla/Attributes.h"
      11             : 
      12             : #include "base/basictypes.h"
      13             : #include "base/process.h"
      14             : 
      15             : #include "nscore.h"
      16             : #include "nsDebug.h"
      17             : 
      18             : #include "ipc/IPCMessageUtils.h"
      19             : #include "mozilla/ipc/SharedMemory.h"
      20             : 
      21             : /**
      22             :  * |Shmem| is one agent in the IPDL shared memory scheme.  The way it
      23             :     works is essentially
      24             :  *
      25             :  *  (1) C++ code calls, say, |parentActor->AllocShmem(size)|
      26             : 
      27             :  *  (2) IPDL-generated code creates a |mozilla::ipc::SharedMemory|
      28             :  *  wrapping the bare OS shmem primitives.  The code then adds the new
      29             :  *  SharedMemory to the set of shmem segments being managed by IPDL.
      30             :  *
      31             :  *  (3) IPDL-generated code "shares" the new SharedMemory to the child
      32             :  *  process, and then sends a special asynchronous IPC message to the
      33             :  *  child notifying it of the creation of the segment.  (What this
      34             :  *  means is OS specific.)
      35             :  *
      36             :  *  (4a) The child receives the special IPC message, and using the
      37             :  *  |SharedMemory{Basic}::Handle| it was passed, creates a
      38             :  *  |mozilla::ipc::SharedMemory| in the child
      39             :  *  process.
      40             :  *
      41             :  *  (4b) After sending the "shmem-created" IPC message, IPDL-generated
      42             :  *  code in the parent returns a |mozilla::ipc::Shmem| back to the C++
      43             :  *  caller of |parentActor->AllocShmem()|.  The |Shmem| is a "weak
      44             :  *  reference" to the underlying |SharedMemory|, which is managed by
      45             :  *  IPDL-generated code.  C++ consumers of |Shmem| can't get at the
      46             :  *  underlying |SharedMemory|.
      47             :  *
      48             :  * If parent code wants to give access rights to the Shmem to the
      49             :  * child, it does so by sending its |Shmem| to the child, in an IPDL
      50             :  * message.  The parent's |Shmem| then "dies", i.e. becomes
      51             :  * inaccessible.  This process could be compared to passing a
      52             :  * "shmem-access baton" between parent and child.
      53             :  */
      54             : 
      55             : namespace mozilla {
      56             : namespace layers {
      57             : class ShadowLayerForwarder;
      58             : } // namespace layers
      59             : 
      60             : namespace ipc {
      61             : 
      62             : class Shmem final
      63             : {
      64             :   friend struct IPC::ParamTraits<mozilla::ipc::Shmem>;
      65             : #ifdef DEBUG
      66             :   // For ShadowLayerForwarder::CheckSurfaceDescriptor
      67             :   friend class mozilla::layers::ShadowLayerForwarder;
      68             : #endif
      69             : 
      70             : public:
      71             :   typedef int32_t id_t;
      72             :   // Low-level wrapper around platform shmem primitives.
      73             :   typedef mozilla::ipc::SharedMemory SharedMemory;
      74             :   typedef SharedMemory::SharedMemoryType SharedMemoryType;
      75             :   struct IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead {};
      76             : 
      77          10 :   Shmem() :
      78             :     mSegment(nullptr),
      79             :     mData(nullptr),
      80             :     mSize(0),
      81          10 :     mId(0)
      82             :   {
      83          10 :   }
      84             : 
      85           7 :   Shmem(const Shmem& aOther) :
      86             :     mSegment(aOther.mSegment),
      87           7 :     mData(aOther.mData),
      88           7 :     mSize(aOther.mSize),
      89          21 :     mId(aOther.mId)
      90             :   {
      91           7 :   }
      92             : 
      93             : #if !defined(DEBUG)
      94             :   Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
      95             :         SharedMemory* aSegment, id_t aId) :
      96             :     mSegment(aSegment),
      97             :     mData(aSegment->memory()),
      98             :     mSize(0),
      99             :     mId(aId)
     100             :   {
     101             :     mSize = static_cast<size_t>(*PtrToSize(mSegment));
     102             :   }
     103             : #else
     104             :   Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
     105             :         SharedMemory* aSegment, id_t aId);
     106             : #endif
     107             : 
     108          20 :   ~Shmem()
     109          20 :   {
     110             :     // Shmem only holds a "weak ref" to the actual segment, which is
     111             :     // owned by IPDL. So there's nothing interesting to be done here
     112          20 :     forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
     113          20 :   }
     114             : 
     115           8 :   Shmem& operator=(const Shmem& aRhs)
     116             :   {
     117           8 :     mSegment = aRhs.mSegment;
     118           8 :     mData = aRhs.mData;
     119           8 :     mSize = aRhs.mSize;
     120           8 :     mId = aRhs.mId;
     121           8 :     return *this;
     122             :   }
     123             : 
     124           0 :   bool operator==(const Shmem& aRhs) const
     125             :   {
     126           0 :     return mSegment == aRhs.mSegment;
     127             :   }
     128             : 
     129             :   // Returns whether this Shmem is writable by you, and thus whether you can
     130             :   // transfer writability to another actor.
     131             :   bool
     132           0 :   IsWritable() const
     133             :   {
     134           0 :     return mSegment != nullptr;
     135             :   }
     136             : 
     137             :   // Returns whether this Shmem is readable by you, and thus whether you can
     138             :   // transfer readability to another actor.
     139             :   bool
     140           1 :   IsReadable() const
     141             :   {
     142           1 :     return mSegment != nullptr;
     143             :   }
     144             : 
     145             :   // Return a pointer to the user-visible data segment.
     146             :   template<typename T>
     147             :   T*
     148           4 :   get() const
     149             :   {
     150           4 :     AssertInvariants();
     151           4 :     AssertAligned<T>();
     152             : 
     153           4 :     return reinterpret_cast<T*>(mData);
     154             :   }
     155             : 
     156             :   // Return the size of the segment as requested when this shmem
     157             :   // segment was allocated, in units of T.  The underlying mapping may
     158             :   // actually be larger because of page alignment and private data,
     159             :   // but this isn't exposed to clients.
     160             :   template<typename T>
     161             :   size_t
     162           1 :   Size() const
     163             :   {
     164           1 :     AssertInvariants();
     165           1 :     AssertAligned<T>();
     166             : 
     167           1 :     return mSize / sizeof(T);
     168             :   }
     169             : 
     170             :   // These shouldn't be used directly, use the IPDL interface instead.
     171           5 :   id_t Id(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const {
     172           5 :     return mId;
     173             :   }
     174             : 
     175             :   SharedMemory* Segment(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const {
     176             :     return mSegment;
     177             :   }
     178             : 
     179             : #ifndef DEBUG
     180             :   void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
     181             :   {
     182             :   }
     183             : #else
     184             :   void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead);
     185             : #endif
     186             : 
     187          23 :   void forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
     188             :   {
     189          23 :     mSegment = nullptr;
     190          23 :     mData = nullptr;
     191          23 :     mSize = 0;
     192          23 :     mId = 0;
     193          23 :   }
     194             : 
     195             :   static already_AddRefed<Shmem::SharedMemory>
     196             :   Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
     197             :         size_t aNBytes,
     198             :         SharedMemoryType aType,
     199             :         bool aUnsafe,
     200             :         bool aProtect=false);
     201             : 
     202             :   // Prepare this to be shared with |aProcess|.  Return an IPC message
     203             :   // that contains enough information for the other process to map
     204             :   // this segment in OpenExisting() below.  Return a new message if
     205             :   // successful (owned by the caller), nullptr if not.
     206             :   IPC::Message*
     207             :   ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
     208             :           base::ProcessId aTargetPid,
     209             :           int32_t routingId);
     210             : 
     211             :   // Stop sharing this with |aTargetPid|.  Return an IPC message that
     212             :   // contains enough information for the other process to unmap this
     213             :   // segment.  Return a new message if successful (owned by the
     214             :   // caller), nullptr if not.
     215             :   IPC::Message*
     216             :   UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
     217             :               base::ProcessId aTargetPid,
     218             :               int32_t routingId);
     219             : 
     220             :   // Return a SharedMemory instance in this process using the
     221             :   // descriptor shared to us by the process that created the
     222             :   // underlying OS shmem resource.  The contents of the descriptor
     223             :   // depend on the type of SharedMemory that was passed to us.
     224             :   static already_AddRefed<SharedMemory>
     225             :   OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
     226             :                const IPC::Message& aDescriptor,
     227             :                id_t* aId,
     228             :                bool aProtect=false);
     229             : 
     230             :   static void
     231             :   Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
     232             :           SharedMemory* aSegment);
     233             : 
     234             : private:
     235             :   template<typename T>
     236           5 :   void AssertAligned() const
     237             :   {
     238           0 :     if (0 != (mSize % sizeof(T)))
     239           0 :       MOZ_CRASH("shmem is not T-aligned");
     240           5 :   }
     241             : 
     242             : #if !defined(DEBUG)
     243             :   void AssertInvariants() const
     244             :   { }
     245             : 
     246             :   static uint32_t*
     247             :   PtrToSize(SharedMemory* aSegment)
     248             :   {
     249             :     char* endOfSegment =
     250             :       reinterpret_cast<char*>(aSegment->memory()) + aSegment->Size();
     251             :     return reinterpret_cast<uint32_t*>(endOfSegment - sizeof(uint32_t));
     252             :   }
     253             : 
     254             : #else
     255             :   void AssertInvariants() const;
     256             : #endif
     257             : 
     258             :   RefPtr<SharedMemory> mSegment;
     259             :   void* mData;
     260             :   size_t mSize;
     261             :   id_t mId;
     262             : };
     263             : 
     264             : 
     265             : } // namespace ipc
     266             : } // namespace mozilla
     267             : 
     268             : 
     269             : namespace IPC {
     270             : 
     271             : template<>
     272             : struct ParamTraits<mozilla::ipc::Shmem>
     273             : {
     274             :   typedef mozilla::ipc::Shmem paramType;
     275             : 
     276             :   // NB: Read()/Write() look creepy in that Shmems have a pointer
     277             :   // member, but IPDL internally uses mId to properly initialize a
     278             :   // "real" Shmem
     279             : 
     280           3 :   static void Write(Message* aMsg, const paramType& aParam)
     281             :   {
     282           3 :     WriteParam(aMsg, aParam.mId);
     283           3 :   }
     284             : 
     285           2 :   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
     286             :   {
     287             :     paramType::id_t id;
     288           2 :     if (!ReadParam(aMsg, aIter, &id))
     289           0 :       return false;
     290           2 :     aResult->mId = id;
     291           2 :     return true;
     292             :   }
     293             : 
     294             :   static void Log(const paramType& aParam, std::wstring* aLog)
     295             :   {
     296             :     aLog->append(L"(shmem segment)");
     297             :   }
     298             : };
     299             : 
     300             : 
     301             : } // namespace IPC
     302             : 
     303             : 
     304             : #endif // ifndef mozilla_ipc_Shmem_h

Generated by: LCOV version 1.13