mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 523174: add a higher-level Shmem class that implements exclusive access rights between parent/child actors and does over/underflow checking. (Also adds a stop-gap lower-level SharedMemory class in lieu of bug 523172.) r=joedrew
This commit is contained in:
parent
6e3d83cf38
commit
96d13f9099
@ -57,7 +57,7 @@ SharedDIB::Create(PRUint32 aSize)
|
||||
Close();
|
||||
|
||||
mShMem = new base::SharedMemory();
|
||||
if (!mShMem || !mShMem->Create(std::wstring(L""), false, false, aSize))
|
||||
if (!mShMem || !mShMem->Create("", false, false, aSize))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Map the entire section
|
||||
|
@ -67,7 +67,11 @@ class SharedMemory {
|
||||
// opens the existing shared memory and ignores the size parameter.
|
||||
// If name is the empty string, use a unique name.
|
||||
// Returns true on success, false on failure.
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
bool Create(const std::string& name, bool read_only, bool open_existing,
|
||||
#else
|
||||
bool Create(const std::wstring& name, bool read_only, bool open_existing,
|
||||
#endif
|
||||
size_t size);
|
||||
|
||||
// Deletes resources associated with a shared memory segment based on name.
|
||||
|
@ -70,10 +70,18 @@ SharedMemoryHandle SharedMemory::NULLHandle() {
|
||||
return SharedMemoryHandle();
|
||||
}
|
||||
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
bool SharedMemory::Create(const std::string &cname, bool read_only,
|
||||
#else
|
||||
bool SharedMemory::Create(const std::wstring &name, bool read_only,
|
||||
#endif
|
||||
bool open_existing, size_t size) {
|
||||
read_only_ = read_only;
|
||||
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
std::wstring name = UTF8ToWide(cname);
|
||||
#endif
|
||||
|
||||
int posix_flags = 0;
|
||||
posix_flags |= read_only ? O_RDONLY : O_RDWR;
|
||||
if (!open_existing || mapped_file_ <= 0)
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/win_util.h"
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
# include "base/string_util.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -55,10 +58,18 @@ SharedMemoryHandle SharedMemory::NULLHandle() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
bool SharedMemory::Create(const std::string &cname, bool read_only,
|
||||
#else
|
||||
bool SharedMemory::Create(const std::wstring &name, bool read_only,
|
||||
#endif
|
||||
bool open_existing, size_t size) {
|
||||
DCHECK(mapped_file_ == NULL);
|
||||
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
std::wstring name = UTF8ToWide(cname);
|
||||
#endif
|
||||
|
||||
name_ = name;
|
||||
read_only_ = read_only;
|
||||
mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
|
||||
|
@ -170,7 +170,11 @@ StatsTablePrivate* StatsTablePrivate::New(const std::string& name,
|
||||
int max_threads,
|
||||
int max_counters) {
|
||||
scoped_ptr<StatsTablePrivate> priv(new StatsTablePrivate());
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
if (!priv->shared_memory_.Create(name, false, true,
|
||||
#else
|
||||
if (!priv->shared_memory_.Create(base::SysUTF8ToWide(name), false, true,
|
||||
#endif
|
||||
size))
|
||||
return NULL;
|
||||
if (!priv->shared_memory_.Map(size))
|
||||
|
@ -27,7 +27,11 @@ TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
|
||||
|
||||
TransportDIB* dib = new TransportDIB;
|
||||
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
if (!dib->shared_memory_.Create("", false /* read write */,
|
||||
#else
|
||||
if (!dib->shared_memory_.Create(L"", false /* read write */,
|
||||
#endif
|
||||
true /* open existing */, size)) {
|
||||
delete dib;
|
||||
return NULL;
|
||||
|
@ -57,6 +57,8 @@ EXPORTS_mozilla/ipc = \
|
||||
GeckoThread.h \
|
||||
ProtocolUtils.h \
|
||||
RPCChannel.h \
|
||||
SharedMemory.h \
|
||||
Shmem.h \
|
||||
SyncChannel.h \
|
||||
ScopedXREEmbed.h \
|
||||
$(NULL)
|
||||
@ -70,12 +72,18 @@ CPPSRCS += \
|
||||
MessagePump.cpp \
|
||||
RPCChannel.cpp \
|
||||
ScopedXREEmbed.cpp \
|
||||
Shmem.cpp \
|
||||
StringUtil.cpp \
|
||||
SyncChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
CPPSRCS += WindowsMessageLoop.cpp
|
||||
CPPSRCS += \
|
||||
SharedMemory_windows.cpp \
|
||||
WindowsMessageLoop.cpp \
|
||||
$(NULL)
|
||||
else
|
||||
CPPSRCS += SharedMemory_posix.cpp
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/ipc/app/defs.mk
|
||||
|
125
ipc/glue/SharedMemory.h
Normal file
125
ipc/glue/SharedMemory.h
Normal file
@ -0,0 +1,125 @@
|
||||
/* -*- 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):
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef mozilla_ipc_SharedMemory_h
|
||||
#define mozilla_ipc_SharedMemory_h
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include "nsDebug.h"
|
||||
|
||||
//
|
||||
// This is a low-level wrapper around platform shared memory. Don't
|
||||
// use it directly; use Shmem allocated through IPDL interfaces.
|
||||
//
|
||||
namespace {
|
||||
enum Rights {
|
||||
RightsNone = 0,
|
||||
RightsRead = 1 << 0,
|
||||
RightsWrite = 1 << 1
|
||||
};
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class SharedMemory : public base::SharedMemory
|
||||
{
|
||||
public:
|
||||
typedef base::SharedMemoryHandle SharedMemoryHandle;
|
||||
|
||||
SharedMemory() :
|
||||
base::SharedMemory(),
|
||||
mSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
SharedMemory(const SharedMemoryHandle& aHandle) :
|
||||
base::SharedMemory(aHandle, false),
|
||||
mSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool Map(size_t nBytes)
|
||||
{
|
||||
bool ok = base::SharedMemory::Map(nBytes);
|
||||
if (ok)
|
||||
mSize = nBytes;
|
||||
return ok;
|
||||
}
|
||||
|
||||
size_t Size()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void
|
||||
Protect(char* aAddr, size_t aSize, int aRights)
|
||||
{
|
||||
char* memStart = reinterpret_cast<char*>(memory());
|
||||
if (!memStart)
|
||||
NS_RUNTIMEABORT("SharedMemory region points at NULL!");
|
||||
char* memEnd = memStart + Size();
|
||||
|
||||
char* protStart = aAddr;
|
||||
if (!protStart)
|
||||
NS_RUNTIMEABORT("trying to Protect() a NULL region!");
|
||||
char* protEnd = protStart + aSize;
|
||||
|
||||
if (!(memStart <= protStart
|
||||
&& protEnd <= memEnd))
|
||||
NS_RUNTIMEABORT("attempt to Protect() a region outside this SharedMemory");
|
||||
|
||||
// checks alignment etc.
|
||||
SystemProtect(aAddr, aSize, aRights);
|
||||
}
|
||||
|
||||
static void SystemProtect(char* aAddr, size_t aSize, int aRights);
|
||||
static size_t SystemPageSize();
|
||||
|
||||
private:
|
||||
// NB: we have to track this because shared_memory_win.cc doesn't
|
||||
size_t mSize;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla_ipc_SharedMemory_h
|
70
ipc/glue/SharedMemory_posix.cpp
Normal file
70
ipc/glue/SharedMemory_posix.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/* -*- 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):
|
||||
*
|
||||
* 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 <sys/mman.h> // mprotect
|
||||
#include <unistd.h> // sysconf
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
void
|
||||
SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights)
|
||||
{
|
||||
int flags = 0;
|
||||
if (aRights & RightsRead)
|
||||
flags |= PROT_READ;
|
||||
if (aRights & RightsWrite)
|
||||
flags |= PROT_WRITE;
|
||||
if (RightsNone == aRights)
|
||||
flags = PROT_NONE;
|
||||
|
||||
if (0 < mprotect(aAddr, aSize, flags))
|
||||
NS_RUNTIMEABORT("can't mprotect()");
|
||||
}
|
||||
|
||||
size_t
|
||||
SharedMemory::SystemPageSize()
|
||||
{
|
||||
return sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
72
ipc/glue/SharedMemory_windows.cpp
Normal file
72
ipc/glue/SharedMemory_windows.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/* -*- 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):
|
||||
*
|
||||
* 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 <windows.h>
|
||||
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
void
|
||||
SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights)
|
||||
{
|
||||
DWORD flags;
|
||||
if ((aRights & RightsRead) && (aRights & RightsWrite))
|
||||
flags = PAGE_READWRITE;
|
||||
else if (aRights & RightsRead)
|
||||
flags = PAGE_READONLY;
|
||||
else
|
||||
flags = PAGE_NOACCESS;
|
||||
|
||||
DWORD oldflags;
|
||||
if (!VirtualProtect(aAddr, aSize, flags, &oldflags))
|
||||
NS_RUNTIMEABORT("can't VirtualProtect()");
|
||||
}
|
||||
|
||||
size_t
|
||||
SharedMemory::SystemPageSize()
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
359
ipc/glue/Shmem.cpp
Normal file
359
ipc/glue/Shmem.cpp
Normal file
@ -0,0 +1,359 @@
|
||||
/* -*- 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 <math.h>
|
||||
|
||||
#include "Shmem.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
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";
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
namespace {
|
||||
|
||||
struct Header
|
||||
{
|
||||
size_t mSize;
|
||||
char mMagic[sizeof(sMagic)];
|
||||
};
|
||||
|
||||
void
|
||||
GetSections(Shmem::SharedMemory* aSegment,
|
||||
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()");
|
||||
|
||||
size_t pageSize = Shmem::SharedMemory::SystemPageSize();
|
||||
*aData = *aFrontSentinel + pageSize;
|
||||
|
||||
*aBackSentinel = *aFrontSentinel + aSegment->Size() - pageSize;
|
||||
}
|
||||
|
||||
} // namespace <anon>
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
char* frontSentinel;
|
||||
char* data;
|
||||
char* backSentinel;
|
||||
GetSections(aSegment, &frontSentinel, &data, &backSentinel);
|
||||
|
||||
// do a quick validity check to avoid weird-looking crashes in libc
|
||||
char check = *frontSentinel;
|
||||
(void)check;
|
||||
|
||||
Header* header = reinterpret_cast<Header*>(frontSentinel);
|
||||
NS_ABORT_IF_FALSE(!strncmp(header->mMagic, sMagic, sizeof(sMagic)),
|
||||
"invalid segment");
|
||||
mSize = header->mSize;
|
||||
|
||||
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);
|
||||
checkMappingFront = checkMappingBack; // avoid "unused" warnings
|
||||
}
|
||||
|
||||
void
|
||||
Shmem::Protect(SharedMemory* aSegment)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aSegment, "NULL segment");
|
||||
aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
|
||||
aSegment->Size(),
|
||||
RightsNone);
|
||||
}
|
||||
|
||||
void
|
||||
Shmem::Unprotect(SharedMemory* aSegment)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aSegment, "NULL segment");
|
||||
aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()),
|
||||
aSegment->Size(),
|
||||
RightsRead | RightsWrite);
|
||||
}
|
||||
|
||||
Shmem::SharedMemory*
|
||||
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
size_t aNBytes,
|
||||
bool aProtect)
|
||||
{
|
||||
size_t pageSize = SharedMemory::SystemPageSize();
|
||||
// |2*pageSize| is for the front and back sentinel
|
||||
SharedMemory* segment = CreateSegment(PageAlignedSize(aNBytes + 2*pageSize));
|
||||
if (!segment)
|
||||
return 0;
|
||||
|
||||
char *frontSentinel;
|
||||
char *data;
|
||||
char *backSentinel;
|
||||
GetSections(segment, &frontSentinel, &data, &backSentinel);
|
||||
|
||||
// initialize the segment with Shmem-internal information
|
||||
Header* header = reinterpret_cast<Header*>(frontSentinel);
|
||||
memcpy(header->mMagic, sMagic, sizeof(sMagic));
|
||||
header->mSize = aNBytes;
|
||||
|
||||
if (aProtect)
|
||||
Protect(segment);
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
Shmem::SharedMemory*
|
||||
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemoryHandle aHandle,
|
||||
size_t aNBytes,
|
||||
bool aProtect)
|
||||
{
|
||||
if (!SharedMemory::IsHandleValid(aHandle))
|
||||
NS_RUNTIMEABORT("trying to open invalid handle");
|
||||
|
||||
size_t pageSize = SharedMemory::SystemPageSize();
|
||||
// |2*pageSize| is for the front and back sentinels
|
||||
SharedMemory* segment = CreateSegment(PageAlignedSize(aNBytes + 2*pageSize),
|
||||
aHandle);
|
||||
if (!segment)
|
||||
return 0;
|
||||
|
||||
if (aProtect)
|
||||
Protect(segment);
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
void
|
||||
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemory* aSegment)
|
||||
{
|
||||
if (!aSegment)
|
||||
return;
|
||||
|
||||
size_t pageSize = SharedMemory::SystemPageSize();
|
||||
char *frontSentinel;
|
||||
char *data;
|
||||
char *backSentinel;
|
||||
GetSections(aSegment, &frontSentinel, &data, &backSentinel);
|
||||
|
||||
aSegment->Protect(frontSentinel, pageSize, RightsWrite | RightsRead);
|
||||
Header* header = reinterpret_cast<Header*>(frontSentinel);
|
||||
memset(header->mMagic, 0, sizeof(sMagic));
|
||||
header->mSize = 0;
|
||||
|
||||
DestroySegment(aSegment);
|
||||
}
|
||||
|
||||
|
||||
#else // !defined(DEBUG)
|
||||
|
||||
Shmem::SharedMemory*
|
||||
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
size_t aNBytes,
|
||||
bool /*unused*/)
|
||||
{
|
||||
SharedMemory* segment =
|
||||
CreateSegment(PageAlignedSize(aNBytes + sizeof(size_t)));
|
||||
if (!segment)
|
||||
return 0;
|
||||
|
||||
*PtrToSize(segment) = aNBytes;
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
Shmem::SharedMemory*
|
||||
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemoryHandle aHandle,
|
||||
size_t aNBytes,
|
||||
bool /* unused */)
|
||||
{
|
||||
SharedMemory* segment =
|
||||
CreateSegment(PageAlignedSize(aNBytes + sizeof(size_t)), aHandle);
|
||||
if (!segment)
|
||||
return 0;
|
||||
|
||||
// this is the only validity check done OPT builds
|
||||
if (aNBytes != *PtrToSize(segment))
|
||||
NS_RUNTIMEABORT("Alloc() segment size disagrees with OpenExisting()'s");
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
void
|
||||
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemory* aSegment)
|
||||
{
|
||||
DestroySegment(aSegment);
|
||||
}
|
||||
|
||||
|
||||
#endif // if defined(DEBUG)
|
||||
|
||||
|
||||
Shmem::SharedMemory*
|
||||
Shmem::CreateSegment(size_t aNBytes, SharedMemoryHandle aHandle)
|
||||
{
|
||||
nsAutoPtr<SharedMemory> segment;
|
||||
|
||||
if (SharedMemory::IsHandleValid(aHandle)) {
|
||||
segment = new SharedMemory(aHandle);
|
||||
}
|
||||
else {
|
||||
segment = new SharedMemory();
|
||||
if (!segment->Create("", false, false, aNBytes))
|
||||
return 0;
|
||||
}
|
||||
if (!segment->Map(aNBytes))
|
||||
return 0;
|
||||
return segment.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Shmem::DestroySegment(SharedMemory* aSegment)
|
||||
{
|
||||
// the SharedMemory dtor closes and unmaps the actual OS shmem segment
|
||||
delete aSegment;
|
||||
}
|
||||
|
||||
size_t
|
||||
Shmem::PageAlignedSize(size_t aSize)
|
||||
{
|
||||
size_t pageSize = SharedMemory::SystemPageSize();
|
||||
size_t nPagesNeeded = int(ceil(double(aSize) / double(pageSize)));
|
||||
return pageSize * nPagesNeeded;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
299
ipc/glue/Shmem.h
Normal file
299
ipc/glue/Shmem.h
Normal file
@ -0,0 +1,299 @@
|
||||
/* -*- 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 ***** */
|
||||
|
||||
#ifndef mozilla_ipc_Shmem_h
|
||||
#define mozilla_ipc_Shmem_h
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include "IPC/IPCMessageUtils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
/**
|
||||
* |Shmem| is one agent in the IPDL shared memory scheme. The way it
|
||||
works is essentially
|
||||
*
|
||||
* (1) C++ code calls, say, |parentActor->AllocShmem(size)|
|
||||
|
||||
* (2) IPDL-generated code creates a |mozilla::ipc::SharedMemory|
|
||||
* wrapping the bare OS shmem primitives. The code then adds the new
|
||||
* SharedMemory to the set of shmem segments being managed by IPDL.
|
||||
*
|
||||
* (3) IPDL-generated code "shares" the new SharedMemory to the child
|
||||
* process, and then sends a special asynchronous IPC message to the
|
||||
* child notifying it of the creation of the segment. (What this
|
||||
* means is OS specific.)
|
||||
*
|
||||
* (4a) The child receives the special IPC message, and using the
|
||||
* |mozilla::ipc::SharedMemoryHandle| (which is an fd or HANDLE) it
|
||||
* was passed, creates a |mozilla::ipc::SharedMemory| in the child
|
||||
* process.
|
||||
*
|
||||
* (4b) After sending the "shmem-created" IPC message, IPDL-generated
|
||||
* code in the parent returns a |mozilla::ipc::Shmem| back to the C++
|
||||
* caller of |parentActor->AllocShmem()|. The |Shmem| is a "weak
|
||||
* reference" to the underlying |SharedMemory|, which is managed by
|
||||
* IPDL-generated code. C++ consumers of |Shmem| can't get at the
|
||||
* underlying |SharedMemory|.
|
||||
*
|
||||
* If parent code wants to give access rights to the Shmem to the
|
||||
* child, it does so by sending its |Shmem| to the child, in an IPDL
|
||||
* message. The parent's |Shmem| then "dies", i.e. becomes
|
||||
* inaccessible. This process could be compared to passing a
|
||||
* "shmem-access baton" between parent and child.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
|
||||
class NS_FINAL_CLASS Shmem
|
||||
{
|
||||
friend class IPC::ParamTraits<mozilla::ipc::Shmem>;
|
||||
|
||||
public:
|
||||
typedef int32 id_t;
|
||||
// Low-level wrapper around platform shmem primitives.
|
||||
typedef mozilla::ipc::SharedMemory SharedMemory;
|
||||
typedef SharedMemory::SharedMemoryHandle SharedMemoryHandle;
|
||||
struct IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead {};
|
||||
|
||||
Shmem() :
|
||||
mSegment(0),
|
||||
mData(0),
|
||||
mSize(0),
|
||||
mId(0)
|
||||
{
|
||||
}
|
||||
|
||||
Shmem(const Shmem& aOther) :
|
||||
mSegment(aOther.mSegment),
|
||||
mData(aOther.mData),
|
||||
mSize(aOther.mSize),
|
||||
mId(aOther.mId)
|
||||
{
|
||||
}
|
||||
|
||||
#if !defined(DEBUG)
|
||||
Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemory* aSegment, id_t aId) :
|
||||
mSegment(aSegment),
|
||||
mData(aSegment->memory()),
|
||||
mSize(0),
|
||||
mId(aId)
|
||||
{
|
||||
mSize = *PtrToSize(mSegment);
|
||||
}
|
||||
#else
|
||||
Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemory* aSegment, id_t aId);
|
||||
#endif
|
||||
|
||||
~Shmem()
|
||||
{
|
||||
// Shmem only holds a "weak ref" to the actual segment, which is
|
||||
// owned by IPDL. So there's nothing interesting to be done here
|
||||
forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
}
|
||||
|
||||
Shmem& operator=(const Shmem& aRhs)
|
||||
{
|
||||
mSegment = aRhs.mSegment;
|
||||
mData = aRhs.mData;
|
||||
mSize = aRhs.mSize;
|
||||
mId = aRhs.mId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Return a pointer to the user-visible data segment.
|
||||
template<typename T>
|
||||
T*
|
||||
get() const
|
||||
{
|
||||
AssertInvariants();
|
||||
AssertAligned<T>();
|
||||
|
||||
return reinterpret_cast<T*>(mData);
|
||||
}
|
||||
|
||||
// Return the size of the segment as requested when this shmem
|
||||
// segment was allocated, in units of T. The underlying mapping may
|
||||
// actually be larger because of page alignment and private data,
|
||||
// but this isn't exposed to clients.
|
||||
template<typename T>
|
||||
size_t
|
||||
Size() const
|
||||
{
|
||||
AssertInvariants();
|
||||
AssertAligned<T>();
|
||||
|
||||
return mSize / sizeof(T);
|
||||
}
|
||||
|
||||
// These shouldn't be used directly, use the IPDL interface instead.
|
||||
id_t Id(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) {
|
||||
return mId;
|
||||
}
|
||||
|
||||
void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
||||
{
|
||||
Protect(mSegment);
|
||||
}
|
||||
|
||||
void forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
||||
{
|
||||
mSegment = 0;
|
||||
mData = 0;
|
||||
mSize = 0;
|
||||
mId = 0;
|
||||
}
|
||||
|
||||
static SharedMemory*
|
||||
Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
size_t aNBytes,
|
||||
bool aProtect=false);
|
||||
|
||||
// Return a SharedMemory instance in this process using the
|
||||
// SharedMemoryHandle (fd/HANDLE) shared to us by the process that
|
||||
// created the underlying OS shmem resource
|
||||
static SharedMemory*
|
||||
OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemoryHandle aHandle,
|
||||
size_t aNBytes,
|
||||
bool aProtect=false);
|
||||
|
||||
static void
|
||||
Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
SharedMemory* aSegment);
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void AssertAligned() const
|
||||
{
|
||||
if (0 != (mSize % sizeof(T)))
|
||||
NS_RUNTIMEABORT("shmem is not T-aligned");
|
||||
}
|
||||
|
||||
#if !defined(DEBUG)
|
||||
void AssertInvariants() const
|
||||
{ }
|
||||
static void Unprotect(SharedMemory* aSegment)
|
||||
{ }
|
||||
static void Protect(SharedMemory* aSegment)
|
||||
{ }
|
||||
|
||||
static size_t*
|
||||
PtrToSize(SharedMemory* aSegment)
|
||||
{
|
||||
char* endOfSegment =
|
||||
reinterpret_cast<char*>(aSegment->memory()) + aSegment->Size();
|
||||
return reinterpret_cast<size_t*>(endOfSegment - sizeof(size_t));
|
||||
}
|
||||
|
||||
#else
|
||||
void AssertInvariants() const;
|
||||
|
||||
static void Unprotect(SharedMemory* aSegment);
|
||||
static void Protect(SharedMemory* aSegment);
|
||||
#endif
|
||||
|
||||
static SharedMemory*
|
||||
CreateSegment(size_t aNBytes,
|
||||
SharedMemoryHandle aHandle=SharedMemory::NULLHandle());
|
||||
|
||||
static void
|
||||
DestroySegment(SharedMemory* aSegment);
|
||||
|
||||
static size_t
|
||||
PageAlignedSize(size_t aSize);
|
||||
|
||||
SharedMemory* mSegment;
|
||||
void* mData;
|
||||
size_t mSize;
|
||||
id_t mId;
|
||||
|
||||
// disable these
|
||||
static void* operator new(size_t) CPP_THROW_NEW;
|
||||
static void operator delete(void*);
|
||||
};
|
||||
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::ipc::Shmem>
|
||||
{
|
||||
typedef mozilla::ipc::Shmem paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mId);
|
||||
}
|
||||
|
||||
// NB: Read()/Write() look creepy, but IPDL internally uses mId to
|
||||
// properly initialize a "real" Shmem
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
paramType::id_t id;
|
||||
if (!ReadParam(aMsg, aIter, &id))
|
||||
return false;
|
||||
aResult->mId = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(L"(shmem segment)");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
|
||||
#endif // ifndef mozilla_ipc_Shmem_h
|
Loading…
Reference in New Issue
Block a user