2009-12-04 21:45:15 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* vim: sw=2 ts=8 et :
|
|
|
|
*/
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla IPC.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* The Mozilla Foundation
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Chris Jones <jones.chris.g@gmail.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "Shmem.h"
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
#include "ProtocolUtils.h"
|
|
|
|
#include "SharedMemoryBasic.h"
|
|
|
|
#include "SharedMemorySysV.h"
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
#include "nsAutoPtr.h"
|
2011-06-25 01:01:30 +04:00
|
|
|
#include "mozilla/unused.h"
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace ipc {
|
|
|
|
|
|
|
|
class ShmemCreated : public IPC::Message
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
typedef Shmem::id_t id_t;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ShmemCreated(int32 routingId,
|
|
|
|
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);
|
|
|
|
IPC::WriteParam(this, int32(SharedMemory::TYPE_BASIC)),
|
|
|
|
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) ||
|
|
|
|
!IPC::ReadParam(msg, iter, reinterpret_cast<int32*>(aType)))
|
|
|
|
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
|
|
|
|
ShmemCreated(int32 routingId,
|
|
|
|
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);
|
|
|
|
IPC::WriteParam(this, int32(SharedMemory::TYPE_SYSV)),
|
|
|
|
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 05:11:40 +04:00
|
|
|
class ShmemDestroyed : public IPC::Message
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
typedef Shmem::id_t id_t;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ShmemDestroyed(int32 routingId,
|
|
|
|
const id_t& aIPDLId) :
|
|
|
|
IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE, PRIORITY_NORMAL)
|
|
|
|
{
|
|
|
|
IPC::WriteParam(this, aIPDLId);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
static Shmem::SharedMemory*
|
|
|
|
CreateSegment(size_t aNBytes, SharedMemorySysV::Handle aHandle)
|
|
|
|
{
|
|
|
|
nsAutoPtr<SharedMemory> segment;
|
|
|
|
|
|
|
|
if (SharedMemorySysV::IsHandleValid(aHandle)) {
|
|
|
|
segment = new SharedMemorySysV(aHandle);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
segment = new SharedMemorySysV();
|
|
|
|
|
|
|
|
if (!segment->Create(aNBytes))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!segment->Map(aNBytes))
|
|
|
|
return 0;
|
2010-05-22 23:35:32 +04:00
|
|
|
|
|
|
|
segment->AddRef();
|
2010-04-16 09:29:16 +04:00
|
|
|
return segment.forget();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static Shmem::SharedMemory*
|
|
|
|
CreateSegment(size_t aNBytes, SharedMemoryBasic::Handle aHandle)
|
|
|
|
{
|
|
|
|
nsAutoPtr<SharedMemory> segment;
|
|
|
|
|
|
|
|
if (SharedMemoryBasic::IsHandleValid(aHandle)) {
|
|
|
|
segment = new SharedMemoryBasic(aHandle);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
segment = new SharedMemoryBasic();
|
|
|
|
|
|
|
|
if (!segment->Create(aNBytes))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!segment->Map(aNBytes))
|
|
|
|
return 0;
|
2010-05-22 23:35:32 +04:00
|
|
|
|
|
|
|
segment->AddRef();
|
2010-04-16 09:29:16 +04:00
|
|
|
return segment.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DestroySegment(SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
// the SharedMemory dtor closes and unmaps the actual OS shmem segment
|
2010-05-22 23:35:32 +04:00
|
|
|
if (aSegment)
|
|
|
|
aSegment->Release();
|
2010-04-16 09:29:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
#if defined(DEBUG)
|
2010-04-16 09:29:16 +04:00
|
|
|
|
2009-12-04 21:45:15 +03: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 09:29:16 +04:00
|
|
|
struct Header {
|
2010-11-05 10:17:07 +03:00
|
|
|
// Don't use size_t or bool here because their size depends on the
|
|
|
|
// architecture.
|
2010-08-31 21:51:51 +04:00
|
|
|
uint32 mSize;
|
2010-11-05 10:17:07 +03:00
|
|
|
uint32 mUnsafe;
|
2009-12-04 21:45:15 +03:00
|
|
|
char mMagic[sizeof(sMagic)];
|
|
|
|
};
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
static void
|
2009-12-04 21:45:15 +03:00
|
|
|
GetSections(Shmem::SharedMemory* aSegment,
|
2010-11-05 10:17:07 +03:00
|
|
|
Header** aHeader,
|
2009-12-04 21:45:15 +03:00
|
|
|
char** aFrontSentinel,
|
|
|
|
char** aData,
|
|
|
|
char** aBackSentinel)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aSegment && aFrontSentinel && aData && aBackSentinel,
|
|
|
|
"NULL param(s)");
|
|
|
|
|
|
|
|
*aFrontSentinel = reinterpret_cast<char*>(aSegment->memory());
|
|
|
|
NS_ABORT_IF_FALSE(*aFrontSentinel, "NULL memory()");
|
|
|
|
|
2010-11-05 10:17:07 +03:00
|
|
|
*aHeader = reinterpret_cast<Header*>(*aFrontSentinel);
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
size_t pageSize = Shmem::SharedMemory::SystemPageSize();
|
|
|
|
*aData = *aFrontSentinel + pageSize;
|
|
|
|
|
|
|
|
*aBackSentinel = *aFrontSentinel + aSegment->Size() - pageSize;
|
|
|
|
}
|
|
|
|
|
2010-11-05 10:17:07 +03:00
|
|
|
static Header*
|
|
|
|
GetHeader(Shmem::SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
Header* header;
|
|
|
|
char* dontcare;
|
|
|
|
GetSections(aSegment, &header, &dontcare, &dontcare, &dontcare);
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
static void
|
|
|
|
Protect(SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aSegment, "NULL segment");
|
|
|
|
aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
|
|
|
|
aSegment->Size(),
|
|
|
|
RightsNone);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Unprotect(SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aSegment, "NULL segment");
|
|
|
|
aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
|
|
|
|
aSegment->Size(),
|
|
|
|
RightsRead | RightsWrite);
|
|
|
|
}
|
2009-12-04 21:45:15 +03: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),
|
|
|
|
mData(0),
|
|
|
|
mSize(0)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mSegment, "NULL segment");
|
|
|
|
NS_ABORT_IF_FALSE(aId != 0, "invalid ID");
|
|
|
|
|
|
|
|
Unprotect(mSegment);
|
|
|
|
|
2010-11-05 10:17:07 +03:00
|
|
|
Header* header;
|
2009-12-04 21:45:15 +03:00
|
|
|
char* frontSentinel;
|
|
|
|
char* data;
|
|
|
|
char* backSentinel;
|
2010-11-05 10:17:07 +03:00
|
|
|
GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel);
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
// do a quick validity check to avoid weird-looking crashes in libc
|
|
|
|
char check = *frontSentinel;
|
|
|
|
(void)check;
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(!strncmp(header->mMagic, sMagic, sizeof(sMagic)),
|
|
|
|
"invalid segment");
|
2010-08-31 21:51:51 +04:00
|
|
|
mSize = static_cast<size_t>(header->mSize);
|
2009-12-04 21:45:15 +03: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
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mSegment, "NULL segment");
|
|
|
|
NS_ABORT_IF_FALSE(mData, "NULL data pointer");
|
|
|
|
NS_ABORT_IF_FALSE(mSize > 0, "invalid size");
|
|
|
|
// 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-25 01:01:30 +04:00
|
|
|
|
|
|
|
// avoid "unused" warnings for these variables:
|
|
|
|
unused << checkMappingFront;
|
|
|
|
unused << checkMappingBack;
|
2009-12-04 21:45:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-04-16 09:29:16 +04:00
|
|
|
Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
2009-12-04 21:45:15 +03:00
|
|
|
{
|
2010-04-16 09:29:16 +04:00
|
|
|
AssertInvariants();
|
2010-11-05 10:17:07 +03: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 21:45:15 +03:00
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
// static
|
2009-12-04 21:45:15 +03:00
|
|
|
Shmem::SharedMemory*
|
|
|
|
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
size_t aNBytes,
|
2010-04-16 09:29:16 +04:00
|
|
|
SharedMemoryType aType,
|
2010-11-05 10:17:07 +03:00
|
|
|
bool aUnsafe,
|
2009-12-04 21:45:15 +03:00
|
|
|
bool aProtect)
|
|
|
|
{
|
2010-09-24 10:31:47 +04:00
|
|
|
NS_ASSERTION(aNBytes <= PR_UINT32_MAX, "Will truncate shmem segment size!");
|
2010-11-05 10:17:07 +03:00
|
|
|
NS_ABORT_IF_FALSE(!aProtect || !aUnsafe, "protect => !unsafe");
|
2010-09-24 10:31:47 +04:00
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
2010-04-16 09:29:16 +04:00
|
|
|
SharedMemory* segment = nsnull;
|
2009-12-04 21:45:15 +03:00
|
|
|
// |2*pageSize| is for the front and back sentinel
|
2010-11-05 10:17:07 +03:00
|
|
|
size_t segmentSize = SharedMemory::PageAlignedSize(aNBytes + 2*pageSize);
|
2010-04-16 09:29:16 +04: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
|
|
|
|
else
|
|
|
|
NS_RUNTIMEABORT("unknown shmem type");
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
if (!segment)
|
|
|
|
return 0;
|
|
|
|
|
2010-11-05 10:17:07 +03:00
|
|
|
Header* header;
|
2009-12-04 21:45:15 +03:00
|
|
|
char *frontSentinel;
|
|
|
|
char *data;
|
|
|
|
char *backSentinel;
|
2010-11-05 10:17:07 +03:00
|
|
|
GetSections(segment, &header, &frontSentinel, &data, &backSentinel);
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
// initialize the segment with Shmem-internal information
|
2010-11-05 10:17:07 +03: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
|
|
|
|
NS_ABORT_IF_FALSE(sizeof(Header) <= pageSize,
|
|
|
|
"Shmem::Header has gotten too big");
|
2009-12-04 21:45:15 +03:00
|
|
|
memcpy(header->mMagic, sMagic, sizeof(sMagic));
|
2010-08-31 21:51:51 +04:00
|
|
|
header->mSize = static_cast<uint32>(aNBytes);
|
2010-11-05 10:17:07 +03:00
|
|
|
header->mUnsafe = aUnsafe;
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
if (aProtect)
|
|
|
|
Protect(segment);
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
// static
|
2009-12-04 21:45:15 +03:00
|
|
|
Shmem::SharedMemory*
|
|
|
|
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
2010-04-16 09:29:16 +04:00
|
|
|
const IPC::Message& aDescriptor,
|
|
|
|
id_t* aId,
|
2009-12-04 21:45:15 +03:00
|
|
|
bool aProtect)
|
|
|
|
{
|
2010-04-16 09:29:16 +04:00
|
|
|
if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type())
|
|
|
|
NS_RUNTIMEABORT("expected 'shmem created' message");
|
2009-12-04 21:45:15 +03:00
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
void* iter = 0;
|
|
|
|
SharedMemory::SharedMemoryType type;
|
|
|
|
size_t size;
|
|
|
|
if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
SharedMemory* segment = 0;
|
2009-12-04 21:45:15 +03:00
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
|
|
|
// |2*pageSize| is for the front and back sentinels
|
2010-11-05 10:17:07 +03:00
|
|
|
size_t segmentSize = SharedMemory::PageAlignedSize(size + 2*pageSize);
|
2010-04-16 09:29:16 +04:00
|
|
|
|
|
|
|
if (SharedMemory::TYPE_BASIC == type) {
|
|
|
|
SharedMemoryBasic::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!SharedMemoryBasic::IsHandleValid(handle))
|
|
|
|
NS_RUNTIMEABORT("trying to open invalid handle");
|
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (SharedMemory::TYPE_SYSV == type) {
|
|
|
|
SharedMemorySysV::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!SharedMemorySysV::IsHandleValid(handle))
|
|
|
|
NS_RUNTIMEABORT("trying to open invalid handle");
|
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else {
|
|
|
|
NS_RUNTIMEABORT("unknown shmem type");
|
|
|
|
}
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
if (!segment)
|
|
|
|
return 0;
|
|
|
|
|
2010-11-05 10:17:07 +03:00
|
|
|
// The caller of this function may not know whether the segment is
|
|
|
|
// unsafe or not
|
|
|
|
Header* header = GetHeader(segment);
|
|
|
|
if (!header->mUnsafe && aProtect)
|
2009-12-04 21:45:15 +03:00
|
|
|
Protect(segment);
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
// static
|
2009-12-04 21:45:15 +03:00
|
|
|
void
|
|
|
|
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
if (!aSegment)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t pageSize = SharedMemory::SystemPageSize();
|
2010-11-05 10:17:07 +03:00
|
|
|
Header* header;
|
2009-12-04 21:45:15 +03:00
|
|
|
char *frontSentinel;
|
|
|
|
char *data;
|
|
|
|
char *backSentinel;
|
2010-11-05 10:17:07 +03:00
|
|
|
GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel);
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
aSegment->Protect(frontSentinel, pageSize, RightsWrite | RightsRead);
|
|
|
|
memset(header->mMagic, 0, sizeof(sMagic));
|
|
|
|
header->mSize = 0;
|
2010-11-05 10:17:07 +03:00
|
|
|
header->mUnsafe = false; // make it "safe" so as to catch errors
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
DestroySegment(aSegment);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#else // !defined(DEBUG)
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
// static
|
2009-12-04 21:45:15 +03:00
|
|
|
Shmem::SharedMemory*
|
|
|
|
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
size_t aNBytes,
|
2010-04-16 09:29:16 +04:00
|
|
|
SharedMemoryType aType,
|
2010-11-05 10:17:07 +03:00
|
|
|
bool /*unused*/,
|
2009-12-04 21:45:15 +03:00
|
|
|
bool /*unused*/)
|
|
|
|
{
|
2010-04-16 09:29:16 +04:00
|
|
|
SharedMemory *segment = nsnull;
|
|
|
|
|
|
|
|
if (aType == SharedMemory::TYPE_BASIC)
|
2010-11-05 10:17:07 +03:00
|
|
|
segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32)),
|
2010-04-16 09:29:16 +04:00
|
|
|
SharedMemoryBasic::NULLHandle());
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (aType == SharedMemory::TYPE_SYSV)
|
2010-11-05 10:17:07 +03:00
|
|
|
segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32)),
|
2010-04-16 09:29:16 +04:00
|
|
|
SharedMemorySysV::NULLHandle());
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
// Unhandled!!
|
|
|
|
NS_ABORT();
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
if (!segment)
|
|
|
|
return 0;
|
|
|
|
|
2010-09-24 10:31:47 +04:00
|
|
|
*PtrToSize(segment) = static_cast<uint32>(aNBytes);
|
2009-12-04 21:45:15 +03:00
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
// static
|
2009-12-04 21:45:15 +03:00
|
|
|
Shmem::SharedMemory*
|
|
|
|
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
2010-04-16 09:29:16 +04:00
|
|
|
const IPC::Message& aDescriptor,
|
|
|
|
id_t* aId,
|
|
|
|
bool /*unused*/)
|
2009-12-04 21:45:15 +03:00
|
|
|
{
|
2010-04-16 09:29:16 +04:00
|
|
|
if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type())
|
|
|
|
NS_RUNTIMEABORT("expected 'shmem created' message");
|
|
|
|
|
|
|
|
SharedMemory::SharedMemoryType type;
|
|
|
|
void* iter = 0;
|
|
|
|
size_t size;
|
|
|
|
if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
SharedMemory* segment = 0;
|
2011-08-26 04:59:57 +04:00
|
|
|
size_t segmentSize = SharedMemory::PageAlignedSize(size + sizeof(uint32));
|
2010-04-16 09:29:16 +04:00
|
|
|
|
|
|
|
if (SharedMemory::TYPE_BASIC == type) {
|
|
|
|
SharedMemoryBasic::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!SharedMemoryBasic::IsHandleValid(handle))
|
|
|
|
NS_RUNTIMEABORT("trying to open invalid handle");
|
|
|
|
|
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
else if (SharedMemory::TYPE_SYSV == type) {
|
|
|
|
SharedMemorySysV::Handle handle;
|
|
|
|
if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!SharedMemorySysV::IsHandleValid(handle))
|
|
|
|
NS_RUNTIMEABORT("trying to open invalid handle");
|
|
|
|
segment = CreateSegment(segmentSize, handle);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else {
|
|
|
|
NS_RUNTIMEABORT("unknown shmem type");
|
|
|
|
}
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
if (!segment)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// this is the only validity check done OPT builds
|
2010-09-24 10:31:47 +04:00
|
|
|
if (size != static_cast<size_t>(*PtrToSize(segment)))
|
2009-12-04 21:45:15 +03:00
|
|
|
NS_RUNTIMEABORT("Alloc() segment size disagrees with OpenExisting()'s");
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
// static
|
2009-12-04 21:45:15 +03:00
|
|
|
void
|
|
|
|
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
SharedMemory* aSegment)
|
|
|
|
{
|
|
|
|
DestroySegment(aSegment);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // if defined(DEBUG)
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
int
|
|
|
|
Shmem::GetSysVID() const
|
|
|
|
{
|
|
|
|
#ifdef MOZ_HAVE_SHAREDMEMORYSYSV
|
|
|
|
AssertInvariants();
|
2009-12-04 21:45:15 +03:00
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
if (mSegment->Type() != SharedMemory::TYPE_SYSV)
|
|
|
|
NS_RUNTIMEABORT("Can't call GetSysVID() on a non-SysV Shmem!");
|
|
|
|
|
|
|
|
SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment);
|
|
|
|
return seg->GetHandle();
|
|
|
|
#else
|
|
|
|
NS_RUNTIMEABORT("Can't call GetSysVID() with no support for SysV shared memory!");
|
|
|
|
return -1; // not reached
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC::Message*
|
|
|
|
Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
base::ProcessHandle aProcess,
|
|
|
|
int32 routingId)
|
2009-12-04 21:45:15 +03:00
|
|
|
{
|
2010-04-16 09:29:16 +04:00
|
|
|
AssertInvariants();
|
|
|
|
|
|
|
|
if (SharedMemory::TYPE_BASIC == mSegment->Type()) {
|
|
|
|
SharedMemoryBasic* seg = static_cast<SharedMemoryBasic*>(mSegment);
|
|
|
|
SharedMemoryBasic::Handle handle;
|
|
|
|
if (!seg->ShareToProcess(aProcess, &handle))
|
|
|
|
return 0;
|
2009-12-04 21:45:15 +03:00
|
|
|
|
2010-04-16 09:29:16 +04: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 21:45:15 +03:00
|
|
|
}
|
2010-04-16 09:29:16 +04:00
|
|
|
#endif
|
2009-12-04 21:45:15 +03:00
|
|
|
else {
|
2010-04-16 09:29:16 +04:00
|
|
|
NS_RUNTIMEABORT("unknown shmem type (here?!)");
|
2009-12-04 21:45:15 +03:00
|
|
|
}
|
|
|
|
|
2010-04-16 09:29:16 +04:00
|
|
|
return 0;
|
2009-12-04 21:45:15 +03:00
|
|
|
}
|
|
|
|
|
2010-04-27 05:11:40 +04:00
|
|
|
IPC::Message*
|
|
|
|
Shmem::UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|
|
|
base::ProcessHandle aProcess,
|
|
|
|
int32 routingId)
|
|
|
|
{
|
|
|
|
AssertInvariants();
|
|
|
|
return new ShmemDestroyed(routingId, mId);
|
|
|
|
}
|
|
|
|
|
2009-12-04 21:45:15 +03:00
|
|
|
} // namespace ipc
|
|
|
|
} // namespace mozilla
|