ipc/glue/Shmem.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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 #include "Shmem.h"
michael@0 9
michael@0 10 #include "ProtocolUtils.h"
michael@0 11 #include "SharedMemoryBasic.h"
michael@0 12 #include "SharedMemorySysV.h"
michael@0 13
michael@0 14 #include "nsAutoPtr.h"
michael@0 15 #include "mozilla/unused.h"
michael@0 16
michael@0 17
michael@0 18 namespace mozilla {
michael@0 19 namespace ipc {
michael@0 20
michael@0 21 class ShmemCreated : public IPC::Message
michael@0 22 {
michael@0 23 private:
michael@0 24 typedef Shmem::id_t id_t;
michael@0 25
michael@0 26 public:
michael@0 27 ShmemCreated(int32_t routingId,
michael@0 28 const id_t& aIPDLId,
michael@0 29 const size_t& aSize,
michael@0 30 const SharedMemoryBasic::Handle& aHandle) :
michael@0 31 IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL)
michael@0 32 {
michael@0 33 IPC::WriteParam(this, aIPDLId);
michael@0 34 IPC::WriteParam(this, aSize);
michael@0 35 IPC::WriteParam(this, int32_t(SharedMemory::TYPE_BASIC)),
michael@0 36 IPC::WriteParam(this, aHandle);
michael@0 37 }
michael@0 38
michael@0 39 // Instead of a single Read() function, we have ReadInfo() and
michael@0 40 // ReadHandle(). The reason is that the handle type is specific to
michael@0 41 // the shmem type. These functions should only be called in the
michael@0 42 // order ReadInfo(); ReadHandle();, and only once each.
michael@0 43
michael@0 44 static bool
michael@0 45 ReadInfo(const Message* msg, void** iter,
michael@0 46 id_t* aIPDLId,
michael@0 47 size_t* aSize,
michael@0 48 SharedMemory::SharedMemoryType* aType)
michael@0 49 {
michael@0 50 if (!IPC::ReadParam(msg, iter, aIPDLId) ||
michael@0 51 !IPC::ReadParam(msg, iter, aSize) ||
michael@0 52 !IPC::ReadParam(msg, iter, reinterpret_cast<int32_t*>(aType)))
michael@0 53 return false;
michael@0 54 return true;
michael@0 55 }
michael@0 56
michael@0 57 static bool
michael@0 58 ReadHandle(const Message* msg, void** iter,
michael@0 59 SharedMemoryBasic::Handle* aHandle)
michael@0 60 {
michael@0 61 if (!IPC::ReadParam(msg, iter, aHandle))
michael@0 62 return false;
michael@0 63 msg->EndRead(*iter);
michael@0 64 return true;
michael@0 65 }
michael@0 66
michael@0 67 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 68 ShmemCreated(int32_t routingId,
michael@0 69 const id_t& aIPDLId,
michael@0 70 const size_t& aSize,
michael@0 71 const SharedMemorySysV::Handle& aHandle) :
michael@0 72 IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL)
michael@0 73 {
michael@0 74 IPC::WriteParam(this, aIPDLId);
michael@0 75 IPC::WriteParam(this, aSize);
michael@0 76 IPC::WriteParam(this, int32_t(SharedMemory::TYPE_SYSV)),
michael@0 77 IPC::WriteParam(this, aHandle);
michael@0 78 }
michael@0 79
michael@0 80 static bool
michael@0 81 ReadHandle(const Message* msg, void** iter,
michael@0 82 SharedMemorySysV::Handle* aHandle)
michael@0 83 {
michael@0 84 if (!IPC::ReadParam(msg, iter, aHandle))
michael@0 85 return false;
michael@0 86 msg->EndRead(*iter);
michael@0 87 return true;
michael@0 88 }
michael@0 89 #endif
michael@0 90
michael@0 91 void Log(const std::string& aPrefix,
michael@0 92 FILE* aOutf) const
michael@0 93 {
michael@0 94 fputs("(special ShmemCreated msg)", aOutf);
michael@0 95 }
michael@0 96 };
michael@0 97
michael@0 98 class ShmemDestroyed : public IPC::Message
michael@0 99 {
michael@0 100 private:
michael@0 101 typedef Shmem::id_t id_t;
michael@0 102
michael@0 103 public:
michael@0 104 ShmemDestroyed(int32_t routingId,
michael@0 105 const id_t& aIPDLId) :
michael@0 106 IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE, PRIORITY_NORMAL)
michael@0 107 {
michael@0 108 IPC::WriteParam(this, aIPDLId);
michael@0 109 }
michael@0 110 };
michael@0 111
michael@0 112
michael@0 113 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 114 static Shmem::SharedMemory*
michael@0 115 CreateSegment(size_t aNBytes, SharedMemorySysV::Handle aHandle)
michael@0 116 {
michael@0 117 nsAutoPtr<SharedMemory> segment;
michael@0 118
michael@0 119 if (SharedMemorySysV::IsHandleValid(aHandle)) {
michael@0 120 segment = new SharedMemorySysV(aHandle);
michael@0 121 }
michael@0 122 else {
michael@0 123 segment = new SharedMemorySysV();
michael@0 124
michael@0 125 if (!segment->Create(aNBytes))
michael@0 126 return 0;
michael@0 127 }
michael@0 128 if (!segment->Map(aNBytes))
michael@0 129 return 0;
michael@0 130
michael@0 131 segment->AddRef();
michael@0 132 return segment.forget();
michael@0 133 }
michael@0 134 #endif
michael@0 135
michael@0 136 static Shmem::SharedMemory*
michael@0 137 CreateSegment(size_t aNBytes, SharedMemoryBasic::Handle aHandle)
michael@0 138 {
michael@0 139 nsAutoPtr<SharedMemory> segment;
michael@0 140
michael@0 141 if (SharedMemoryBasic::IsHandleValid(aHandle)) {
michael@0 142 segment = new SharedMemoryBasic(aHandle);
michael@0 143 }
michael@0 144 else {
michael@0 145 segment = new SharedMemoryBasic();
michael@0 146
michael@0 147 if (!segment->Create(aNBytes))
michael@0 148 return 0;
michael@0 149 }
michael@0 150 if (!segment->Map(aNBytes))
michael@0 151 return 0;
michael@0 152
michael@0 153 segment->AddRef();
michael@0 154 return segment.forget();
michael@0 155 }
michael@0 156
michael@0 157 static void
michael@0 158 DestroySegment(SharedMemory* aSegment)
michael@0 159 {
michael@0 160 // the SharedMemory dtor closes and unmaps the actual OS shmem segment
michael@0 161 if (aSegment)
michael@0 162 aSegment->Release();
michael@0 163 }
michael@0 164
michael@0 165
michael@0 166 #if defined(DEBUG)
michael@0 167
michael@0 168 static const char sMagic[] =
michael@0 169 "This little piggy went to market.\n"
michael@0 170 "This little piggy stayed at home.\n"
michael@0 171 "This little piggy has roast beef,\n"
michael@0 172 "This little piggy had none.\n"
michael@0 173 "And this little piggy cried \"Wee! Wee! Wee!\" all the way home";
michael@0 174
michael@0 175
michael@0 176 struct Header {
michael@0 177 // Don't use size_t or bool here because their size depends on the
michael@0 178 // architecture.
michael@0 179 uint32_t mSize;
michael@0 180 uint32_t mUnsafe;
michael@0 181 char mMagic[sizeof(sMagic)];
michael@0 182 };
michael@0 183
michael@0 184 static void
michael@0 185 GetSections(Shmem::SharedMemory* aSegment,
michael@0 186 Header** aHeader,
michael@0 187 char** aFrontSentinel,
michael@0 188 char** aData,
michael@0 189 char** aBackSentinel)
michael@0 190 {
michael@0 191 NS_ABORT_IF_FALSE(aSegment && aFrontSentinel && aData && aBackSentinel,
michael@0 192 "NULL param(s)");
michael@0 193
michael@0 194 *aFrontSentinel = reinterpret_cast<char*>(aSegment->memory());
michael@0 195 NS_ABORT_IF_FALSE(*aFrontSentinel, "NULL memory()");
michael@0 196
michael@0 197 *aHeader = reinterpret_cast<Header*>(*aFrontSentinel);
michael@0 198
michael@0 199 size_t pageSize = Shmem::SharedMemory::SystemPageSize();
michael@0 200 *aData = *aFrontSentinel + pageSize;
michael@0 201
michael@0 202 *aBackSentinel = *aFrontSentinel + aSegment->Size() - pageSize;
michael@0 203 }
michael@0 204
michael@0 205 static Header*
michael@0 206 GetHeader(Shmem::SharedMemory* aSegment)
michael@0 207 {
michael@0 208 Header* header;
michael@0 209 char* dontcare;
michael@0 210 GetSections(aSegment, &header, &dontcare, &dontcare, &dontcare);
michael@0 211 return header;
michael@0 212 }
michael@0 213
michael@0 214 static void
michael@0 215 Protect(SharedMemory* aSegment)
michael@0 216 {
michael@0 217 NS_ABORT_IF_FALSE(aSegment, "NULL segment");
michael@0 218 aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
michael@0 219 aSegment->Size(),
michael@0 220 RightsNone);
michael@0 221 }
michael@0 222
michael@0 223 static void
michael@0 224 Unprotect(SharedMemory* aSegment)
michael@0 225 {
michael@0 226 NS_ABORT_IF_FALSE(aSegment, "NULL segment");
michael@0 227 aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
michael@0 228 aSegment->Size(),
michael@0 229 RightsRead | RightsWrite);
michael@0 230 }
michael@0 231
michael@0 232 //
michael@0 233 // In debug builds, we specially allocate shmem segments. The layout
michael@0 234 // is as follows
michael@0 235 //
michael@0 236 // Page 0: "front sentinel"
michael@0 237 // size of mapping
michael@0 238 // magic bytes
michael@0 239 // Page 1 through n-1:
michael@0 240 // user data
michael@0 241 // Page n: "back sentinel"
michael@0 242 // [nothing]
michael@0 243 //
michael@0 244 // The mapping can be in one of the following states, wrt to the
michael@0 245 // current process.
michael@0 246 //
michael@0 247 // State "unmapped": all pages are mapped with no access rights.
michael@0 248 //
michael@0 249 // State "mapping": all pages are mapped with read/write access.
michael@0 250 //
michael@0 251 // State "mapped": the front and back sentinels are mapped with no
michael@0 252 // access rights, and all the other pages are mapped with
michael@0 253 // read/write access.
michael@0 254 //
michael@0 255 // When a SharedMemory segment is first allocated, it starts out in
michael@0 256 // the "mapping" state for the process that allocates the segment, and
michael@0 257 // in the "unmapped" state for the other process. The allocating
michael@0 258 // process will then create a Shmem, which takes the segment into the
michael@0 259 // "mapped" state, where it can be accessed by clients.
michael@0 260 //
michael@0 261 // When a Shmem is sent to another process in an IPDL message, the
michael@0 262 // segment transitions into the "unmapped" state for the sending
michael@0 263 // process, and into the "mapping" state for the receiving process.
michael@0 264 // The receiving process will then create a Shmem from the underlying
michael@0 265 // segment, and take the segment into the "mapped" state.
michael@0 266 //
michael@0 267 // In the "mapping" state, we use the front sentinel to verify the
michael@0 268 // integrity of the shmem segment. If valid, it has a size_t
michael@0 269 // containing the number of bytes the user allocated followed by the
michael@0 270 // magic bytes above.
michael@0 271 //
michael@0 272 // In the "mapped" state, the front and back sentinels have no access
michael@0 273 // rights. They act as guards against buffer overflows and underflows
michael@0 274 // in client code; if clients touch a sentinel, they die with SIGSEGV.
michael@0 275 //
michael@0 276 // The "unmapped" state is used to enforce single-owner semantics of
michael@0 277 // the shmem segment. If a process other than the current owner tries
michael@0 278 // to touch the segment, it dies with SIGSEGV.
michael@0 279 //
michael@0 280
michael@0 281 Shmem::Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 282 SharedMemory* aSegment, id_t aId) :
michael@0 283 mSegment(aSegment),
michael@0 284 mData(0),
michael@0 285 mSize(0)
michael@0 286 {
michael@0 287 NS_ABORT_IF_FALSE(mSegment, "NULL segment");
michael@0 288 NS_ABORT_IF_FALSE(aId != 0, "invalid ID");
michael@0 289
michael@0 290 Unprotect(mSegment);
michael@0 291
michael@0 292 Header* header;
michael@0 293 char* frontSentinel;
michael@0 294 char* data;
michael@0 295 char* backSentinel;
michael@0 296 GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel);
michael@0 297
michael@0 298 // do a quick validity check to avoid weird-looking crashes in libc
michael@0 299 char check = *frontSentinel;
michael@0 300 (void)check;
michael@0 301
michael@0 302 NS_ABORT_IF_FALSE(!strncmp(header->mMagic, sMagic, sizeof(sMagic)),
michael@0 303 "invalid segment");
michael@0 304 mSize = static_cast<size_t>(header->mSize);
michael@0 305
michael@0 306 size_t pageSize = SharedMemory::SystemPageSize();
michael@0 307 // transition into the "mapped" state by protecting the front and
michael@0 308 // back sentinels (which guard against buffer under/overflows)
michael@0 309 mSegment->Protect(frontSentinel, pageSize, RightsNone);
michael@0 310 mSegment->Protect(backSentinel, pageSize, RightsNone);
michael@0 311
michael@0 312 // don't set these until we know they're valid
michael@0 313 mData = data;
michael@0 314 mId = aId;
michael@0 315 }
michael@0 316
michael@0 317 void
michael@0 318 Shmem::AssertInvariants() const
michael@0 319 {
michael@0 320 NS_ABORT_IF_FALSE(mSegment, "NULL segment");
michael@0 321 NS_ABORT_IF_FALSE(mData, "NULL data pointer");
michael@0 322 NS_ABORT_IF_FALSE(mSize > 0, "invalid size");
michael@0 323 // if the segment isn't owned by the current process, these will
michael@0 324 // trigger SIGSEGV
michael@0 325 char checkMappingFront = *reinterpret_cast<char*>(mData);
michael@0 326 char checkMappingBack = *(reinterpret_cast<char*>(mData) + mSize - 1);
michael@0 327
michael@0 328 // avoid "unused" warnings for these variables:
michael@0 329 unused << checkMappingFront;
michael@0 330 unused << checkMappingBack;
michael@0 331 }
michael@0 332
michael@0 333 void
michael@0 334 Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
michael@0 335 {
michael@0 336 AssertInvariants();
michael@0 337
michael@0 338 size_t pageSize = SharedMemory::SystemPageSize();
michael@0 339 Header* header = GetHeader(mSegment);
michael@0 340
michael@0 341 // Open this up for reading temporarily
michael@0 342 mSegment->Protect(reinterpret_cast<char*>(header), pageSize, RightsRead);
michael@0 343
michael@0 344 if (!header->mUnsafe) {
michael@0 345 Protect(mSegment);
michael@0 346 } else {
michael@0 347 mSegment->Protect(reinterpret_cast<char*>(header), pageSize, RightsNone);
michael@0 348 }
michael@0 349 }
michael@0 350
michael@0 351 // static
michael@0 352 Shmem::SharedMemory*
michael@0 353 Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 354 size_t aNBytes,
michael@0 355 SharedMemoryType aType,
michael@0 356 bool aUnsafe,
michael@0 357 bool aProtect)
michael@0 358 {
michael@0 359 NS_ASSERTION(aNBytes <= UINT32_MAX, "Will truncate shmem segment size!");
michael@0 360 NS_ABORT_IF_FALSE(!aProtect || !aUnsafe, "protect => !unsafe");
michael@0 361
michael@0 362 size_t pageSize = SharedMemory::SystemPageSize();
michael@0 363 SharedMemory* segment = nullptr;
michael@0 364 // |2*pageSize| is for the front and back sentinel
michael@0 365 size_t segmentSize = SharedMemory::PageAlignedSize(aNBytes + 2*pageSize);
michael@0 366
michael@0 367 if (aType == SharedMemory::TYPE_BASIC)
michael@0 368 segment = CreateSegment(segmentSize, SharedMemoryBasic::NULLHandle());
michael@0 369 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 370 else if (aType == SharedMemory::TYPE_SYSV)
michael@0 371 segment = CreateSegment(segmentSize, SharedMemorySysV::NULLHandle());
michael@0 372 #endif
michael@0 373 else {
michael@0 374 NS_ERROR("unknown shmem type");
michael@0 375 return nullptr;
michael@0 376 }
michael@0 377
michael@0 378 if (!segment)
michael@0 379 return 0;
michael@0 380
michael@0 381 Header* header;
michael@0 382 char *frontSentinel;
michael@0 383 char *data;
michael@0 384 char *backSentinel;
michael@0 385 GetSections(segment, &header, &frontSentinel, &data, &backSentinel);
michael@0 386
michael@0 387 // initialize the segment with Shmem-internal information
michael@0 388
michael@0 389 // NB: this can't be a static assert because technically pageSize
michael@0 390 // isn't known at compile time, event though in practice it's always
michael@0 391 // going to be 4KiB
michael@0 392 NS_ABORT_IF_FALSE(sizeof(Header) <= pageSize,
michael@0 393 "Shmem::Header has gotten too big");
michael@0 394 memcpy(header->mMagic, sMagic, sizeof(sMagic));
michael@0 395 header->mSize = static_cast<uint32_t>(aNBytes);
michael@0 396 header->mUnsafe = aUnsafe;
michael@0 397
michael@0 398 if (aProtect)
michael@0 399 Protect(segment);
michael@0 400
michael@0 401 return segment;
michael@0 402 }
michael@0 403
michael@0 404 // static
michael@0 405 Shmem::SharedMemory*
michael@0 406 Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 407 const IPC::Message& aDescriptor,
michael@0 408 id_t* aId,
michael@0 409 bool aProtect)
michael@0 410 {
michael@0 411 if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
michael@0 412 NS_ERROR("expected 'shmem created' message");
michael@0 413 return nullptr;
michael@0 414 }
michael@0 415
michael@0 416 void* iter = 0;
michael@0 417 SharedMemory::SharedMemoryType type;
michael@0 418 size_t size;
michael@0 419 if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
michael@0 420 return 0;
michael@0 421
michael@0 422 SharedMemory* segment = 0;
michael@0 423 size_t pageSize = SharedMemory::SystemPageSize();
michael@0 424 // |2*pageSize| is for the front and back sentinels
michael@0 425 size_t segmentSize = SharedMemory::PageAlignedSize(size + 2*pageSize);
michael@0 426
michael@0 427 if (SharedMemory::TYPE_BASIC == type) {
michael@0 428 SharedMemoryBasic::Handle handle;
michael@0 429 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
michael@0 430 return 0;
michael@0 431
michael@0 432 if (!SharedMemoryBasic::IsHandleValid(handle)) {
michael@0 433 NS_ERROR("trying to open invalid handle");
michael@0 434 return nullptr;
michael@0 435 }
michael@0 436 segment = CreateSegment(segmentSize, handle);
michael@0 437 }
michael@0 438 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 439 else if (SharedMemory::TYPE_SYSV == type) {
michael@0 440 SharedMemorySysV::Handle handle;
michael@0 441 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
michael@0 442 return 0;
michael@0 443
michael@0 444 if (!SharedMemorySysV::IsHandleValid(handle)) {
michael@0 445 NS_ERROR("trying to open invalid handle");
michael@0 446 return nullptr;
michael@0 447 }
michael@0 448 segment = CreateSegment(segmentSize, handle);
michael@0 449 }
michael@0 450 #endif
michael@0 451 else {
michael@0 452 NS_ERROR("unknown shmem type");
michael@0 453 return nullptr;
michael@0 454 }
michael@0 455
michael@0 456 if (!segment)
michael@0 457 return 0;
michael@0 458
michael@0 459 Header* header = GetHeader(segment);
michael@0 460
michael@0 461 if (size != header->mSize) {
michael@0 462 NS_ERROR("Wrong size for this Shmem!");
michael@0 463 delete segment;
michael@0 464 return nullptr;
michael@0 465 }
michael@0 466
michael@0 467 // The caller of this function may not know whether the segment is
michael@0 468 // unsafe or not
michael@0 469 if (!header->mUnsafe && aProtect)
michael@0 470 Protect(segment);
michael@0 471
michael@0 472 return segment;
michael@0 473 }
michael@0 474
michael@0 475 // static
michael@0 476 void
michael@0 477 Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 478 SharedMemory* aSegment)
michael@0 479 {
michael@0 480 if (!aSegment)
michael@0 481 return;
michael@0 482
michael@0 483 size_t pageSize = SharedMemory::SystemPageSize();
michael@0 484 Header* header;
michael@0 485 char *frontSentinel;
michael@0 486 char *data;
michael@0 487 char *backSentinel;
michael@0 488 GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel);
michael@0 489
michael@0 490 aSegment->Protect(frontSentinel, pageSize, RightsWrite | RightsRead);
michael@0 491 memset(header->mMagic, 0, sizeof(sMagic));
michael@0 492 header->mSize = 0;
michael@0 493 header->mUnsafe = false; // make it "safe" so as to catch errors
michael@0 494
michael@0 495 DestroySegment(aSegment);
michael@0 496 }
michael@0 497
michael@0 498
michael@0 499 #else // !defined(DEBUG)
michael@0 500
michael@0 501 // static
michael@0 502 Shmem::SharedMemory*
michael@0 503 Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 504 size_t aNBytes,
michael@0 505 SharedMemoryType aType,
michael@0 506 bool /*unused*/,
michael@0 507 bool /*unused*/)
michael@0 508 {
michael@0 509 SharedMemory *segment = nullptr;
michael@0 510
michael@0 511 if (aType == SharedMemory::TYPE_BASIC)
michael@0 512 segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)),
michael@0 513 SharedMemoryBasic::NULLHandle());
michael@0 514 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 515 else if (aType == SharedMemory::TYPE_SYSV)
michael@0 516 segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)),
michael@0 517 SharedMemorySysV::NULLHandle());
michael@0 518 #endif
michael@0 519 else {
michael@0 520 return nullptr;
michael@0 521 }
michael@0 522
michael@0 523 if (!segment)
michael@0 524 return 0;
michael@0 525
michael@0 526 *PtrToSize(segment) = static_cast<uint32_t>(aNBytes);
michael@0 527
michael@0 528 return segment;
michael@0 529 }
michael@0 530
michael@0 531 // static
michael@0 532 Shmem::SharedMemory*
michael@0 533 Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 534 const IPC::Message& aDescriptor,
michael@0 535 id_t* aId,
michael@0 536 bool /*unused*/)
michael@0 537 {
michael@0 538 if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
michael@0 539 return nullptr;
michael@0 540 }
michael@0 541
michael@0 542 SharedMemory::SharedMemoryType type;
michael@0 543 void* iter = 0;
michael@0 544 size_t size;
michael@0 545 if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
michael@0 546 return 0;
michael@0 547
michael@0 548 SharedMemory* segment = 0;
michael@0 549 size_t segmentSize = SharedMemory::PageAlignedSize(size + sizeof(uint32_t));
michael@0 550
michael@0 551 if (SharedMemory::TYPE_BASIC == type) {
michael@0 552 SharedMemoryBasic::Handle handle;
michael@0 553 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
michael@0 554 return 0;
michael@0 555
michael@0 556 if (!SharedMemoryBasic::IsHandleValid(handle)) {
michael@0 557 return nullptr;
michael@0 558 }
michael@0 559
michael@0 560 segment = CreateSegment(segmentSize, handle);
michael@0 561 }
michael@0 562 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 563 else if (SharedMemory::TYPE_SYSV == type) {
michael@0 564 SharedMemorySysV::Handle handle;
michael@0 565 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
michael@0 566 return 0;
michael@0 567
michael@0 568 if (!SharedMemorySysV::IsHandleValid(handle)) {
michael@0 569 return nullptr;
michael@0 570 }
michael@0 571 segment = CreateSegment(segmentSize, handle);
michael@0 572 }
michael@0 573 #endif
michael@0 574 else {
michael@0 575 return nullptr;
michael@0 576 }
michael@0 577
michael@0 578 if (!segment)
michael@0 579 return 0;
michael@0 580
michael@0 581 // this is the only validity check done in non-DEBUG builds
michael@0 582 if (size != static_cast<size_t>(*PtrToSize(segment))) {
michael@0 583 delete segment;
michael@0 584 return nullptr;
michael@0 585 }
michael@0 586
michael@0 587 return segment;
michael@0 588 }
michael@0 589
michael@0 590 // static
michael@0 591 void
michael@0 592 Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 593 SharedMemory* aSegment)
michael@0 594 {
michael@0 595 DestroySegment(aSegment);
michael@0 596 }
michael@0 597
michael@0 598 #endif // if defined(DEBUG)
michael@0 599
michael@0 600 int
michael@0 601 Shmem::GetSysVID() const
michael@0 602 {
michael@0 603 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 604 AssertInvariants();
michael@0 605
michael@0 606 if (mSegment->Type() != SharedMemory::TYPE_SYSV) {
michael@0 607 NS_ERROR("Can't call GetSysVID() on a non-SysV Shmem!");
michael@0 608 return -1;
michael@0 609 }
michael@0 610
michael@0 611 SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment);
michael@0 612 return seg->GetHandle();
michael@0 613 #else
michael@0 614 NS_ERROR("Can't call GetSysVID() with no support for SysV shared memory!");
michael@0 615 return -1; // not reached
michael@0 616 #endif
michael@0 617 }
michael@0 618
michael@0 619 IPC::Message*
michael@0 620 Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 621 base::ProcessHandle aProcess,
michael@0 622 int32_t routingId)
michael@0 623 {
michael@0 624 AssertInvariants();
michael@0 625
michael@0 626 if (SharedMemory::TYPE_BASIC == mSegment->Type()) {
michael@0 627 SharedMemoryBasic* seg = static_cast<SharedMemoryBasic*>(mSegment);
michael@0 628 SharedMemoryBasic::Handle handle;
michael@0 629 if (!seg->ShareToProcess(aProcess, &handle))
michael@0 630 return 0;
michael@0 631
michael@0 632 return new ShmemCreated(routingId, mId, mSize, handle);
michael@0 633 }
michael@0 634 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV
michael@0 635 else if (SharedMemory::TYPE_SYSV == mSegment->Type()) {
michael@0 636 SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment);
michael@0 637 return new ShmemCreated(routingId, mId, mSize, seg->GetHandle());
michael@0 638 }
michael@0 639 #endif
michael@0 640 else {
michael@0 641 NS_ABORT_IF_FALSE(false, "unknown shmem type (here?!)");
michael@0 642 return nullptr;
michael@0 643 }
michael@0 644
michael@0 645 return 0;
michael@0 646 }
michael@0 647
michael@0 648 IPC::Message*
michael@0 649 Shmem::UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
michael@0 650 base::ProcessHandle aProcess,
michael@0 651 int32_t routingId)
michael@0 652 {
michael@0 653 AssertInvariants();
michael@0 654 return new ShmemDestroyed(routingId, mId);
michael@0 655 }
michael@0 656
michael@0 657 } // namespace ipc
michael@0 658 } // namespace mozilla

mercurial