2009-12-04 18:45:15 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* vim: sw=2 ts=8 et :
|
|
|
|
*/
|
2012-05-21 11:12:37 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
#include "Shmem.h"
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
#include "ProtocolUtils.h"
|
|
|
|
#include "SharedMemoryBasic.h"
|
|
|
|
#include "SharedMemorySysV.h"
|
|
|
|
|
2011-06-24 21:01:30 +00:00
|
|
|
#include "mozilla/unused.h"
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
namespace mozilla {
|
|
|
|
namespace ipc {
|
|
|
|
|
|
|
|
class ShmemCreated : public IPC::Message
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
typedef Shmem::id_t id_t;
|
|
|
|
|
|
|
|
public:
|
2012-09-17 08:37:20 +00:00
|
|
|
ShmemCreated(int32_t routingId,
|
2010-04-16 05:29:16 +00:00
|
|
|
const id_t& aIPDLId,
|
|
|
|
const size_t& aSize,
|
|
|
|
const SharedMemoryBasic::Handle& aHandle) :
|
|
|
|
IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL)
|
|
|
|
{
|
|
|
|
IPC::WriteParam(this, aIPDLId);
|
|
|
|
IPC::WriteParam(this, aSize);
|
2012-09-17 08:37:20 +00:00
|
|
|
IPC::WriteParam(this, int32_t(SharedMemory::TYPE_BASIC)),
|
2010-04-16 05:29:16 +00:00
|
|
|
IPC::WriteParam(this, aHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instead of a single Read() function, we have ReadInfo() and
|
|
|
|
// ReadHandle(). The reason is that the handle type is specific to
|
|
|
|
// the shmem type. These functions should only be called in the
|
|
|
|
// order ReadInfo(); ReadHandle();, and only once each.
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ReadInfo(const Message* msg, void** iter,
|
|
|
|
id_t* aIPDLId,
|
|
|
|
size_t* aSize,
|
|
|
|
SharedMemory::SharedMemoryType* aType)
|
|
|
|
{
|
|
|
|
if (!IPC::ReadParam(msg, iter, aIPDLId) ||
|
|
|
|
!IPC::ReadParam(msg, iter, aSize) ||
|
2012-09-17 08:37:20 +00:00
|
|
|
!IPC::ReadParam(msg, iter, reinterpret_cast<int32_t*>(aType)))
|
2010-04-16 05:29:16 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ReadHandle(const Message* msg, void** iter,
|
|
|
|
SharedMemoryBasic::Handle* aHandle)
|
|
|
|
{
|
|
|
|
if (!IPC::ReadParam(msg, iter, aHandle))
|
|
|
|
return false;
|
|
|
|
msg->EndRead(*iter);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
2012-09-17 08:37:20 +00:00
|
|
|
ShmemCreated(int32_t routingId,
|
2010-04-16 05:29:16 +00:00
|
|
|
const id_t& aIPDLId,
|
|
|
|
const size_t& aSize,
|
|
|
|
const SharedMemorySysV::Handle& aHandle) :
|
|
|
|
IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL)
|
|
|
|
{
|
|
|
|
IPC::WriteParam(this, aIPDLId);
|
|
|
|
IPC::WriteParam(this, aSize);
|
2012-09-17 08:37:20 +00:00
|
|
|
IPC::WriteParam(this, int32_t(SharedMemory::TYPE_SYSV)),
|
2010-04-16 05:29:16 +00:00
|
|
|
IPC::WriteParam(this, aHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ReadHandle(const Message* msg, void** iter,
|
|
|
|
SharedMemorySysV::Handle* aHandle)
|
|
|
|
{
|
|
|
|
if (!IPC::ReadParam(msg, iter, aHandle))
|
|
|
|
return false;
|
|
|
|
msg->EndRead(*iter);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void Log(const std::string& aPrefix,
|
|
|
|
FILE* aOutf) const
|
|
|
|
{
|
|
|
|
fputs("(special ShmemCreated msg)", aOutf);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-04-27 01:11:40 +00:00
|
|
|
class ShmemDestroyed : public IPC::Message
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
typedef Shmem::id_t id_t;
|
|
|
|
|
|
|
|
public:
|
2012-09-17 08:37:20 +00:00
|
|
|
ShmemDestroyed(int32_t routingId,
|
2010-04-27 01:11:40 +00:00
|
|
|
const id_t& aIPDLId) :
|
|
|
|
IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE, PRIORITY_NORMAL)
|
|
|
|
{
|
|
|
|
IPC::WriteParam(this, aIPDLId);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
2014-07-25 23:41:25 +00:00
|
|
|
static already_AddRefed<Shmem::SharedMemory>
|
2010-04-16 05:29:16 +00:00
|
|
|
CreateSegment(size_t aNBytes, SharedMemorySysV::Handle aHandle)
|
|
|
|
{
|
2014-07-25 23:41:25 +00:00
|
|
|
nsRefPtr<SharedMemory> segment;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
if (SharedMemorySysV::IsHandleValid(aHandle)) {
|
|
|
|
segment = new SharedMemorySysV(aHandle);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
segment = new SharedMemorySysV();
|
|
|
|
|
|
|
|
if (!segment->Create(aNBytes))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
}
|
|
|
|
if (!segment->Map(aNBytes))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-05-22 19:35:32 +00:00
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
return segment.forget();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
static already_AddRefed<Shmem::SharedMemory>
|
2010-04-16 05:29:16 +00:00
|
|
|
CreateSegment(size_t aNBytes, SharedMemoryBasic::Handle aHandle)
|
|
|
|
{
|
2014-07-25 23:41:25 +00:00
|
|
|
nsRefPtr<SharedMemory> segment;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
if (SharedMemoryBasic::IsHandleValid(aHandle)) {
|
|
|
|
segment = new SharedMemoryBasic(aHandle);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
segment = new SharedMemoryBasic();
|
|
|
|
|
|
|
|
if (!segment->Create(aNBytes))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
}
|
|
|
|
if (!segment->Map(aNBytes))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-05-22 19:35:32 +00:00
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
return segment.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DestroySegment(SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
// the SharedMemory dtor closes and unmaps the actual OS shmem segment
|
2010-05-22 19:35:32 +00:00
|
|
|
if (aSegment)
|
|
|
|
aSegment->Release();
|
2010-04-16 05:29:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
#if defined(DEBUG)
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
static const char sMagic[] =
|
|
|
|
"This little piggy went to market.\n"
|
|
|
|
"This little piggy stayed at home.\n"
|
|
|
|
"This little piggy has roast beef,\n"
|
|
|
|
"This little piggy had none.\n"
|
|
|
|
"And this little piggy cried \"Wee! Wee! Wee!\" all the way home";
|
|
|
|
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
struct Header {
|
2010-11-05 07:17:07 +00:00
|
|
|
// Don't use size_t or bool here because their size depends on the
|
|
|
|
// architecture.
|
2012-09-17 08:37:20 +00:00
|
|
|
uint32_t mSize;
|
|
|
|
uint32_t mUnsafe;
|
2009-12-04 18:45:15 +00:00
|
|
|
char mMagic[sizeof(sMagic)];
|
|
|
|
};
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
static void
|
2009-12-04 18:45:15 +00:00
|
|
|
GetSections(Shmem::SharedMemory* aSegment,
|
2010-11-05 07:17:07 +00:00
|
|
|
Header** aHeader,
|
2009-12-04 18:45:15 +00:00
|
|
|
char** aFrontSentinel,
|
|
|
|
char** aData,
|
|
|
|
char** aBackSentinel)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(aSegment && aFrontSentinel && aData && aBackSentinel,
|
|
|
|
"null param(s)");
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
*aFrontSentinel = reinterpret_cast<char*>(aSegment->memory());
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(*aFrontSentinel, "null memory()");
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2010-11-05 07:17:07 +00:00
|
|
|
*aHeader = reinterpret_cast<Header*>(*aFrontSentinel);
|
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
size_t pageSize = Shmem::SharedMemory::SystemPageSize();
|
|
|
|
*aData = *aFrontSentinel + pageSize;
|
|
|
|
|
|
|
|
*aBackSentinel = *aFrontSentinel + aSegment->Size() - pageSize;
|
|
|
|
}
|
|
|
|
|
2010-11-05 07:17:07 +00:00
|
|
|
static Header*
|
|
|
|
GetHeader(Shmem::SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
Header* header;
|
|
|
|
char* dontcare;
|
|
|
|
GetSections(aSegment, &header, &dontcare, &dontcare, &dontcare);
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
static void
|
|
|
|
Protect(SharedMemory* aSegment)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(aSegment, "null segment");
|
2010-04-16 05:29:16 +00:00
|
|
|
aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
|
|
|
|
aSegment->Size(),
|
|
|
|
RightsNone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Unprotect(SharedMemory* aSegment)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(aSegment, "null segment");
|
2010-04-16 05:29:16 +00:00
|
|
|
aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
|
|
|
|
aSegment->Size(),
|
|
|
|
RightsRead | RightsWrite);
|
|
|
|
}
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// In debug builds, we specially allocate shmem segments. The layout
|
|
|
|
// is as follows
|
|
|
|
//
|
|
|
|
// Page 0: "front sentinel"
|
|
|
|
// size of mapping
|
|
|
|
// magic bytes
|
|
|
|
// Page 1 through n-1:
|
|
|
|
// user data
|
|
|
|
// Page n: "back sentinel"
|
|
|
|
// [nothing]
|
|
|
|
//
|
|
|
|
// The mapping can be in one of the following states, wrt to the
|
|
|
|
// current process.
|
|
|
|
//
|
|
|
|
// State "unmapped": all pages are mapped with no access rights.
|
|
|
|
//
|
|
|
|
// State "mapping": all pages are mapped with read/write access.
|
|
|
|
//
|
|
|
|
// State "mapped": the front and back sentinels are mapped with no
|
|
|
|
// access rights, and all the other pages are mapped with
|
|
|
|
// read/write access.
|
|
|
|
//
|
|
|
|
// When a SharedMemory segment is first allocated, it starts out in
|
|
|
|
// the "mapping" state for the process that allocates the segment, and
|
|
|
|
// in the "unmapped" state for the other process. The allocating
|
|
|
|
// process will then create a Shmem, which takes the segment into the
|
|
|
|
// "mapped" state, where it can be accessed by clients.
|
|
|
|
//
|
|
|
|
// When a Shmem is sent to another process in an IPDL message, the
|
|
|
|
// segment transitions into the "unmapped" state for the sending
|
|
|
|
// process, and into the "mapping" state for the receiving process.
|
|
|
|
// The receiving process will then create a Shmem from the underlying
|
|
|
|
// segment, and take the segment into the "mapped" state.
|
|
|
|
//
|
|
|
|
// In the "mapping" state, we use the front sentinel to verify the
|
|
|
|
// integrity of the shmem segment. If valid, it has a size_t
|
|
|
|
// containing the number of bytes the user allocated followed by the
|
|
|
|
// magic bytes above.
|
|
|
|
//
|
|
|
|
// In the "mapped" state, the front and back sentinels have no access
|
|
|
|
// rights. They act as guards against buffer overflows and underflows
|
|
|
|
// in client code; if clients touch a sentinel, they die with SIGSEGV.
|
|
|
|
//
|
|
|
|
// The "unmapped" state is used to enforce single-owner semantics of
|
|
|
|
// the shmem segment. If a process other than the current owner tries
|
|
|
|
// to touch the segment, it dies with SIGSEGV.
|
|
|
|
//
|
|
|
|
|
|
|
|
Shmem::Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
SharedMemory* aSegment, id_t aId) :
|
|
|
|
mSegment(aSegment),
|
2014-07-15 23:51:44 +00:00
|
|
|
mData(nullptr),
|
2009-12-04 18:45:15 +00:00
|
|
|
mSize(0)
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(mSegment, "null segment");
|
|
|
|
MOZ_ASSERT(aId != 0, "invalid ID");
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
Unprotect(mSegment);
|
|
|
|
|
2010-11-05 07:17:07 +00:00
|
|
|
Header* header;
|
2009-12-04 18:45:15 +00:00
|
|
|
char* frontSentinel;
|
|
|
|
char* data;
|
|
|
|
char* backSentinel;
|
2010-11-05 07:17:07 +00:00
|
|
|
GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel);
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
// do a quick validity check to avoid weird-looking crashes in libc
|
|
|
|
char check = *frontSentinel;
|
|
|
|
(void)check;
|
|
|
|
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(!strncmp(header->mMagic, sMagic, sizeof(sMagic)),
|
|
|
|
"invalid segment");
|
2010-08-31 17:51:51 +00:00
|
|
|
mSize = static_cast<size_t>(header->mSize);
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
|
|
|
// transition into the "mapped" state by protecting the front and
|
|
|
|
// back sentinels (which guard against buffer under/overflows)
|
|
|
|
mSegment->Protect(frontSentinel, pageSize, RightsNone);
|
|
|
|
mSegment->Protect(backSentinel, pageSize, RightsNone);
|
|
|
|
|
|
|
|
// don't set these until we know they're valid
|
|
|
|
mData = data;
|
|
|
|
mId = aId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Shmem::AssertInvariants() const
|
|
|
|
{
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(mSegment, "null segment");
|
|
|
|
MOZ_ASSERT(mData, "null data pointer");
|
|
|
|
MOZ_ASSERT(mSize > 0, "invalid size");
|
2009-12-04 18:45:15 +00:00
|
|
|
// if the segment isn't owned by the current process, these will
|
|
|
|
// trigger SIGSEGV
|
|
|
|
char checkMappingFront = *reinterpret_cast<char*>(mData);
|
|
|
|
char checkMappingBack = *(reinterpret_cast<char*>(mData) + mSize - 1);
|
2011-06-24 21:01:30 +00:00
|
|
|
|
|
|
|
// avoid "unused" warnings for these variables:
|
|
|
|
unused << checkMappingFront;
|
|
|
|
unused << checkMappingBack;
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-04-16 05:29:16 +00:00
|
|
|
Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
2009-12-04 18:45:15 +00:00
|
|
|
{
|
2010-04-16 05:29:16 +00:00
|
|
|
AssertInvariants();
|
2010-11-05 07:17:07 +00:00
|
|
|
|
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
|
|
|
Header* header = GetHeader(mSegment);
|
|
|
|
|
|
|
|
// Open this up for reading temporarily
|
|
|
|
mSegment->Protect(reinterpret_cast<char*>(header), pageSize, RightsRead);
|
|
|
|
|
|
|
|
if (!header->mUnsafe) {
|
|
|
|
Protect(mSegment);
|
|
|
|
} else {
|
|
|
|
mSegment->Protect(reinterpret_cast<char*>(header), pageSize, RightsNone);
|
|
|
|
}
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
// static
|
2014-07-25 23:41:25 +00:00
|
|
|
already_AddRefed<Shmem::SharedMemory>
|
2009-12-04 18:45:15 +00:00
|
|
|
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
size_t aNBytes,
|
2010-04-16 05:29:16 +00:00
|
|
|
SharedMemoryType aType,
|
2010-11-05 07:17:07 +00:00
|
|
|
bool aUnsafe,
|
2009-12-04 18:45:15 +00:00
|
|
|
bool aProtect)
|
|
|
|
{
|
2012-09-28 06:57:33 +00:00
|
|
|
NS_ASSERTION(aNBytes <= UINT32_MAX, "Will truncate shmem segment size!");
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(!aProtect || !aUnsafe, "protect => !unsafe");
|
2010-09-24 06:31:47 +00:00
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
2014-07-25 23:41:25 +00:00
|
|
|
nsRefPtr<SharedMemory> segment;
|
2009-12-04 18:45:15 +00:00
|
|
|
// |2*pageSize| is for the front and back sentinel
|
2010-11-05 07:17:07 +00:00
|
|
|
size_t segmentSize = SharedMemory::PageAlignedSize(aNBytes + 2*pageSize);
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
if (aType == SharedMemory::TYPE_BASIC)
|
|
|
|
segment = CreateSegment(segmentSize, SharedMemoryBasic::NULLHandle());
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (aType == SharedMemory::TYPE_SYSV)
|
|
|
|
segment = CreateSegment(segmentSize, SharedMemorySysV::NULLHandle());
|
|
|
|
#endif
|
2014-02-25 03:21:48 +00:00
|
|
|
else {
|
|
|
|
NS_ERROR("unknown shmem type");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
if (!segment)
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2010-11-05 07:17:07 +00:00
|
|
|
Header* header;
|
2009-12-04 18:45:15 +00:00
|
|
|
char *frontSentinel;
|
|
|
|
char *data;
|
|
|
|
char *backSentinel;
|
2010-11-05 07:17:07 +00:00
|
|
|
GetSections(segment, &header, &frontSentinel, &data, &backSentinel);
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
// initialize the segment with Shmem-internal information
|
2010-11-05 07:17:07 +00:00
|
|
|
|
|
|
|
// NB: this can't be a static assert because technically pageSize
|
|
|
|
// isn't known at compile time, event though in practice it's always
|
|
|
|
// going to be 4KiB
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(sizeof(Header) <= pageSize,
|
|
|
|
"Shmem::Header has gotten too big");
|
2009-12-04 18:45:15 +00:00
|
|
|
memcpy(header->mMagic, sMagic, sizeof(sMagic));
|
2012-09-17 08:37:20 +00:00
|
|
|
header->mSize = static_cast<uint32_t>(aNBytes);
|
2010-11-05 07:17:07 +00:00
|
|
|
header->mUnsafe = aUnsafe;
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
if (aProtect)
|
|
|
|
Protect(segment);
|
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
return segment.forget();
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
// static
|
2014-07-25 23:41:25 +00:00
|
|
|
already_AddRefed<Shmem::SharedMemory>
|
2009-12-04 18:45:15 +00:00
|
|
|
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
2010-04-16 05:29:16 +00:00
|
|
|
const IPC::Message& aDescriptor,
|
|
|
|
id_t* aId,
|
2009-12-04 18:45:15 +00:00
|
|
|
bool aProtect)
|
|
|
|
{
|
2014-02-25 03:21:48 +00:00
|
|
|
if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
|
|
|
|
NS_ERROR("expected 'shmem created' message");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2014-07-15 23:51:44 +00:00
|
|
|
void* iter = nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
SharedMemory::SharedMemoryType type;
|
|
|
|
size_t size;
|
|
|
|
if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
nsRefPtr<SharedMemory> segment;
|
2009-12-04 18:45:15 +00:00
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
|
|
|
// |2*pageSize| is for the front and back sentinels
|
2010-11-05 07:17:07 +00:00
|
|
|
size_t segmentSize = SharedMemory::PageAlignedSize(size + 2*pageSize);
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
if (SharedMemory::TYPE_BASIC == type) {
|
|
|
|
SharedMemoryBasic::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2014-02-25 03:21:48 +00:00
|
|
|
if (!SharedMemoryBasic::IsHandleValid(handle)) {
|
|
|
|
NS_ERROR("trying to open invalid handle");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (SharedMemory::TYPE_SYSV == type) {
|
|
|
|
SharedMemorySysV::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2014-02-25 03:21:48 +00:00
|
|
|
if (!SharedMemorySysV::IsHandleValid(handle)) {
|
|
|
|
NS_ERROR("trying to open invalid handle");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else {
|
2014-02-25 03:21:48 +00:00
|
|
|
NS_ERROR("unknown shmem type");
|
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
}
|
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
if (!segment)
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2014-02-26 19:10:55 +00:00
|
|
|
Header* header = GetHeader(segment);
|
|
|
|
|
|
|
|
if (size != header->mSize) {
|
|
|
|
NS_ERROR("Wrong size for this Shmem!");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2010-11-05 07:17:07 +00:00
|
|
|
// The caller of this function may not know whether the segment is
|
|
|
|
// unsafe or not
|
|
|
|
if (!header->mUnsafe && aProtect)
|
2009-12-04 18:45:15 +00:00
|
|
|
Protect(segment);
|
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
return segment.forget();
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
// static
|
2009-12-04 18:45:15 +00:00
|
|
|
void
|
|
|
|
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
if (!aSegment)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
2010-11-05 07:17:07 +00:00
|
|
|
Header* header;
|
2009-12-04 18:45:15 +00:00
|
|
|
char *frontSentinel;
|
|
|
|
char *data;
|
|
|
|
char *backSentinel;
|
2010-11-05 07:17:07 +00:00
|
|
|
GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel);
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
aSegment->Protect(frontSentinel, pageSize, RightsWrite | RightsRead);
|
|
|
|
memset(header->mMagic, 0, sizeof(sMagic));
|
|
|
|
header->mSize = 0;
|
2010-11-05 07:17:07 +00:00
|
|
|
header->mUnsafe = false; // make it "safe" so as to catch errors
|
2009-12-04 18:45:15 +00:00
|
|
|
|
|
|
|
DestroySegment(aSegment);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#else // !defined(DEBUG)
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
// static
|
2014-07-25 23:41:25 +00:00
|
|
|
already_AddRefed<Shmem::SharedMemory>
|
2009-12-04 18:45:15 +00:00
|
|
|
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
2014-07-15 23:51:44 +00:00
|
|
|
size_t aNBytes,
|
2010-04-16 05:29:16 +00:00
|
|
|
SharedMemoryType aType,
|
2010-11-05 07:17:07 +00:00
|
|
|
bool /*unused*/,
|
2009-12-04 18:45:15 +00:00
|
|
|
bool /*unused*/)
|
|
|
|
{
|
2014-07-25 23:41:25 +00:00
|
|
|
nsRefPtr<SharedMemory> segment;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
if (aType == SharedMemory::TYPE_BASIC)
|
2012-09-17 08:37:20 +00:00
|
|
|
segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)),
|
2010-04-16 05:29:16 +00:00
|
|
|
SharedMemoryBasic::NULLHandle());
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (aType == SharedMemory::TYPE_SYSV)
|
2012-09-17 08:37:20 +00:00
|
|
|
segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)),
|
2010-04-16 05:29:16 +00:00
|
|
|
SharedMemorySysV::NULLHandle());
|
|
|
|
#endif
|
2014-02-25 03:21:48 +00:00
|
|
|
else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
if (!segment)
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2012-09-17 08:37:20 +00:00
|
|
|
*PtrToSize(segment) = static_cast<uint32_t>(aNBytes);
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
return segment.forget();
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
// static
|
2014-07-25 23:41:25 +00:00
|
|
|
already_AddRefed<Shmem::SharedMemory>
|
2009-12-04 18:45:15 +00:00
|
|
|
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
2010-04-16 05:29:16 +00:00
|
|
|
const IPC::Message& aDescriptor,
|
|
|
|
id_t* aId,
|
|
|
|
bool /*unused*/)
|
2009-12-04 18:45:15 +00:00
|
|
|
{
|
2014-02-25 03:21:48 +00:00
|
|
|
if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
SharedMemory::SharedMemoryType type;
|
2014-07-15 23:51:44 +00:00
|
|
|
void* iter = nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
size_t size;
|
|
|
|
if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
nsRefPtr<SharedMemory> segment;
|
2012-09-17 08:37:20 +00:00
|
|
|
size_t segmentSize = SharedMemory::PageAlignedSize(size + sizeof(uint32_t));
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
if (SharedMemory::TYPE_BASIC == type) {
|
|
|
|
SharedMemoryBasic::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2014-02-25 03:21:48 +00:00
|
|
|
if (!SharedMemoryBasic::IsHandleValid(handle)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (SharedMemory::TYPE_SYSV == type) {
|
|
|
|
SharedMemorySysV::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
|
2014-02-25 03:21:48 +00:00
|
|
|
if (!SharedMemorySysV::IsHandleValid(handle)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else {
|
2014-02-25 03:21:48 +00:00
|
|
|
return nullptr;
|
2010-04-16 05:29:16 +00:00
|
|
|
}
|
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
if (!segment)
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2014-02-26 19:10:55 +00:00
|
|
|
// this is the only validity check done in non-DEBUG builds
|
2014-02-25 03:21:48 +00:00
|
|
|
if (size != static_cast<size_t>(*PtrToSize(segment))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2014-07-25 23:41:25 +00:00
|
|
|
return segment.forget();
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
// static
|
2009-12-04 18:45:15 +00:00
|
|
|
void
|
|
|
|
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
DestroySegment(aSegment);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // if defined(DEBUG)
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
int
|
|
|
|
Shmem::GetSysVID() const
|
|
|
|
{
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
AssertInvariants();
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2014-02-25 03:21:48 +00:00
|
|
|
if (mSegment->Type() != SharedMemory::TYPE_SYSV) {
|
|
|
|
NS_ERROR("Can't call GetSysVID() on a non-SysV Shmem!");
|
|
|
|
return -1;
|
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
|
|
|
|
SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment);
|
|
|
|
return seg->GetHandle();
|
|
|
|
#else
|
2014-02-25 03:21:48 +00:00
|
|
|
NS_ERROR("Can't call GetSysVID() with no support for SysV shared memory!");
|
2010-04-16 05:29:16 +00:00
|
|
|
return -1; // not reached
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC::Message*
|
|
|
|
Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
base::ProcessHandle aProcess,
|
2012-09-17 08:37:20 +00:00
|
|
|
int32_t routingId)
|
2009-12-04 18:45:15 +00:00
|
|
|
{
|
2010-04-16 05:29:16 +00:00
|
|
|
AssertInvariants();
|
|
|
|
|
2014-06-11 13:51:12 +00:00
|
|
|
// kInvalidProcessHandle is used to indicate that it's the same process.
|
|
|
|
if (aProcess == kInvalidProcessHandle) {
|
|
|
|
aProcess = base::GetCurrentProcessHandle();
|
|
|
|
}
|
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
if (SharedMemory::TYPE_BASIC == mSegment->Type()) {
|
|
|
|
SharedMemoryBasic* seg = static_cast<SharedMemoryBasic*>(mSegment);
|
|
|
|
SharedMemoryBasic::Handle handle;
|
|
|
|
if (!seg->ShareToProcess(aProcess, &handle))
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
|
2010-04-16 05:29:16 +00:00
|
|
|
return new ShmemCreated(routingId, mId, mSize, handle);
|
|
|
|
}
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (SharedMemory::TYPE_SYSV == mSegment->Type()) {
|
|
|
|
SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment);
|
|
|
|
return new ShmemCreated(routingId, mId, mSize, seg->GetHandle());
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
2010-04-16 05:29:16 +00:00
|
|
|
#endif
|
2009-12-04 18:45:15 +00:00
|
|
|
else {
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(false, "unknown shmem type (here?!)");
|
2014-02-25 03:21:48 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-15 23:51:44 +00:00
|
|
|
return nullptr;
|
2009-12-04 18:45:15 +00:00
|
|
|
}
|
|
|
|
|
2010-04-27 01:11:40 +00:00
|
|
|
IPC::Message*
|
|
|
|
Shmem::UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
base::ProcessHandle aProcess,
|
2012-09-17 08:37:20 +00:00
|
|
|
int32_t routingId)
|
2010-04-27 01:11:40 +00:00
|
|
|
{
|
|
|
|
AssertInvariants();
|
|
|
|
return new ShmemDestroyed(routingId, mId);
|
|
|
|
}
|
|
|
|
|
2009-12-04 18:45:15 +00:00
|
|
|
} // namespace ipc
|
|
|
|
} // namespace mozilla
|