ipc/glue/Shmem.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial