Backed out 4 changesets (bug 1454816) for causing build bustages. CLOSED TREE
Backed out changeset 3e8d2c47138c (bug 1454816) Backed out changeset 80ff20241831 (bug 1454816) Backed out changeset 28c2d6d2a683 (bug 1454816) Backed out changeset 236943ab4142 (bug 1454816)
This commit is contained in:
@@ -2388,7 +2388,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRegisterStringBundles(
|
|||||||
|
|
||||||
for (auto& descriptor : aDescriptors) {
|
for (auto& descriptor : aDescriptors) {
|
||||||
stringBundleService->RegisterContentBundle(
|
stringBundleService->RegisterContentBundle(
|
||||||
descriptor.bundleURL(), descriptor.mapHandle(), descriptor.mapSize());
|
descriptor.bundleURL(), descriptor.mapFile(), descriptor.mapSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
@@ -2401,7 +2401,7 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateL10nFileSources(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
|
mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
|
||||||
SharedMemoryHandle&& aMapHandle, const uint32_t& aMapSize,
|
const FileDescriptor& aMapFile, const uint32_t& aMapSize,
|
||||||
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
|
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
|
||||||
nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
|
nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
|
||||||
for (auto& ipcBlob : aBlobs) {
|
for (auto& ipcBlob : aBlobs) {
|
||||||
@@ -2409,12 +2409,12 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mSharedData) {
|
if (mSharedData) {
|
||||||
mSharedData->Update(std::move(aMapHandle), aMapSize, std::move(blobImpls),
|
mSharedData->Update(aMapFile, aMapSize, std::move(blobImpls),
|
||||||
std::move(aChangedKeys));
|
std::move(aChangedKeys));
|
||||||
} else {
|
} else {
|
||||||
mSharedData =
|
mSharedData =
|
||||||
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
|
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
|
||||||
std::move(aMapHandle), aMapSize, std::move(blobImpls));
|
aMapFile, aMapSize, std::move(blobImpls));
|
||||||
}
|
}
|
||||||
|
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
@@ -2482,7 +2482,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList(
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
|
mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
|
||||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||||
SharedMemoryHandle&& aHandle) {
|
base::SharedMemoryHandle&& aHandle) {
|
||||||
if (gfxPlatform::Initialized()) {
|
if (gfxPlatform::Initialized()) {
|
||||||
gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
|
gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
|
||||||
std::move(aHandle));
|
std::move(aHandle));
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class ContentChild final : public PContentChild,
|
|||||||
const mozilla::dom::ipc::StructuredCloneData& aInitialData,
|
const mozilla::dom::ipc::StructuredCloneData& aInitialData,
|
||||||
bool aIsReadyForBackgroundProcessing);
|
bool aIsReadyForBackgroundProcessing);
|
||||||
|
|
||||||
void InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
|
void InitSharedUASheets(Maybe<base::SharedMemoryHandle>&& aHandle,
|
||||||
uintptr_t aAddress);
|
uintptr_t aAddress);
|
||||||
|
|
||||||
void InitGraphicsDeviceData(const ContentDeviceData& aData);
|
void InitGraphicsDeviceData(const ContentDeviceData& aData);
|
||||||
@@ -314,7 +314,7 @@ class ContentChild final : public PContentChild,
|
|||||||
nsTArray<L10nFileSourceDescriptor>&& aDescriptors);
|
nsTArray<L10nFileSourceDescriptor>&& aDescriptors);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvUpdateSharedData(
|
mozilla::ipc::IPCResult RecvUpdateSharedData(
|
||||||
SharedMemoryHandle&& aMapHandle, const uint32_t& aMapSize,
|
const FileDescriptor& aMapFile, const uint32_t& aMapSize,
|
||||||
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
|
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvFontListChanged();
|
mozilla::ipc::IPCResult RecvFontListChanged();
|
||||||
@@ -334,7 +334,7 @@ class ContentChild final : public PContentChild,
|
|||||||
mozilla::ipc::IPCResult RecvRebuildFontList(const bool& aFullRebuild);
|
mozilla::ipc::IPCResult RecvRebuildFontList(const bool& aFullRebuild);
|
||||||
mozilla::ipc::IPCResult RecvFontListShmBlockAdded(
|
mozilla::ipc::IPCResult RecvFontListShmBlockAdded(
|
||||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||||
SharedMemoryHandle&& aHandle);
|
base::SharedMemoryHandle&& aHandle);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvUpdateAppLocales(
|
mozilla::ipc::IPCResult RecvUpdateAppLocales(
|
||||||
nsTArray<nsCString>&& aAppLocales);
|
nsTArray<nsCString>&& aAppLocales);
|
||||||
@@ -510,9 +510,9 @@ class ContentChild final : public PContentChild,
|
|||||||
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
|
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
|
||||||
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
|
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
|
||||||
FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList,
|
FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList,
|
||||||
Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
|
Maybe<base::SharedMemoryHandle>&& aSharedUASheetHandle,
|
||||||
const uintptr_t& aSharedUASheetAddress,
|
const uintptr_t& aSharedUASheetAddress,
|
||||||
nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
|
nsTArray<base::SharedMemoryHandle>&& aSharedFontListBlocks,
|
||||||
const bool& aIsReadyForBackgroundProcessing);
|
const bool& aIsReadyForBackgroundProcessing);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
|
mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
|
||||||
@@ -542,7 +542,7 @@ class ContentChild final : public PContentChild,
|
|||||||
// for use during gfx initialization.
|
// for use during gfx initialization.
|
||||||
SystemFontList& SystemFontList() { return mFontList; }
|
SystemFontList& SystemFontList() { return mFontList; }
|
||||||
|
|
||||||
nsTArray<SharedMemoryHandle>& SharedFontListBlocks() {
|
nsTArray<base::SharedMemoryHandle>& SharedFontListBlocks() {
|
||||||
return mSharedFontListBlocks;
|
return mSharedFontListBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -831,7 +831,7 @@ class ContentChild final : public PContentChild,
|
|||||||
// Temporary storage for look and feel data.
|
// Temporary storage for look and feel data.
|
||||||
FullLookAndFeel mLookAndFeelData;
|
FullLookAndFeel mLookAndFeelData;
|
||||||
// Temporary storage for list of shared-fontlist memory blocks.
|
// Temporary storage for list of shared-fontlist memory blocks.
|
||||||
nsTArray<SharedMemoryHandle> mSharedFontListBlocks;
|
nsTArray<base::SharedMemoryHandle> mSharedFontListBlocks;
|
||||||
|
|
||||||
AppInfo mAppInfo;
|
AppInfo mAppInfo;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
#include "ContentParent.h"
|
#include "ContentParent.h"
|
||||||
#include "mozilla/ipc/ProcessUtils.h"
|
#include "mozilla/ipc/ProcessUtils.h"
|
||||||
@@ -150,7 +151,6 @@
|
|||||||
#include "mozilla/ipc/Endpoint.h"
|
#include "mozilla/ipc/Endpoint.h"
|
||||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "mozilla/ipc/TestShellParent.h"
|
#include "mozilla/ipc/TestShellParent.h"
|
||||||
#include "mozilla/layers/CompositorThread.h"
|
#include "mozilla/layers/CompositorThread.h"
|
||||||
#include "mozilla/layers/ImageBridgeParent.h"
|
#include "mozilla/layers/ImageBridgeParent.h"
|
||||||
@@ -1526,12 +1526,11 @@ void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
|
|||||||
|
|
||||||
void ContentParent::BroadcastStringBundle(
|
void ContentParent::BroadcastStringBundle(
|
||||||
const StringBundleDescriptor& aBundle) {
|
const StringBundleDescriptor& aBundle) {
|
||||||
|
AutoTArray<StringBundleDescriptor, 1> array;
|
||||||
|
array.AppendElement(aBundle);
|
||||||
|
|
||||||
for (auto* cp : AllProcesses(eLive)) {
|
for (auto* cp : AllProcesses(eLive)) {
|
||||||
AutoTArray<StringBundleDescriptor, 1> array;
|
Unused << cp->SendRegisterStringBundles(array);
|
||||||
array.AppendElement(StringBundleDescriptor(
|
|
||||||
aBundle.bundleURL(), SharedMemory::CloneHandle(aBundle.mapHandle()),
|
|
||||||
aBundle.mapSize()));
|
|
||||||
Unused << cp->SendRegisterStringBundles(std::move(array));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1545,9 +1544,9 @@ void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
|
|||||||
uint32_t aIndex) {
|
uint32_t aIndex) {
|
||||||
auto* pfl = gfxPlatformFontList::PlatformFontList();
|
auto* pfl = gfxPlatformFontList::PlatformFontList();
|
||||||
for (auto* cp : AllProcesses(eLive)) {
|
for (auto* cp : AllProcesses(eLive)) {
|
||||||
SharedMemory::Handle handle =
|
base::SharedMemoryHandle handle =
|
||||||
pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
|
pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
|
||||||
if (handle == SharedMemory::NULLHandle()) {
|
if (handle == base::SharedMemory::NULLHandle()) {
|
||||||
// If something went wrong here, we just skip it; the child will need to
|
// If something went wrong here, we just skip it; the child will need to
|
||||||
// request the block as needed, at some performance cost.
|
// request the block as needed, at some performance cost.
|
||||||
continue;
|
continue;
|
||||||
@@ -5681,7 +5680,7 @@ mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
|
mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
|
||||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||||
SharedMemory::Handle* aOut) {
|
base::SharedMemoryHandle* aOut) {
|
||||||
auto* fontList = gfxPlatformFontList::PlatformFontList();
|
auto* fontList = gfxPlatformFontList::PlatformFontList();
|
||||||
MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
|
MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
|
||||||
fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
|
fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
|
||||||
@@ -5733,7 +5732,7 @@ mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
|
mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
|
||||||
nsIURI* aURI, SharedMemory::Handle* aOutHandle, uint32_t* aOutSize) {
|
nsIURI* aURI, base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize) {
|
||||||
if (!aURI) {
|
if (!aURI) {
|
||||||
return IPC_FAIL(this, "aURI must not be null.");
|
return IPC_FAIL(this, "aURI must not be null.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "mozilla/ipc/BackgroundUtils.h"
|
#include "mozilla/ipc/BackgroundUtils.h"
|
||||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||||
#include "mozilla/ipc/InputStreamUtils.h"
|
#include "mozilla/ipc/InputStreamUtils.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/DataMutex.h"
|
#include "mozilla/DataMutex.h"
|
||||||
#include "mozilla/HalTypes.h"
|
#include "mozilla/HalTypes.h"
|
||||||
@@ -1128,7 +1127,7 @@ class ContentParent final : public PContentParent,
|
|||||||
|
|
||||||
mozilla::ipc::IPCResult RecvGetFontListShmBlock(
|
mozilla::ipc::IPCResult RecvGetFontListShmBlock(
|
||||||
const uint32_t& aGeneration, const uint32_t& aIndex,
|
const uint32_t& aGeneration, const uint32_t& aIndex,
|
||||||
mozilla::ipc::SharedMemory::Handle* aOut);
|
base::SharedMemoryHandle* aOut);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvInitializeFamily(const uint32_t& aGeneration,
|
mozilla::ipc::IPCResult RecvInitializeFamily(const uint32_t& aGeneration,
|
||||||
const uint32_t& aFamilyIndex,
|
const uint32_t& aFamilyIndex,
|
||||||
@@ -1151,9 +1150,9 @@ class ContentParent final : public PContentParent,
|
|||||||
mozilla::ipc::IPCResult RecvStartCmapLoading(const uint32_t& aGeneration,
|
mozilla::ipc::IPCResult RecvStartCmapLoading(const uint32_t& aGeneration,
|
||||||
const uint32_t& aStartIndex);
|
const uint32_t& aStartIndex);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvGetHyphDict(
|
mozilla::ipc::IPCResult RecvGetHyphDict(nsIURI* aURIParams,
|
||||||
nsIURI* aURIParams, mozilla::ipc::SharedMemory::Handle* aOutHandle,
|
base::SharedMemoryHandle* aOutHandle,
|
||||||
uint32_t* aOutSize);
|
uint32_t* aOutSize);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsAString& aCodecName,
|
mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsAString& aCodecName,
|
||||||
const uint32_t& aDecodeFPS);
|
const uint32_t& aDecodeFPS);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "mozilla/ipc/IOThreadChild.h"
|
#include "mozilla/ipc/IOThreadChild.h"
|
||||||
|
|
||||||
#include "ContentProcess.h"
|
#include "ContentProcess.h"
|
||||||
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
|
||||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||||
@@ -77,7 +78,7 @@ void ContentProcess::InfallibleInit(int aArgc, char* aArgv[]) {
|
|||||||
geckoargs::sParentBuildID.Get(aArgc, aArgv);
|
geckoargs::sParentBuildID.Get(aArgc, aArgv);
|
||||||
|
|
||||||
// command line: -jsInitHandle handle -jsInitLen length
|
// command line: -jsInitHandle handle -jsInitLen length
|
||||||
Maybe<mozilla::ipc::SharedMemoryHandle> jsInitHandle =
|
Maybe<UniqueFileHandle> jsInitHandle =
|
||||||
geckoargs::sJsInitHandle.Get(aArgc, aArgv);
|
geckoargs::sJsInitHandle.Get(aArgc, aArgv);
|
||||||
Maybe<uint64_t> jsInitLen = geckoargs::sJsInitLen.Get(aArgc, aArgv);
|
Maybe<uint64_t> jsInitLen = geckoargs::sJsInitLen.Get(aArgc, aArgv);
|
||||||
|
|
||||||
|
|||||||
@@ -6,40 +6,39 @@
|
|||||||
|
|
||||||
#include "MemMapSnapshot.h"
|
#include "MemMapSnapshot.h"
|
||||||
|
|
||||||
|
#include "mozilla/AutoMemMap.h"
|
||||||
#include "mozilla/ResultExtensions.h"
|
#include "mozilla/ResultExtensions.h"
|
||||||
|
#include "mozilla/Try.h"
|
||||||
|
#include "mozilla/ipc/FileDescriptor.h"
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
Result<Ok, nsresult> MemMapSnapshot::Init(size_t aSize) {
|
Result<Ok, nsresult> MemMapSnapshot::Init(size_t aSize) {
|
||||||
MOZ_ASSERT(!mMem);
|
MOZ_ASSERT(!mInitialized);
|
||||||
|
|
||||||
auto aMem = MakeRefPtr<SharedMemory>();
|
if (NS_WARN_IF(!mMem.CreateFreezeable(aSize))) {
|
||||||
if (NS_WARN_IF(!aMem->CreateFreezable(aSize))) {
|
|
||||||
return Err(NS_ERROR_FAILURE);
|
return Err(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
if (NS_WARN_IF(!aMem->Map(aSize))) {
|
if (NS_WARN_IF(!mMem.Map(aSize))) {
|
||||||
return Err(NS_ERROR_FAILURE);
|
return Err(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
mMem = std::move(aMem);
|
mInitialized = true;
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Ok, nsresult> MemMapSnapshot::Finalize(RefPtr<SharedMemory>& aMem) {
|
Result<Ok, nsresult> MemMapSnapshot::Finalize(loader::AutoMemMap& aMem) {
|
||||||
MOZ_ASSERT(mMem);
|
MOZ_ASSERT(mInitialized);
|
||||||
|
|
||||||
auto size = mMem->Size();
|
if (NS_WARN_IF(!mMem.Freeze())) {
|
||||||
if (NS_WARN_IF(!mMem->Freeze())) {
|
|
||||||
return Err(NS_ERROR_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
aMem = std::move(mMem);
|
|
||||||
|
|
||||||
// We need to re-map the memory as `Freeze()` unmaps it.
|
|
||||||
if (NS_WARN_IF(!aMem->Map(size))) {
|
|
||||||
return Err(NS_ERROR_FAILURE);
|
return Err(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
// TakeHandle resets mMem, so call max_size first.
|
||||||
|
size_t size = mMem.max_size();
|
||||||
|
FileDescriptor memHandle(mMem.TakeHandle());
|
||||||
|
MOZ_TRY(aMem.initWithHandle(memHandle, size));
|
||||||
|
|
||||||
|
mInitialized = false;
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,17 @@
|
|||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/RangedPtr.h"
|
#include "mozilla/RangedPtr.h"
|
||||||
#include "mozilla/Result.h"
|
#include "mozilla/Result.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "base/shared_memory.h"
|
||||||
#include "ErrorList.h"
|
#include "ErrorList.h"
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
namespace mozilla {
|
||||||
|
namespace loader {
|
||||||
|
class AutoMemMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for creating a read-only snapshot of memory-mapped data.
|
* A helper class for creating a read-only snapshot of memory-mapped data.
|
||||||
@@ -31,18 +35,20 @@ namespace mozilla::ipc {
|
|||||||
class MOZ_RAII MemMapSnapshot {
|
class MOZ_RAII MemMapSnapshot {
|
||||||
public:
|
public:
|
||||||
Result<Ok, nsresult> Init(size_t aSize);
|
Result<Ok, nsresult> Init(size_t aSize);
|
||||||
Result<Ok, nsresult> Finalize(RefPtr<SharedMemory>& aMem);
|
Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RangedPtr<T> Get() {
|
RangedPtr<T> Get() {
|
||||||
MOZ_ASSERT(mMem);
|
MOZ_ASSERT(mInitialized);
|
||||||
return {static_cast<T*>(mMem->Memory()), mMem->MaxSize() / sizeof(T)};
|
return {static_cast<T*>(mMem.memory()), mMem.max_size() / sizeof(T)};
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<SharedMemory> mMem;
|
base::SharedMemory mMem;
|
||||||
|
bool mInitialized = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
} // namespace ipc
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // dom_ipc_MemMapSnapshot_h
|
#endif // dom_ipc_MemMapSnapshot_h
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext
|
|||||||
using mozilla::dom::PermitUnloadResult from "nsIDocumentViewer.h";
|
using mozilla::dom::PermitUnloadResult from "nsIDocumentViewer.h";
|
||||||
using mozilla::dom::MaybeDiscardedWindowContext from "mozilla/dom/WindowContext.h";
|
using mozilla::dom::MaybeDiscardedWindowContext from "mozilla/dom/WindowContext.h";
|
||||||
using mozilla::dom::WindowContextTransaction from "mozilla/dom/WindowContext.h";
|
using mozilla::dom::WindowContextTransaction from "mozilla/dom/WindowContext.h";
|
||||||
[MoveOnly] using mozilla::ipc::SharedMemoryHandle from "mozilla/ipc/SharedMemory.h";
|
[MoveOnly] using base::SharedMemoryHandle from "base/shared_memory.h";
|
||||||
using gfxSparseBitSet from "gfxFontUtils.h";
|
using gfxSparseBitSet from "gfxFontUtils.h";
|
||||||
using FontVisibility from "gfxFontEntry.h";
|
using FontVisibility from "gfxFontEntry.h";
|
||||||
using mozilla::dom::MediaControlAction from "mozilla/dom/MediaControlKeySource.h";
|
using mozilla::dom::MediaControlAction from "mozilla/dom/MediaControlKeySource.h";
|
||||||
@@ -401,7 +401,7 @@ struct VisitedQueryResult
|
|||||||
struct StringBundleDescriptor
|
struct StringBundleDescriptor
|
||||||
{
|
{
|
||||||
nsCString bundleURL;
|
nsCString bundleURL;
|
||||||
SharedMemoryHandle mapHandle;
|
FileDescriptor mapFile;
|
||||||
uint32_t mapSize;
|
uint32_t mapSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -750,7 +750,7 @@ child:
|
|||||||
|
|
||||||
async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
|
async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
|
||||||
|
|
||||||
async UpdateSharedData(SharedMemoryHandle aMapHandle, uint32_t aSize,
|
async UpdateSharedData(FileDescriptor mapFile, uint32_t aSize,
|
||||||
IPCBlob[] blobs,
|
IPCBlob[] blobs,
|
||||||
nsCString[] changedKeys);
|
nsCString[] changedKeys);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "MemMapSnapshot.h"
|
#include "MemMapSnapshot.h"
|
||||||
#include "ScriptPreloader-inl.h"
|
#include "ScriptPreloader-inl.h"
|
||||||
|
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/dom/AutoEntryScript.h"
|
#include "mozilla/dom/AutoEntryScript.h"
|
||||||
#include "mozilla/dom/BlobImpl.h"
|
#include "mozilla/dom/BlobImpl.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
@@ -42,12 +41,12 @@ static inline void AlignTo(size_t* aOffset, size_t aAlign) {
|
|||||||
|
|
||||||
SharedMap::SharedMap() = default;
|
SharedMap::SharedMap() = default;
|
||||||
|
|
||||||
SharedMap::SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&& aMapHandle,
|
SharedMap::SharedMap(nsIGlobalObject* aGlobal, const FileDescriptor& aMapFile,
|
||||||
size_t aMapSize, nsTArray<RefPtr<BlobImpl>>&& aBlobs)
|
size_t aMapSize, nsTArray<RefPtr<BlobImpl>>&& aBlobs)
|
||||||
: DOMEventTargetHelper(aGlobal),
|
: DOMEventTargetHelper(aGlobal), mBlobImpls(std::move(aBlobs)) {
|
||||||
mBlobImpls(std::move(aBlobs)),
|
mMapFile.reset(new FileDescriptor(aMapFile));
|
||||||
mMapHandle(std::move(aMapHandle)),
|
mMapSize = aMapSize;
|
||||||
mMapSize(aMapSize) {}
|
}
|
||||||
|
|
||||||
bool SharedMap::Has(const nsACString& aName) {
|
bool SharedMap::Has(const nsACString& aName) {
|
||||||
Unused << MaybeRebuild();
|
Unused << MaybeRebuild();
|
||||||
@@ -97,20 +96,24 @@ void SharedMap::Entry::Read(JSContext* aCx,
|
|||||||
holder.Read(aCx, aRetVal, aRv);
|
holder.Read(aCx, aRetVal, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedMap::SharedMemoryHandle SharedMap::CloneHandle() const {
|
FileDescriptor SharedMap::CloneMapFile() const {
|
||||||
if (mMap->IsValid()) {
|
if (mMap.initialized()) {
|
||||||
return mMap->CloneHandle();
|
return mMap.cloneHandle();
|
||||||
}
|
}
|
||||||
return SharedMemory::CloneHandle(mMapHandle);
|
return *mMapFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMap::Update(SharedMemoryHandle&& aMapHandle, size_t aMapSize,
|
void SharedMap::Update(const FileDescriptor& aMapFile, size_t aMapSize,
|
||||||
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
|
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
|
||||||
nsTArray<nsCString>&& aChangedKeys) {
|
nsTArray<nsCString>&& aChangedKeys) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!mWritable);
|
MOZ_DIAGNOSTIC_ASSERT(!mWritable);
|
||||||
|
|
||||||
mMap->TakeHandleAndUnmap();
|
mMap.reset();
|
||||||
mMapHandle = std::move(aMapHandle);
|
if (mMapFile) {
|
||||||
|
*mMapFile = aMapFile;
|
||||||
|
} else {
|
||||||
|
mMapFile.reset(new FileDescriptor(aMapFile));
|
||||||
|
}
|
||||||
mMapSize = aMapSize;
|
mMapSize = aMapSize;
|
||||||
mEntries.Clear();
|
mEntries.Clear();
|
||||||
mEntryArray.reset();
|
mEntryArray.reset();
|
||||||
@@ -191,7 +194,7 @@ void SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<Ok, nsresult> SharedMap::MaybeRebuild() {
|
Result<Ok, nsresult> SharedMap::MaybeRebuild() {
|
||||||
if (!SharedMemory::IsHandleValid(mMapHandle)) {
|
if (!mMapFile) {
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,19 +206,13 @@ Result<Ok, nsresult> SharedMap::MaybeRebuild() {
|
|||||||
// its shared memory region. When needed, that structured clone data is
|
// its shared memory region. When needed, that structured clone data is
|
||||||
// retrieved directly as indexes into the SharedMap's shared memory region.
|
// retrieved directly as indexes into the SharedMap's shared memory region.
|
||||||
|
|
||||||
if (!mMap->SetHandle(SharedMemory::CloneHandle(mMapHandle),
|
MOZ_TRY(mMap.initWithHandle(*mMapFile, mMapSize));
|
||||||
SharedMemory::OpenRights::RightsReadOnly)) {
|
mMapFile.reset();
|
||||||
return Err(NS_ERROR_FAILURE);
|
|
||||||
}
|
|
||||||
mMapHandle = SharedMemory::NULLHandle();
|
|
||||||
if (!mMap->Map(mMapSize)) {
|
|
||||||
return Err(NS_ERROR_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should be able to pass this range as an initializer list or an immediate
|
// We should be able to pass this range as an initializer list or an immediate
|
||||||
// param, but gcc currently chokes on that if optimization is enabled, and
|
// param, but gcc currently chokes on that if optimization is enabled, and
|
||||||
// initializes everything to 0.
|
// initializes everything to 0.
|
||||||
Range<uint8_t> range((uint8_t*)mMap->Memory(), mMap->Size());
|
Range<uint8_t> range(&mMap.get<uint8_t>()[0], mMap.size());
|
||||||
InputBuffer buffer(range);
|
InputBuffer buffer(range);
|
||||||
|
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
@@ -248,7 +245,7 @@ WritableSharedMap::WritableSharedMap() {
|
|||||||
// Serialize the initial empty contents of the map immediately so that we
|
// Serialize the initial empty contents of the map immediately so that we
|
||||||
// always have a file descriptor to send to callers of CloneMapFile().
|
// always have a file descriptor to send to callers of CloneMapFile().
|
||||||
Unused << Serialize();
|
Unused << Serialize();
|
||||||
MOZ_RELEASE_ASSERT(mMap->IsValid());
|
MOZ_RELEASE_ASSERT(mMap.initialized());
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedMap* WritableSharedMap::GetReadOnly() {
|
SharedMap* WritableSharedMap::GetReadOnly() {
|
||||||
@@ -256,7 +253,7 @@ SharedMap* WritableSharedMap::GetReadOnly() {
|
|||||||
nsTArray<RefPtr<BlobImpl>> blobs(mBlobImpls.Clone());
|
nsTArray<RefPtr<BlobImpl>> blobs(mBlobImpls.Clone());
|
||||||
mReadOnly =
|
mReadOnly =
|
||||||
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
|
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
|
||||||
CloneHandle(), MapSize(), std::move(blobs));
|
CloneMapFile(), MapSize(), std::move(blobs));
|
||||||
}
|
}
|
||||||
return mReadOnly;
|
return mReadOnly;
|
||||||
}
|
}
|
||||||
@@ -339,7 +336,7 @@ Result<Ok, nsresult> WritableSharedMap::Serialize() {
|
|||||||
memcpy(ptr.get(), header.Get(), header.cursor());
|
memcpy(ptr.get(), header.Get(), header.cursor());
|
||||||
|
|
||||||
// We've already updated offsets at this point. We need this to succeed.
|
// We've already updated offsets at this point. We need this to succeed.
|
||||||
mMap->TakeHandleAndUnmap();
|
mMap.reset();
|
||||||
MOZ_RELEASE_ASSERT(mem.Finalize(mMap).isOk());
|
MOZ_RELEASE_ASSERT(mem.Finalize(mMap).isOk());
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
@@ -355,7 +352,7 @@ void WritableSharedMap::SendTo(ContentParent* aParent) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Unused << aParent->SendUpdateSharedData(CloneHandle(), mMap->Size(), blobs,
|
Unused << aParent->SendUpdateSharedData(CloneMapFile(), mMap.size(), blobs,
|
||||||
mChangedKeys);
|
mChangedKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +373,7 @@ void WritableSharedMap::BroadcastChanges() {
|
|||||||
|
|
||||||
if (mReadOnly) {
|
if (mReadOnly) {
|
||||||
nsTArray<RefPtr<BlobImpl>> blobImpls(mBlobImpls.Clone());
|
nsTArray<RefPtr<BlobImpl>> blobImpls(mBlobImpls.Clone());
|
||||||
mReadOnly->Update(CloneHandle(), mMap->Size(), std::move(blobImpls),
|
mReadOnly->Update(CloneMapFile(), mMap.size(), std::move(blobImpls),
|
||||||
std::move(mChangedKeys));
|
std::move(mChangedKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
#include "mozilla/dom/MozSharedMapBinding.h"
|
#include "mozilla/dom/MozSharedMapBinding.h"
|
||||||
|
|
||||||
|
#include "mozilla/AutoMemMap.h"
|
||||||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "mozilla/DOMEventTargetHelper.h"
|
#include "mozilla/DOMEventTargetHelper.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
@@ -53,13 +53,12 @@ namespace ipc {
|
|||||||
* WritableSharedMap instances.
|
* WritableSharedMap instances.
|
||||||
*/
|
*/
|
||||||
class SharedMap : public DOMEventTargetHelper {
|
class SharedMap : public DOMEventTargetHelper {
|
||||||
using SharedMemory = mozilla::ipc::SharedMemory;
|
using FileDescriptor = mozilla::ipc::FileDescriptor;
|
||||||
using SharedMemoryHandle = mozilla::ipc::SharedMemoryHandle;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SharedMap();
|
SharedMap();
|
||||||
|
|
||||||
SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&&, size_t,
|
SharedMap(nsIGlobalObject* aGlobal, const FileDescriptor&, size_t,
|
||||||
nsTArray<RefPtr<BlobImpl>>&& aBlobs);
|
nsTArray<RefPtr<BlobImpl>>&& aBlobs);
|
||||||
|
|
||||||
// Returns true if the map contains the given (UTF-8) key.
|
// Returns true if the map contains the given (UTF-8) key.
|
||||||
@@ -97,7 +96,7 @@ class SharedMap : public DOMEventTargetHelper {
|
|||||||
* memory region for this map. The file descriptor may be passed between
|
* memory region for this map. The file descriptor may be passed between
|
||||||
* processes, and used to update corresponding instances in child processes.
|
* processes, and used to update corresponding instances in child processes.
|
||||||
*/
|
*/
|
||||||
SharedMemoryHandle CloneHandle() const;
|
FileDescriptor CloneMapFile() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of the memory mapped region that backs this map. Must be
|
* Returns the size of the memory mapped region that backs this map. Must be
|
||||||
@@ -105,14 +104,14 @@ class SharedMap : public DOMEventTargetHelper {
|
|||||||
* descriptor returned by CloneMapFile() in order to initialize or update a
|
* descriptor returned by CloneMapFile() in order to initialize or update a
|
||||||
* child SharedMap.
|
* child SharedMap.
|
||||||
*/
|
*/
|
||||||
size_t MapSize() const { return mMap->Size(); }
|
size_t MapSize() const { return mMap.size(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates this instance to reflect the contents of the shared memory region
|
* Updates this instance to reflect the contents of the shared memory region
|
||||||
* in the given map handle, and broadcasts a change event for the given set of
|
* in the given map file, and broadcasts a change event for the given set of
|
||||||
* changed (UTF-8-encoded) keys.
|
* changed (UTF-8-encoded) keys.
|
||||||
*/
|
*/
|
||||||
void Update(SharedMemoryHandle&& aMapHandle, size_t aMapSize,
|
void Update(const FileDescriptor& aMapFile, size_t aMapSize,
|
||||||
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
|
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
|
||||||
nsTArray<nsCString>&& aChangedKeys);
|
nsTArray<nsCString>&& aChangedKeys);
|
||||||
|
|
||||||
@@ -263,8 +262,12 @@ class SharedMap : public DOMEventTargetHelper {
|
|||||||
Result<Ok, nsresult> MaybeRebuild();
|
Result<Ok, nsresult> MaybeRebuild();
|
||||||
void MaybeRebuild() const;
|
void MaybeRebuild() const;
|
||||||
|
|
||||||
SharedMemoryHandle mMapHandle;
|
// Note: This header is included by WebIDL binding headers, and therefore
|
||||||
// The size of the memory-mapped region backed by mMap, in bytes.
|
// can't include "windows.h". Since FileDescriptor.h does include "windows.h"
|
||||||
|
// on Windows, we can only forward declare FileDescriptor, and can't include
|
||||||
|
// it as an inline member.
|
||||||
|
UniquePtr<FileDescriptor> mMapFile;
|
||||||
|
// The size of the memory-mapped region backed by mMapFile, in bytes.
|
||||||
size_t mMapSize = 0;
|
size_t mMapSize = 0;
|
||||||
|
|
||||||
mutable nsClassHashtable<nsCStringHashKey, Entry> mEntries;
|
mutable nsClassHashtable<nsCStringHashKey, Entry> mEntries;
|
||||||
@@ -273,14 +276,14 @@ class SharedMap : public DOMEventTargetHelper {
|
|||||||
// Manages the memory mapping of the current snapshot. This is initialized
|
// Manages the memory mapping of the current snapshot. This is initialized
|
||||||
// lazily after each SharedMap construction or updated, based on the values in
|
// lazily after each SharedMap construction or updated, based on the values in
|
||||||
// mMapFile and mMapSize.
|
// mMapFile and mMapSize.
|
||||||
RefPtr<SharedMemory> mMap = MakeRefPtr<SharedMemory>();
|
loader::AutoMemMap mMap;
|
||||||
|
|
||||||
bool mWritable = false;
|
bool mWritable = false;
|
||||||
|
|
||||||
// Returns a pointer to the beginning of the memory mapped snapshot. Entry
|
// Returns a pointer to the beginning of the memory mapped snapshot. Entry
|
||||||
// offsets are relative to this pointer, and Entry objects access their
|
// offsets are relative to this pointer, and Entry objects access their
|
||||||
// structured clone data by indexing this pointer.
|
// structured clone data by indexing this pointer.
|
||||||
char* Data() { return static_cast<char*>(mMap->Memory()); }
|
char* Data() { return mMap.get<char>().get(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class WritableSharedMap final : public SharedMap {
|
class WritableSharedMap final : public SharedMap {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "mozilla/BinarySearch.h"
|
#include "mozilla/BinarySearch.h"
|
||||||
#include "mozilla/Try.h"
|
#include "mozilla/Try.h"
|
||||||
|
#include "mozilla/ipc/FileDescriptor.h"
|
||||||
|
|
||||||
using namespace mozilla::loader;
|
using namespace mozilla::loader;
|
||||||
|
|
||||||
@@ -27,42 +28,27 @@ static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
|
|||||||
return mod ? aAlign - mod : 0;
|
return mod ? aAlign - mod : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedStringMap::SharedStringMap(const SharedMemoryHandle& aMapHandle,
|
SharedStringMap::SharedStringMap(const FileDescriptor& aMapFile,
|
||||||
size_t aMapSize) {
|
size_t aMapSize) {
|
||||||
auto map = MakeRefPtr<SharedMemory>();
|
auto result = mMap.initWithHandle(aMapFile, aMapSize);
|
||||||
{
|
MOZ_RELEASE_ASSERT(result.isOk());
|
||||||
auto result = map->SetHandle(SharedMemory::CloneHandle(aMapHandle),
|
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
||||||
SharedMemory::OpenRights::RightsReadOnly);
|
|
||||||
MOZ_RELEASE_ASSERT(result);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto result = map->Map(aMapSize);
|
|
||||||
MOZ_RELEASE_ASSERT(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We return literal nsStrings and nsCStrings pointing to the mapped data,
|
// We return literal nsStrings and nsCStrings pointing to the mapped data,
|
||||||
// which means that we may still have references to the mapped data even
|
// which means that we may still have references to the mapped data even
|
||||||
// after this instance is destroyed. That means that we need to keep the
|
// after this instance is destroyed. That means that we need to keep the
|
||||||
// mapping alive until process shutdown, in order to be safe.
|
// mapping alive until process shutdown, in order to be safe.
|
||||||
mMappedMemory = map->TakeMapping();
|
mMap.setPersistent();
|
||||||
mHandle = map->TakeHandle();
|
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedStringMap::SharedStringMap(SharedStringMapBuilder&& aBuilder) {
|
SharedStringMap::SharedStringMap(SharedStringMapBuilder&& aBuilder) {
|
||||||
RefPtr<SharedMemory> map;
|
auto result = aBuilder.Finalize(mMap);
|
||||||
auto result = aBuilder.Finalize(map);
|
MOZ_RELEASE_ASSERT(result.isOk());
|
||||||
MOZ_RELEASE_ASSERT(result.isOk() && map);
|
|
||||||
|
|
||||||
mMappedMemory = map->TakeMapping();
|
|
||||||
mHandle = map->TakeHandle();
|
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
|
||||||
|
mMap.setPersistent();
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::SharedMemoryHandle SharedStringMap::CloneHandle() const {
|
mozilla::ipc::FileDescriptor SharedStringMap::CloneFileDescriptor() const {
|
||||||
return SharedMemory::CloneHandle(mHandle);
|
return mMap.cloneHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SharedStringMap::Has(const nsCString& aKey) {
|
bool SharedStringMap::Has(const nsCString& aKey) {
|
||||||
@@ -98,7 +84,7 @@ void SharedStringMapBuilder::Add(const nsCString& aKey,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<Ok, nsresult> SharedStringMapBuilder::Finalize(
|
Result<Ok, nsresult> SharedStringMapBuilder::Finalize(
|
||||||
RefPtr<SharedMemory>& aMap) {
|
loader::AutoMemMap& aMap) {
|
||||||
using Header = SharedStringMap::Header;
|
using Header = SharedStringMap::Header;
|
||||||
|
|
||||||
MOZ_ASSERT(mEntries.Count() == mKeyTable.Count());
|
MOZ_ASSERT(mEntries.Count() == mKeyTable.Count());
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
#ifndef dom_ipc_SharedStringMap_h
|
#ifndef dom_ipc_SharedStringMap_h
|
||||||
#define dom_ipc_SharedStringMap_h
|
#define dom_ipc_SharedStringMap_h
|
||||||
|
|
||||||
|
#include "mozilla/AutoMemMap.h"
|
||||||
#include "mozilla/Result.h"
|
#include "mozilla/Result.h"
|
||||||
#include "mozilla/dom/ipc/StringTable.h"
|
#include "mozilla/dom/ipc/StringTable.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsTHashMap.h"
|
#include "nsTHashMap.h"
|
||||||
|
|
||||||
namespace mozilla::dom::ipc {
|
namespace mozilla::dom::ipc {
|
||||||
@@ -30,6 +30,8 @@ class SharedStringMapBuilder;
|
|||||||
* freed before process shutdown. Do not use it for short-lived mappings.
|
* freed before process shutdown. Do not use it for short-lived mappings.
|
||||||
*/
|
*/
|
||||||
class SharedStringMap {
|
class SharedStringMap {
|
||||||
|
using FileDescriptor = mozilla::ipc::FileDescriptor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* The header at the beginning of the shared memory region describing its
|
* The header at the beginning of the shared memory region describing its
|
||||||
@@ -88,7 +90,7 @@ class SharedStringMap {
|
|||||||
// Note: These constructors are infallible on the premise that this class
|
// Note: These constructors are infallible on the premise that this class
|
||||||
// is used primarily in cases where it is critical to platform
|
// is used primarily in cases where it is critical to platform
|
||||||
// functionality.
|
// functionality.
|
||||||
explicit SharedStringMap(const mozilla::ipc::SharedMemoryHandle&, size_t);
|
explicit SharedStringMap(const FileDescriptor&, size_t);
|
||||||
explicit SharedStringMap(SharedStringMapBuilder&&);
|
explicit SharedStringMap(SharedStringMapBuilder&&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,23 +148,21 @@ class SharedStringMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of the read-only shared memory handle which backs the shared
|
* Returns a copy of the read-only file descriptor which backs the shared
|
||||||
* memory region for this map. The handle may be passed between processes, and
|
* memory region for this map. The file descriptor may be passed between
|
||||||
* used to construct new instances of SharedStringMap with the same data as
|
* processes, and used to construct new instances of SharedStringMap with
|
||||||
* this instance.
|
* the same data as this instance.
|
||||||
*/
|
*/
|
||||||
mozilla::ipc::SharedMemoryHandle CloneHandle() const;
|
FileDescriptor CloneFileDescriptor() const;
|
||||||
|
|
||||||
size_t MapSize() const { return mMappedMemory.size(); }
|
size_t MapSize() const { return mMap.size(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~SharedStringMap() = default;
|
~SharedStringMap() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Type-safe getters for values in the shared memory region:
|
// Type-safe getters for values in the shared memory region:
|
||||||
const Header& GetHeader() const {
|
const Header& GetHeader() const { return mMap.get<Header>()[0]; }
|
||||||
return *reinterpret_cast<const Header*>(mMappedMemory.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
RangedPtr<const Entry> Entries() const {
|
RangedPtr<const Entry> Entries() const {
|
||||||
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
|
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
|
||||||
@@ -171,22 +171,18 @@ class SharedStringMap {
|
|||||||
uint32_t EntryCount() const { return GetHeader().mEntryCount; }
|
uint32_t EntryCount() const { return GetHeader().mEntryCount; }
|
||||||
|
|
||||||
StringTable<nsCString> KeyTable() const {
|
StringTable<nsCString> KeyTable() const {
|
||||||
const auto& header = GetHeader();
|
auto& header = GetHeader();
|
||||||
return {{&mMappedMemory.data()[header.mKeyStringsOffset],
|
return {{&mMap.get<uint8_t>()[header.mKeyStringsOffset],
|
||||||
header.mKeyStringsSize}};
|
header.mKeyStringsSize}};
|
||||||
}
|
}
|
||||||
|
|
||||||
StringTable<nsString> ValueTable() const {
|
StringTable<nsString> ValueTable() const {
|
||||||
const auto& header = GetHeader();
|
auto& header = GetHeader();
|
||||||
return {{&mMappedMemory.data()[header.mValueStringsOffset],
|
return {{&mMap.get<uint8_t>()[header.mValueStringsOffset],
|
||||||
header.mValueStringsSize}};
|
header.mValueStringsSize}};
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::SharedMemoryHandle mHandle;
|
loader::AutoMemMap mMap;
|
||||||
// This is a leaked shared memory mapping (see the constructor definition for
|
|
||||||
// an explanation). It replaces AutoMemMap::setPersistent behavior as part of
|
|
||||||
// bug 1454816.
|
|
||||||
Span<uint8_t> mMappedMemory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,10 +201,10 @@ class MOZ_RAII SharedStringMapBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalizes the binary representation of the map, writes it to a shared
|
* Finalizes the binary representation of the map, writes it to a shared
|
||||||
* memory region, and then initializes the given SharedMemory with a reference
|
* memory region, and then initializes the given AutoMemMap with a reference
|
||||||
* to the read-only copy of it.
|
* to the read-only copy of it.
|
||||||
*/
|
*/
|
||||||
Result<Ok, nsresult> Finalize(RefPtr<mozilla::ipc::SharedMemory>& aMap);
|
Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Entry = SharedStringMap::Entry;
|
using Entry = SharedStringMap::Entry;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||||
# include "mozilla/SandboxInfo.h"
|
# include "mozilla/SandboxInfo.h"
|
||||||
# include "mozilla/ipc/SharedMemory.h"
|
# include "base/shared_memory.h"
|
||||||
#endif
|
#endif
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/SSE.h"
|
#include "mozilla/SSE.h"
|
||||||
@@ -302,7 +302,7 @@ class NotifyGMPProcessLoadedTask : public Runnable {
|
|||||||
|
|
||||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||||
if (SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia) &&
|
if (SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia) &&
|
||||||
ipc::SharedMemory::UsingPosixShm()) {
|
base::SharedMemory::UsingPosixShm()) {
|
||||||
canProfile = false;
|
canProfile = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,14 +7,13 @@
|
|||||||
|
|
||||||
#include "SharedFontList.h"
|
#include "SharedFontList.h"
|
||||||
|
|
||||||
#include "base/process.h"
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
#include "gfxFontUtils.h"
|
#include "gfxFontUtils.h"
|
||||||
#include "nsClassHashtable.h"
|
#include "nsClassHashtable.h"
|
||||||
#include "nsTHashMap.h"
|
#include "nsTHashMap.h"
|
||||||
#include "nsXULAppAPI.h"
|
#include "nsXULAppAPI.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
// This is split out from SharedFontList.h because that header is included
|
// This is split out from SharedFontList.h because that header is included
|
||||||
// quite widely (via gfxPlatformFontList.h, gfxTextRun.h, etc), and other code
|
// quite widely (via gfxPlatformFontList.h, gfxTextRun.h, etc), and other code
|
||||||
@@ -243,11 +242,11 @@ class FontList {
|
|||||||
* list has changed/grown since the child was first initialized).
|
* list has changed/grown since the child was first initialized).
|
||||||
*/
|
*/
|
||||||
void ShareShmBlockToProcess(uint32_t aIndex, base::ProcessId aPid,
|
void ShareShmBlockToProcess(uint32_t aIndex, base::ProcessId aPid,
|
||||||
ipc::SharedMemory::Handle* aOut) {
|
base::SharedMemoryHandle* aOut) {
|
||||||
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
||||||
if (aIndex >= mReadOnlyShmems.Length()) {
|
if (aIndex >= mReadOnlyShmems.Length()) {
|
||||||
// Block index out of range
|
// Block index out of range
|
||||||
*aOut = ipc::SharedMemory::NULLHandle();
|
*aOut = base::SharedMemory::NULLHandle();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*aOut = mReadOnlyShmems[aIndex]->CloneHandle();
|
*aOut = mReadOnlyShmems[aIndex]->CloneHandle();
|
||||||
@@ -261,14 +260,14 @@ class FontList {
|
|||||||
* shared to the given process. This is used at child process startup
|
* shared to the given process. This is used at child process startup
|
||||||
* to pass the complete list at once.
|
* to pass the complete list at once.
|
||||||
*/
|
*/
|
||||||
void ShareBlocksToProcess(nsTArray<ipc::SharedMemory::Handle>* aBlocks,
|
void ShareBlocksToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
|
||||||
base::ProcessId aPid);
|
base::ProcessId aPid);
|
||||||
|
|
||||||
ipc::SharedMemory::Handle ShareBlockToProcess(uint32_t aIndex,
|
base::SharedMemoryHandle ShareBlockToProcess(uint32_t aIndex,
|
||||||
base::ProcessId aPid);
|
base::ProcessId aPid);
|
||||||
|
|
||||||
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||||
ipc::SharedMemory::Handle aHandle);
|
base::SharedMemoryHandle aHandle);
|
||||||
/**
|
/**
|
||||||
* Support for memory reporter.
|
* Support for memory reporter.
|
||||||
*/
|
*/
|
||||||
@@ -300,11 +299,11 @@ class FontList {
|
|||||||
struct ShmBlock {
|
struct ShmBlock {
|
||||||
// Takes ownership of aShmem. Note that in a child process, aShmem will be
|
// Takes ownership of aShmem. Note that in a child process, aShmem will be
|
||||||
// mapped as read-only.
|
// mapped as read-only.
|
||||||
explicit ShmBlock(RefPtr<ipc::SharedMemory>&& aShmem)
|
explicit ShmBlock(mozilla::UniquePtr<base::SharedMemory>&& aShmem)
|
||||||
: mShmem(std::move(aShmem)) {}
|
: mShmem(std::move(aShmem)) {}
|
||||||
|
|
||||||
// Get pointer to the mapped memory.
|
// Get pointer to the mapped memory.
|
||||||
void* Memory() const { return mShmem->Memory(); }
|
void* Memory() const { return mShmem->memory(); }
|
||||||
|
|
||||||
// Only the parent process does allocation, so only it will update this
|
// Only the parent process does allocation, so only it will update this
|
||||||
// field. Content processes read the value when checking Pointer validity.
|
// field. Content processes read the value when checking Pointer validity.
|
||||||
@@ -326,7 +325,7 @@ class FontList {
|
|||||||
return static_cast<BlockHeader*>(Memory())->mBlockSize;
|
return static_cast<BlockHeader*>(Memory())->mBlockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ipc::SharedMemory> mShmem;
|
mozilla::UniquePtr<base::SharedMemory> mShmem;
|
||||||
};
|
};
|
||||||
|
|
||||||
Header& GetHeader() const;
|
Header& GetHeader() const;
|
||||||
@@ -372,7 +371,7 @@ class FontList {
|
|||||||
* Auxiliary array, used only in the parent process; holds read-only copies
|
* Auxiliary array, used only in the parent process; holds read-only copies
|
||||||
* of the shmem blocks; these are what will be shared to child processes.
|
* of the shmem blocks; these are what will be shared to child processes.
|
||||||
*/
|
*/
|
||||||
nsTArray<RefPtr<ipc::SharedMemory>> mReadOnlyShmems;
|
nsTArray<mozilla::UniquePtr<base::SharedMemory>> mReadOnlyShmems;
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
// Bool array to track whether we have read face names from the name table.
|
// Bool array to track whether we have read face names from the name table.
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "gfxPlatformFontList.h"
|
#include "gfxPlatformFontList.h"
|
||||||
#include "gfxFontUtils.h"
|
#include "gfxFontUtils.h"
|
||||||
#include "gfxFont.h"
|
#include "gfxFont.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "prerror.h"
|
#include "prerror.h"
|
||||||
#include "mozilla/dom/ContentChild.h"
|
#include "mozilla/dom/ContentChild.h"
|
||||||
@@ -739,23 +738,22 @@ FontList::FontList(uint32_t aGeneration) {
|
|||||||
// SetXPCOMProcessAttributes.
|
// SetXPCOMProcessAttributes.
|
||||||
auto& blocks = dom::ContentChild::GetSingleton()->SharedFontListBlocks();
|
auto& blocks = dom::ContentChild::GetSingleton()->SharedFontListBlocks();
|
||||||
for (auto& handle : blocks) {
|
for (auto& handle : blocks) {
|
||||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
auto newShm = MakeUnique<base::SharedMemory>();
|
||||||
if (!newShm->IsHandleValid(handle)) {
|
if (!newShm->IsHandleValid(handle)) {
|
||||||
// Bail out and let UpdateShmBlocks try to do its thing below.
|
// Bail out and let UpdateShmBlocks try to do its thing below.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!newShm->SetHandle(std::move(handle),
|
if (!newShm->SetHandle(std::move(handle), true)) {
|
||||||
ipc::SharedMemory::OpenRights::RightsReadOnly)) {
|
|
||||||
MOZ_CRASH("failed to set shm handle");
|
MOZ_CRASH("failed to set shm handle");
|
||||||
}
|
}
|
||||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
|
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
}
|
}
|
||||||
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
|
uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
|
||||||
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
||||||
if (size != SHM_BLOCK_SIZE) {
|
if (size != SHM_BLOCK_SIZE) {
|
||||||
newShm->Unmap();
|
newShm->Unmap();
|
||||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
if (!newShm->Map(size) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -802,16 +800,16 @@ FontList::Header& FontList::GetHeader() const MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
|||||||
bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
|
bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
uint32_t size = std::max(aSizeNeeded, SHM_BLOCK_SIZE);
|
uint32_t size = std::max(aSizeNeeded, SHM_BLOCK_SIZE);
|
||||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
auto newShm = MakeUnique<base::SharedMemory>();
|
||||||
if (!newShm->CreateFreezable(size)) {
|
if (!newShm->CreateFreezeable(size)) {
|
||||||
MOZ_CRASH("failed to create shared memory");
|
MOZ_CRASH("failed to create shared memory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
if (!newShm->Map(size) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto readOnly = MakeRefPtr<ipc::SharedMemory>();
|
auto readOnly = MakeUnique<base::SharedMemory>();
|
||||||
if (!newShm->ReadOnlyCopy(readOnly.get())) {
|
if (!newShm->ReadOnlyCopy(readOnly.get())) {
|
||||||
MOZ_CRASH("failed to create read-only copy");
|
MOZ_CRASH("failed to create read-only copy");
|
||||||
return false;
|
return false;
|
||||||
@@ -846,16 +844,15 @@ bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||||
ipc::SharedMemory::Handle aHandle) {
|
base::SharedMemoryHandle aHandle) {
|
||||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||||
MOZ_ASSERT(mBlocks.Length() > 0);
|
MOZ_ASSERT(mBlocks.Length() > 0);
|
||||||
|
|
||||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
auto newShm = MakeUnique<base::SharedMemory>();
|
||||||
if (!newShm->IsHandleValid(aHandle)) {
|
if (!newShm->IsHandleValid(aHandle)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!newShm->SetHandle(std::move(aHandle),
|
if (!newShm->SetHandle(std::move(aHandle), true)) {
|
||||||
ipc::SharedMemory::RightsReadOnly)) {
|
|
||||||
MOZ_CRASH("failed to set shm handle");
|
MOZ_CRASH("failed to set shm handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,15 +863,15 @@ void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
|
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
|
uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
|
||||||
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
||||||
if (size != SHM_BLOCK_SIZE) {
|
if (size != SHM_BLOCK_SIZE) {
|
||||||
newShm->Unmap();
|
newShm->Unmap();
|
||||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
if (!newShm->Map(size) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -895,27 +892,26 @@ FontList::ShmBlock* FontList::GetBlockFromParent(uint32_t aIndex) {
|
|||||||
// If we have no existing blocks, we don't want a generation check yet;
|
// If we have no existing blocks, we don't want a generation check yet;
|
||||||
// the header in the first block will define the generation of this list
|
// the header in the first block will define the generation of this list
|
||||||
uint32_t generation = aIndex == 0 ? 0 : GetGeneration();
|
uint32_t generation = aIndex == 0 ? 0 : GetGeneration();
|
||||||
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
|
base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
|
||||||
if (!dom::ContentChild::GetSingleton()->SendGetFontListShmBlock(
|
if (!dom::ContentChild::GetSingleton()->SendGetFontListShmBlock(
|
||||||
generation, aIndex, &handle)) {
|
generation, aIndex, &handle)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto newShm = MakeRefPtr<ipc::SharedMemory>();
|
auto newShm = MakeUnique<base::SharedMemory>();
|
||||||
if (!newShm->IsHandleValid(handle)) {
|
if (!newShm->IsHandleValid(handle)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!newShm->SetHandle(std::move(handle),
|
if (!newShm->SetHandle(std::move(handle), true)) {
|
||||||
ipc::SharedMemory::RightsReadOnly)) {
|
|
||||||
MOZ_CRASH("failed to set shm handle");
|
MOZ_CRASH("failed to set shm handle");
|
||||||
}
|
}
|
||||||
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
|
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
}
|
}
|
||||||
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
|
uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
|
||||||
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
|
||||||
if (size != SHM_BLOCK_SIZE) {
|
if (size != SHM_BLOCK_SIZE) {
|
||||||
newShm->Unmap();
|
newShm->Unmap();
|
||||||
if (!newShm->Map(size) || !newShm->Memory()) {
|
if (!newShm->Map(size) || !newShm->memory()) {
|
||||||
MOZ_CRASH("failed to map shared memory");
|
MOZ_CRASH("failed to map shared memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -944,8 +940,8 @@ bool FontList::UpdateShmBlocks(bool aMustLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontList::ShareBlocksToProcess(
|
void FontList::ShareBlocksToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
|
||||||
nsTArray<ipc::SharedMemory::Handle>* aBlocks, base::ProcessId aPid) {
|
base::ProcessId aPid) {
|
||||||
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
||||||
for (auto& shmem : mReadOnlyShmems) {
|
for (auto& shmem : mReadOnlyShmems) {
|
||||||
auto handle = shmem->CloneHandle();
|
auto handle = shmem->CloneHandle();
|
||||||
@@ -961,8 +957,8 @@ void FontList::ShareBlocksToProcess(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipc::SharedMemory::Handle FontList::ShareBlockToProcess(uint32_t aIndex,
|
base::SharedMemoryHandle FontList::ShareBlockToProcess(uint32_t aIndex,
|
||||||
base::ProcessId aPid) {
|
base::ProcessId aPid) {
|
||||||
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
|
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
|
||||||
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
|
||||||
MOZ_RELEASE_ASSERT(aIndex < mReadOnlyShmems.Length());
|
MOZ_RELEASE_ASSERT(aIndex < mReadOnlyShmems.Length());
|
||||||
|
|||||||
@@ -3044,7 +3044,7 @@ void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
|
|||||||
|
|
||||||
void gfxPlatformFontList::ShareFontListShmBlockToProcess(
|
void gfxPlatformFontList::ShareFontListShmBlockToProcess(
|
||||||
uint32_t aGeneration, uint32_t aIndex, base::ProcessId aPid,
|
uint32_t aGeneration, uint32_t aIndex, base::ProcessId aPid,
|
||||||
mozilla::ipc::SharedMemory::Handle* aOut) {
|
base::SharedMemoryHandle* aOut) {
|
||||||
auto list = SharedFontList();
|
auto list = SharedFontList();
|
||||||
if (!list) {
|
if (!list) {
|
||||||
return;
|
return;
|
||||||
@@ -3052,28 +3052,26 @@ void gfxPlatformFontList::ShareFontListShmBlockToProcess(
|
|||||||
if (!aGeneration || list->GetGeneration() == aGeneration) {
|
if (!aGeneration || list->GetGeneration() == aGeneration) {
|
||||||
list->ShareShmBlockToProcess(aIndex, aPid, aOut);
|
list->ShareShmBlockToProcess(aIndex, aPid, aOut);
|
||||||
} else {
|
} else {
|
||||||
*aOut = mozilla::ipc::SharedMemory::NULLHandle();
|
*aOut = base::SharedMemory::NULLHandle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxPlatformFontList::ShareFontListToProcess(
|
void gfxPlatformFontList::ShareFontListToProcess(
|
||||||
nsTArray<mozilla::ipc::SharedMemory::Handle>* aBlocks,
|
nsTArray<base::SharedMemoryHandle>* aBlocks, base::ProcessId aPid) {
|
||||||
base::ProcessId aPid) {
|
|
||||||
auto list = SharedFontList();
|
auto list = SharedFontList();
|
||||||
if (list) {
|
if (list) {
|
||||||
list->ShareBlocksToProcess(aBlocks, aPid);
|
list->ShareBlocksToProcess(aBlocks, aPid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::SharedMemory::Handle gfxPlatformFontList::ShareShmBlockToProcess(
|
base::SharedMemoryHandle gfxPlatformFontList::ShareShmBlockToProcess(
|
||||||
uint32_t aIndex, base::ProcessId aPid) {
|
uint32_t aIndex, base::ProcessId aPid) {
|
||||||
MOZ_RELEASE_ASSERT(SharedFontList());
|
MOZ_RELEASE_ASSERT(SharedFontList());
|
||||||
return SharedFontList()->ShareBlockToProcess(aIndex, aPid);
|
return SharedFontList()->ShareBlockToProcess(aIndex, aPid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxPlatformFontList::ShmBlockAdded(
|
void gfxPlatformFontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||||
uint32_t aGeneration, uint32_t aIndex,
|
base::SharedMemoryHandle aHandle) {
|
||||||
mozilla::ipc::SharedMemory::Handle aHandle) {
|
|
||||||
if (SharedFontList()) {
|
if (SharedFontList()) {
|
||||||
AutoLock lock(mLock);
|
AutoLock lock(mLock);
|
||||||
SharedFontList()->ShmBlockAdded(aGeneration, aIndex, std::move(aHandle));
|
SharedFontList()->ShmBlockAdded(aGeneration, aIndex, std::move(aHandle));
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include "gfxPlatform.h"
|
#include "gfxPlatform.h"
|
||||||
#include "SharedFontList.h"
|
#include "SharedFontList.h"
|
||||||
|
|
||||||
#include "base/process.h"
|
|
||||||
#include "nsIMemoryReporter.h"
|
#include "nsIMemoryReporter.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/EnumeratedArray.h"
|
#include "mozilla/EnumeratedArray.h"
|
||||||
@@ -27,9 +26,10 @@
|
|||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/RangedArray.h"
|
#include "mozilla/RangedArray.h"
|
||||||
#include "mozilla/RecursiveMutex.h"
|
#include "mozilla/RecursiveMutex.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsLanguageAtomService.h"
|
#include "nsLanguageAtomService.h"
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace fontlist {
|
namespace fontlist {
|
||||||
struct AliasData;
|
struct AliasData;
|
||||||
@@ -355,19 +355,18 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
|
|||||||
// be shared to the given processId.
|
// be shared to the given processId.
|
||||||
void ShareFontListShmBlockToProcess(uint32_t aGeneration, uint32_t aIndex,
|
void ShareFontListShmBlockToProcess(uint32_t aGeneration, uint32_t aIndex,
|
||||||
base::ProcessId aPid,
|
base::ProcessId aPid,
|
||||||
mozilla::ipc::SharedMemory::Handle* aOut);
|
base::SharedMemoryHandle* aOut);
|
||||||
|
|
||||||
// Populate the array aBlocks with the complete list of shmem handles ready
|
// Populate the array aBlocks with the complete list of shmem handles ready
|
||||||
// to be shared to the given processId.
|
// to be shared to the given processId.
|
||||||
void ShareFontListToProcess(
|
void ShareFontListToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
|
||||||
nsTArray<mozilla::ipc::SharedMemory::Handle>* aBlocks,
|
base::ProcessId aPid);
|
||||||
base::ProcessId aPid);
|
|
||||||
|
|
||||||
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
|
||||||
mozilla::ipc::SharedMemory::Handle aHandle);
|
base::SharedMemoryHandle aHandle);
|
||||||
|
|
||||||
mozilla::ipc::SharedMemory::Handle ShareShmBlockToProcess(
|
base::SharedMemoryHandle ShareShmBlockToProcess(uint32_t aIndex,
|
||||||
uint32_t aIndex, base::ProcessId aPid);
|
base::ProcessId aPid);
|
||||||
|
|
||||||
void SetCharacterMap(uint32_t aGeneration, uint32_t aFamilyIndex, bool aAlias,
|
void SetCharacterMap(uint32_t aGeneration, uint32_t aFamilyIndex, bool aAlias,
|
||||||
uint32_t aFaceIndex, const gfxSparseBitSet& aMap);
|
uint32_t aFaceIndex, const gfxSparseBitSet& aMap);
|
||||||
|
|||||||
@@ -330,11 +330,11 @@ void nsHyphenationManager::LoadAliases() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nsHyphenationManager::ShareHyphDictToProcess(
|
void nsHyphenationManager::ShareHyphDictToProcess(
|
||||||
nsIURI* aURI, base::ProcessId aPid,
|
nsIURI* aURI, base::ProcessId aPid, base::SharedMemoryHandle* aOutHandle,
|
||||||
mozilla::ipc::SharedMemory::Handle* aOutHandle, uint32_t* aOutSize) {
|
uint32_t* aOutSize) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
// aURI will be referring to an omnijar resource (otherwise just bail).
|
// aURI will be referring to an omnijar resource (otherwise just bail).
|
||||||
*aOutHandle = mozilla::ipc::SharedMemory::NULLHandle();
|
*aOutHandle = base::SharedMemory::NULLHandle();
|
||||||
*aOutSize = 0;
|
*aOutSize = 0;
|
||||||
|
|
||||||
// Extract the locale code from the URI, and get the corresponding
|
// Extract the locale code from the URI, and get the corresponding
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
#ifndef nsHyphenationManager_h__
|
#ifndef nsHyphenationManager_h__
|
||||||
#define nsHyphenationManager_h__
|
#define nsHyphenationManager_h__
|
||||||
|
|
||||||
#include "base/process.h"
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/Omnijar.h"
|
#include "mozilla/Omnijar.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsHashKeys.h"
|
#include "nsHashKeys.h"
|
||||||
#include "nsAtomHashKeys.h"
|
#include "nsAtomHashKeys.h"
|
||||||
#include "nsInterfaceHashtable.h"
|
#include "nsInterfaceHashtable.h"
|
||||||
@@ -28,7 +27,7 @@ class nsHyphenationManager : public nsIObserver {
|
|||||||
already_AddRefed<nsHyphenator> GetHyphenator(nsAtom* aLocale);
|
already_AddRefed<nsHyphenator> GetHyphenator(nsAtom* aLocale);
|
||||||
|
|
||||||
void ShareHyphDictToProcess(nsIURI* aURI, base::ProcessId aPid,
|
void ShareHyphDictToProcess(nsIURI* aURI, base::ProcessId aPid,
|
||||||
mozilla::ipc::SharedMemory::Handle* aOutHandle,
|
base::SharedMemoryHandle* aOutHandle,
|
||||||
uint32_t* aOutSize);
|
uint32_t* aOutSize);
|
||||||
|
|
||||||
static nsHyphenationManager* Instance();
|
static nsHyphenationManager* Instance();
|
||||||
|
|||||||
@@ -66,27 +66,27 @@ static const void* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RefPtr<ipc::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
|
static UniquePtr<base::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
|
||||||
uint32_t* aLength) {
|
uint32_t* aLength) {
|
||||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||||
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
|
base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
MOZ_ASSERT(aURI);
|
MOZ_ASSERT(aURI);
|
||||||
if (!dom::ContentChild::GetSingleton()->SendGetHyphDict(aURI, &handle,
|
if (!dom::ContentChild::GetSingleton()->SendGetHyphDict(aURI, &handle,
|
||||||
&size)) {
|
&size)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
|
UniquePtr<base::SharedMemory> shm = MakeUnique<base::SharedMemory>();
|
||||||
if (!shm->IsHandleValid(handle)) {
|
if (!shm->IsHandleValid(handle)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!shm->SetHandle(std::move(handle), ipc::SharedMemory::RightsReadOnly)) {
|
if (!shm->SetHandle(std::move(handle), true)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!shm->Map(size)) {
|
if (!shm->Map(size)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
char* addr = static_cast<char*>(shm->Memory());
|
char* addr = static_cast<char*>(shm->memory());
|
||||||
if (!addr) {
|
if (!addr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -94,21 +94,21 @@ static RefPtr<ipc::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
|
|||||||
return shm;
|
return shm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RefPtr<ipc::SharedMemory> CopyToShmem(const CompiledData* aData) {
|
static UniquePtr<base::SharedMemory> CopyToShmem(const CompiledData* aData) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
|
||||||
// The shm-related calls here are not expected to fail, but if they do,
|
// The shm-related calls here are not expected to fail, but if they do,
|
||||||
// we'll just return null (as if the resource was unavailable) and proceed
|
// we'll just return null (as if the resource was unavailable) and proceed
|
||||||
// without hyphenation.
|
// without hyphenation.
|
||||||
uint32_t size = mapped_hyph_compiled_data_size(aData);
|
uint32_t size = mapped_hyph_compiled_data_size(aData);
|
||||||
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
|
UniquePtr<base::SharedMemory> shm = MakeUnique<base::SharedMemory>();
|
||||||
if (!shm->CreateFreezable(size)) {
|
if (!shm->CreateFreezeable(size)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!shm->Map(size)) {
|
if (!shm->Map(size)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
char* buffer = static_cast<char*>(shm->Memory());
|
char* buffer = static_cast<char*>(shm->memory());
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -121,8 +121,9 @@ static RefPtr<ipc::SharedMemory> CopyToShmem(const CompiledData* aData) {
|
|||||||
return shm;
|
return shm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RefPtr<ipc::SharedMemory> LoadFromURI(nsIURI* aURI, uint32_t* aLength,
|
static UniquePtr<base::SharedMemory> LoadFromURI(nsIURI* aURI,
|
||||||
bool aPrecompiled) {
|
uint32_t* aLength,
|
||||||
|
bool aPrecompiled) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
nsCOMPtr<nsIChannel> channel;
|
nsCOMPtr<nsIChannel> channel;
|
||||||
if (NS_FAILED(NS_NewChannel(
|
if (NS_FAILED(NS_NewChannel(
|
||||||
@@ -145,14 +146,14 @@ static RefPtr<ipc::SharedMemory> LoadFromURI(nsIURI* aURI, uint32_t* aLength,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (aPrecompiled) {
|
if (aPrecompiled) {
|
||||||
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
|
UniquePtr<base::SharedMemory> shm = MakeUnique<base::SharedMemory>();
|
||||||
if (!shm->CreateFreezable(available)) {
|
if (!shm->CreateFreezeable(available)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!shm->Map(available)) {
|
if (!shm->Map(available)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
char* buffer = static_cast<char*>(shm->Memory());
|
char* buffer = static_cast<char*>(shm->memory());
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -211,7 +212,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
|||||||
// compilation once per language per session.
|
// compilation once per language per session.
|
||||||
if (!precompiled && !XRE_IsParentProcess()) {
|
if (!precompiled && !XRE_IsParentProcess()) {
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
RefPtr<ipc::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
|
UniquePtr<base::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
|
||||||
if (shm) {
|
if (shm) {
|
||||||
// We don't need to validate mDict because the parent process
|
// We don't need to validate mDict because the parent process
|
||||||
// will have done so.
|
// will have done so.
|
||||||
@@ -245,7 +246,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
|||||||
UniquePtr<const CompiledData> data(mapped_hyph_compile_buffer(
|
UniquePtr<const CompiledData> data(mapped_hyph_compile_buffer(
|
||||||
static_cast<const uint8_t*>(ptr), length, false));
|
static_cast<const uint8_t*>(ptr), length, false));
|
||||||
if (data) {
|
if (data) {
|
||||||
RefPtr<ipc::SharedMemory> shm = CopyToShmem(data.get());
|
UniquePtr<base::SharedMemory> shm = CopyToShmem(data.get());
|
||||||
if (shm) {
|
if (shm) {
|
||||||
mDictSize = mapped_hyph_compiled_data_size(data.get());
|
mDictSize = mapped_hyph_compiled_data_size(data.get());
|
||||||
mDict = AsVariant(std::move(shm));
|
mDict = AsVariant(std::move(shm));
|
||||||
@@ -259,14 +260,16 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
|||||||
// buffer; if we're a child, send a request to the parent for the
|
// buffer; if we're a child, send a request to the parent for the
|
||||||
// shared-memory copy (which it will load if not already available).
|
// shared-memory copy (which it will load if not already available).
|
||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
RefPtr<ipc::SharedMemory> shm = LoadFromURI(aURI, &length, precompiled);
|
UniquePtr<base::SharedMemory> shm =
|
||||||
|
LoadFromURI(aURI, &length, precompiled);
|
||||||
if (shm) {
|
if (shm) {
|
||||||
mDictSize = length;
|
mDictSize = length;
|
||||||
mDict = AsVariant(std::move(shm));
|
mDict = AsVariant(std::move(shm));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RefPtr<ipc::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
|
UniquePtr<base::SharedMemory> shm =
|
||||||
|
GetHyphDictFromParent(aURI, &length);
|
||||||
if (shm) {
|
if (shm) {
|
||||||
// We don't need to validate mDict because the parent process
|
// We don't need to validate mDict because the parent process
|
||||||
// will have done so.
|
// will have done so.
|
||||||
@@ -312,7 +315,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
|||||||
UniquePtr<const CompiledData> data(
|
UniquePtr<const CompiledData> data(
|
||||||
mapped_hyph_compile_file(path.get(), false));
|
mapped_hyph_compile_file(path.get(), false));
|
||||||
if (data) {
|
if (data) {
|
||||||
RefPtr<ipc::SharedMemory> shm = CopyToShmem(data.get());
|
UniquePtr<base::SharedMemory> shm = CopyToShmem(data.get());
|
||||||
if (shm) {
|
if (shm) {
|
||||||
mDictSize = mapped_hyph_compiled_data_size(data.get());
|
mDictSize = mapped_hyph_compiled_data_size(data.get());
|
||||||
mDict = AsVariant(std::move(shm));
|
mDict = AsVariant(std::move(shm));
|
||||||
@@ -334,7 +337,7 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
|
|||||||
bool nsHyphenator::IsValid() {
|
bool nsHyphenator::IsValid() {
|
||||||
return mDict.match(
|
return mDict.match(
|
||||||
[](const void*& ptr) { return ptr != nullptr; },
|
[](const void*& ptr) { return ptr != nullptr; },
|
||||||
[](RefPtr<ipc::SharedMemory>& shm) { return shm != nullptr; },
|
[](UniquePtr<base::SharedMemory>& shm) { return shm != nullptr; },
|
||||||
[](UniquePtr<const HyphDic>& hyph) { return hyph != nullptr; });
|
[](UniquePtr<const HyphDic>& hyph) { return hyph != nullptr; });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,9 +449,9 @@ void nsHyphenator::HyphenateWord(const nsAString& aString, uint32_t aStart,
|
|||||||
static_cast<const uint8_t*>(ptr), mDictSize, utf8.BeginReading(),
|
static_cast<const uint8_t*>(ptr), mDictSize, utf8.BeginReading(),
|
||||||
utf8.Length(), hyphenValues.Elements(), hyphenValues.Length());
|
utf8.Length(), hyphenValues.Elements(), hyphenValues.Length());
|
||||||
},
|
},
|
||||||
[&](RefPtr<ipc::SharedMemory>& shm) {
|
[&](UniquePtr<base::SharedMemory>& shm) {
|
||||||
return mapped_hyph_find_hyphen_values_raw(
|
return mapped_hyph_find_hyphen_values_raw(
|
||||||
static_cast<const uint8_t*>(shm->Memory()), mDictSize,
|
static_cast<const uint8_t*>(shm->memory()), mDictSize,
|
||||||
utf8.BeginReading(), utf8.Length(), hyphenValues.Elements(),
|
utf8.BeginReading(), utf8.Length(), hyphenValues.Elements(),
|
||||||
hyphenValues.Length());
|
hyphenValues.Length());
|
||||||
},
|
},
|
||||||
@@ -486,14 +489,14 @@ void nsHyphenator::HyphenateWord(const nsAString& aString, uint32_t aStart,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsHyphenator::CloneHandle(ipc::SharedMemory::Handle* aOutHandle,
|
void nsHyphenator::CloneHandle(base::SharedMemoryHandle* aOutHandle,
|
||||||
uint32_t* aOutSize) {
|
uint32_t* aOutSize) {
|
||||||
// If the resource is invalid, or if we fail to share it to the child
|
// If the resource is invalid, or if we fail to share it to the child
|
||||||
// process, we'll just bail out and continue without hyphenation; no need
|
// process, we'll just bail out and continue without hyphenation; no need
|
||||||
// for this to be a fatal error.
|
// for this to be a fatal error.
|
||||||
if (!mDict.is<RefPtr<ipc::SharedMemory>>()) {
|
if (!mDict.is<UniquePtr<base::SharedMemory>>()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*aOutHandle = mDict.as<RefPtr<ipc::SharedMemory>>()->CloneHandle();
|
*aOutHandle = mDict.as<UniquePtr<base::SharedMemory>>()->CloneHandle();
|
||||||
*aOutSize = mDictSize;
|
*aOutSize = mDictSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
#ifndef nsHyphenator_h__
|
#ifndef nsHyphenator_h__
|
||||||
#define nsHyphenator_h__
|
#define nsHyphenator_h__
|
||||||
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/Variant.h"
|
#include "mozilla/Variant.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
@@ -42,8 +41,7 @@ class nsHyphenator {
|
|||||||
|
|
||||||
nsresult Hyphenate(const nsAString& aText, nsTArray<bool>& aHyphens);
|
nsresult Hyphenate(const nsAString& aText, nsTArray<bool>& aHyphens);
|
||||||
|
|
||||||
void CloneHandle(mozilla::ipc::SharedMemory::Handle* aOutHandle,
|
void CloneHandle(base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize);
|
||||||
uint32_t* aOutSize);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~nsHyphenator() = default;
|
~nsHyphenator() = default;
|
||||||
@@ -52,8 +50,8 @@ class nsHyphenator {
|
|||||||
nsTArray<bool>& aHyphens);
|
nsTArray<bool>& aHyphens);
|
||||||
|
|
||||||
mozilla::Variant<const void*, // raw pointer to uncompressed omnijar data
|
mozilla::Variant<const void*, // raw pointer to uncompressed omnijar data
|
||||||
RefPtr<mozilla::ipc::SharedMemory>, // shmem block
|
mozilla::UniquePtr<base::SharedMemory>, // shmem block
|
||||||
mozilla::UniquePtr<const HyphDic> // loaded by mapped_hyph
|
mozilla::UniquePtr<const HyphDic> // loaded by mapped_hyph
|
||||||
>
|
>
|
||||||
mDict;
|
mDict;
|
||||||
uint32_t mDictSize; // size of mDict data (not used if type is HyphDic)
|
uint32_t mDictSize; // size of mDict data (not used if type is HyphDic)
|
||||||
|
|||||||
@@ -8,12 +8,14 @@
|
|||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class ContentParent;
|
class ContentParent;
|
||||||
}
|
}
|
||||||
|
namespace ipc {
|
||||||
|
class FileDescriptor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define Contractid and CID
|
// Define Contractid and CID
|
||||||
@@ -27,7 +29,7 @@ class ContentParent;
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
[ptr] native ContentParent(mozilla::dom::ContentParent);
|
[ptr] native ContentParent(mozilla::dom::ContentParent);
|
||||||
[ref] native SharedMemoryHandle(mozilla::ipc::SharedMemoryHandle);
|
[ref] native FileDescriptor(mozilla::ipc::FileDescriptor);
|
||||||
native MallocSizeOf(mozilla::MallocSizeOf);
|
native MallocSizeOf(mozilla::MallocSizeOf);
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(D85A17C2-AA7C-11d2-9B8C-00805F8A16D9)]
|
[scriptable, builtinclass, uuid(D85A17C2-AA7C-11d2-9B8C-00805F8A16D9)]
|
||||||
@@ -104,6 +106,6 @@ interface nsIStringBundleService : nsISupports
|
|||||||
[notxpcom, nostdcall] void sendContentBundles(in ContentParent aContentParent);
|
[notxpcom, nostdcall] void sendContentBundles(in ContentParent aContentParent);
|
||||||
|
|
||||||
[notxpcom, nostdcall] void registerContentBundle(in ACString aBundleURL,
|
[notxpcom, nostdcall] void registerContentBundle(in ACString aBundleURL,
|
||||||
[const] in SharedMemoryHandle aMapHandle,
|
[const] in FileDescriptor aMapFile,
|
||||||
in size_t aMapSize);
|
in size_t aMapSize);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -209,8 +209,7 @@ class SharedStringBundle final : public nsStringBundleBase {
|
|||||||
* called in child processes, for bundles initially created in the parent
|
* called in child processes, for bundles initially created in the parent
|
||||||
* process.
|
* process.
|
||||||
*/
|
*/
|
||||||
void SetMapFile(const mozilla::ipc::SharedMemoryHandle& aHandle,
|
void SetMapFile(const FileDescriptor& aFile, size_t aSize);
|
||||||
size_t aSize);
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(SHAREDSTRINGBUNDLE_IID)
|
NS_DECLARE_STATIC_IID_ACCESSOR(SHAREDSTRINGBUNDLE_IID)
|
||||||
@@ -223,16 +222,16 @@ class SharedStringBundle final : public nsStringBundleBase {
|
|||||||
* parent process, and may be used to send shared string bundles to child
|
* parent process, and may be used to send shared string bundles to child
|
||||||
* processes.
|
* processes.
|
||||||
*/
|
*/
|
||||||
mozilla::ipc::SharedMemoryHandle CloneHandle() const {
|
FileDescriptor CloneFileDescriptor() const {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
if (mMapHandle.isSome()) {
|
if (mMapFile.isSome()) {
|
||||||
return mozilla::ipc::SharedMemory::CloneHandle(mMapHandle.ref());
|
return mMapFile.ref();
|
||||||
}
|
}
|
||||||
return mStringMap->CloneHandle();
|
return mStringMap->CloneFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MapSize() const {
|
size_t MapSize() const {
|
||||||
if (mMapHandle.isSome()) {
|
if (mMapFile.isSome()) {
|
||||||
return mMapSize;
|
return mMapSize;
|
||||||
}
|
}
|
||||||
if (mStringMap) {
|
if (mStringMap) {
|
||||||
@@ -241,14 +240,14 @@ class SharedStringBundle final : public nsStringBundleBase {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Initialized() const { return mStringMap || mMapHandle.isSome(); }
|
bool Initialized() const { return mStringMap || mMapFile.isSome(); }
|
||||||
|
|
||||||
StringBundleDescriptor GetDescriptor() const {
|
StringBundleDescriptor GetDescriptor() const {
|
||||||
MOZ_ASSERT(Initialized());
|
MOZ_ASSERT(Initialized());
|
||||||
|
|
||||||
StringBundleDescriptor descriptor;
|
StringBundleDescriptor descriptor;
|
||||||
descriptor.bundleURL() = BundleURL();
|
descriptor.bundleURL() = BundleURL();
|
||||||
descriptor.mapHandle() = CloneHandle();
|
descriptor.mapFile() = CloneFileDescriptor();
|
||||||
descriptor.mapSize() = MapSize();
|
descriptor.mapSize() = MapSize();
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
@@ -274,7 +273,7 @@ class SharedStringBundle final : public nsStringBundleBase {
|
|||||||
private:
|
private:
|
||||||
RefPtr<SharedStringMap> mStringMap;
|
RefPtr<SharedStringMap> mStringMap;
|
||||||
|
|
||||||
Maybe<mozilla::ipc::SharedMemoryHandle> mMapHandle;
|
Maybe<FileDescriptor> mMapFile;
|
||||||
size_t mMapSize;
|
size_t mMapSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -522,9 +521,9 @@ nsresult nsStringBundle::LoadProperties() {
|
|||||||
nsresult SharedStringBundle::LoadProperties() {
|
nsresult SharedStringBundle::LoadProperties() {
|
||||||
if (mStringMap) return NS_OK;
|
if (mStringMap) return NS_OK;
|
||||||
|
|
||||||
if (mMapHandle.isSome()) {
|
if (mMapFile.isSome()) {
|
||||||
mStringMap = new SharedStringMap(mMapHandle.ref(), mMapSize);
|
mStringMap = new SharedStringMap(mMapFile.ref(), mMapSize);
|
||||||
mMapHandle.reset();
|
mMapFile.reset();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,11 +576,10 @@ nsresult SharedStringBundle::LoadProperties() {
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedStringBundle::SetMapFile(
|
void SharedStringBundle::SetMapFile(const FileDescriptor& aFile, size_t aSize) {
|
||||||
const mozilla::ipc::SharedMemoryHandle& aHandle, size_t aSize) {
|
|
||||||
MOZ_ASSERT(XRE_IsContentProcess());
|
MOZ_ASSERT(XRE_IsContentProcess());
|
||||||
mStringMap = nullptr;
|
mStringMap = nullptr;
|
||||||
mMapHandle.emplace(mozilla::ipc::SharedMemory::CloneHandle(aHandle));
|
mMapFile.emplace(aFile);
|
||||||
mMapSize = aSize;
|
mMapSize = aSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,8 +827,8 @@ void nsStringBundleService::SendContentBundles(ContentParent* aContentParent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nsStringBundleService::RegisterContentBundle(
|
void nsStringBundleService::RegisterContentBundle(
|
||||||
const nsACString& aBundleURL,
|
const nsACString& aBundleURL, const FileDescriptor& aMapFile,
|
||||||
const mozilla::ipc::SharedMemoryHandle& aMapHandle, size_t aMapSize) {
|
size_t aMapSize) {
|
||||||
RefPtr<StringBundleProxy> proxy;
|
RefPtr<StringBundleProxy> proxy;
|
||||||
|
|
||||||
bundleCacheEntry_t* cacheEntry = mBundleMap.Get(aBundleURL);
|
bundleCacheEntry_t* cacheEntry = mBundleMap.Get(aBundleURL);
|
||||||
@@ -848,7 +846,7 @@ void nsStringBundleService::RegisterContentBundle(
|
|||||||
|
|
||||||
auto bundle = MakeBundleRefPtr<SharedStringBundle>(
|
auto bundle = MakeBundleRefPtr<SharedStringBundle>(
|
||||||
PromiseFlatCString(aBundleURL).get());
|
PromiseFlatCString(aBundleURL).get());
|
||||||
bundle->SetMapFile(aMapHandle, aMapSize);
|
bundle->SetMapFile(aMapFile, aMapSize);
|
||||||
|
|
||||||
if (proxy) {
|
if (proxy) {
|
||||||
proxy->Retarget(bundle);
|
proxy->Retarget(bundle);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ if CONFIG["TARGET_KERNEL"] == "WINNT":
|
|||||||
"src/base/object_watcher.cc",
|
"src/base/object_watcher.cc",
|
||||||
"src/base/platform_thread_win.cc",
|
"src/base/platform_thread_win.cc",
|
||||||
"src/base/process_util_win.cc",
|
"src/base/process_util_win.cc",
|
||||||
|
"src/base/shared_memory_win.cc",
|
||||||
"src/base/sys_string_conversions_win.cc",
|
"src/base/sys_string_conversions_win.cc",
|
||||||
"src/base/thread_local_win.cc",
|
"src/base/thread_local_win.cc",
|
||||||
"src/base/time_win.cc",
|
"src/base/time_win.cc",
|
||||||
@@ -66,6 +67,7 @@ if CONFIG["TARGET_KERNEL"] != "WINNT":
|
|||||||
"src/base/message_pump_libevent.cc",
|
"src/base/message_pump_libevent.cc",
|
||||||
"src/base/platform_thread_posix.cc",
|
"src/base/platform_thread_posix.cc",
|
||||||
"src/base/process_util_posix.cc",
|
"src/base/process_util_posix.cc",
|
||||||
|
"src/base/shared_memory_posix.cc",
|
||||||
"src/base/string16.cc",
|
"src/base/string16.cc",
|
||||||
"src/base/thread_local_posix.cc",
|
"src/base/thread_local_posix.cc",
|
||||||
"src/base/waitable_event_posix.cc",
|
"src/base/waitable_event_posix.cc",
|
||||||
|
|||||||
197
ipc/chromium/src/base/shared_memory.h
Normal file
197
ipc/chromium/src/base/shared_memory.h
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef BASE_SHARED_MEMORY_H_
|
||||||
|
#define BASE_SHARED_MEMORY_H_
|
||||||
|
|
||||||
|
#if defined(XP_UNIX)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <semaphore.h>
|
||||||
|
#endif
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
#include "base/process.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
// SharedMemoryHandle is a platform specific type which represents
|
||||||
|
// the underlying OS handle to a shared memory segment.
|
||||||
|
typedef mozilla::UniqueFileHandle SharedMemoryHandle;
|
||||||
|
|
||||||
|
// Platform abstraction for shared memory. Provides a C++ wrapper
|
||||||
|
// around the OS primitive for a memory mapped file.
|
||||||
|
class SharedMemory {
|
||||||
|
public:
|
||||||
|
// Create a new SharedMemory object.
|
||||||
|
SharedMemory() = default;
|
||||||
|
|
||||||
|
// Create a new SharedMemory object from an existing, open
|
||||||
|
// shared memory file.
|
||||||
|
SharedMemory(SharedMemoryHandle init_handle, bool read_only)
|
||||||
|
: SharedMemory() {
|
||||||
|
SetHandle(std::move(init_handle), read_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move constructor; transfers ownership.
|
||||||
|
SharedMemory(SharedMemory&& other) = default;
|
||||||
|
|
||||||
|
// Destructor. Will close any open files.
|
||||||
|
~SharedMemory();
|
||||||
|
|
||||||
|
// Initialize a new SharedMemory object from an existing, open
|
||||||
|
// shared memory file.
|
||||||
|
bool SetHandle(SharedMemoryHandle handle, bool read_only);
|
||||||
|
|
||||||
|
// Return true iff the given handle is valid (i.e. not the distingished
|
||||||
|
// invalid value; NULL for a HANDLE and -1 for a file descriptor)
|
||||||
|
static bool IsHandleValid(const SharedMemoryHandle& handle);
|
||||||
|
|
||||||
|
// IsHandleValid applied to this object's handle.
|
||||||
|
bool IsValid() const { return static_cast<bool>(mapped_file_); }
|
||||||
|
|
||||||
|
// Return invalid handle (see comment above for exact definition).
|
||||||
|
static SharedMemoryHandle NULLHandle();
|
||||||
|
|
||||||
|
// Creates a shared memory segment.
|
||||||
|
// Returns true on success, false on failure.
|
||||||
|
bool Create(size_t size) { return CreateInternal(size, false); }
|
||||||
|
|
||||||
|
// Creates a shared memory segment that supports the Freeze()
|
||||||
|
// method; see below. (Warning: creating freezeable shared memory
|
||||||
|
// within a sandboxed process isn't possible on some platforms.)
|
||||||
|
// Returns true on success, false on failure.
|
||||||
|
bool CreateFreezeable(size_t size) { return CreateInternal(size, true); }
|
||||||
|
|
||||||
|
// Maps the shared memory into the caller's address space.
|
||||||
|
// Returns true on success, false otherwise. The memory address
|
||||||
|
// is accessed via the memory() accessor.
|
||||||
|
//
|
||||||
|
// If the specified fixed address is not null, it is the address that the
|
||||||
|
// shared memory must be mapped at. Returns false if the shared memory
|
||||||
|
// could not be mapped at that address.
|
||||||
|
bool Map(size_t bytes, void* fixed_address = nullptr);
|
||||||
|
|
||||||
|
// Unmaps the shared memory from the caller's address space.
|
||||||
|
void Unmap() { memory_ = nullptr; }
|
||||||
|
|
||||||
|
// Get the size of the opened shared memory backing file.
|
||||||
|
// Note: This size is only available to the creator of the
|
||||||
|
// shared memory, and not to those that opened shared memory
|
||||||
|
// created externally.
|
||||||
|
// Returns 0 if not opened or unknown.
|
||||||
|
size_t max_size() const { return max_size_; }
|
||||||
|
|
||||||
|
// Gets a pointer to the opened memory space if it has been
|
||||||
|
// Mapped via Map(). Returns NULL if it is not mapped.
|
||||||
|
void* memory() const { return memory_.get(); }
|
||||||
|
|
||||||
|
// Extracts the underlying file handle, returning a RAII type.
|
||||||
|
// If `unmap_view` is true, this unmaps the memory as a side-effect (and
|
||||||
|
// cleans up any OS-specific resources).
|
||||||
|
mozilla::UniqueFileHandle TakeHandle(bool unmap_view = true) {
|
||||||
|
mozilla::UniqueFileHandle handle = std::move(mapped_file_);
|
||||||
|
Close(unmap_view);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a copy of the underlying file handle, returning a RAII type.
|
||||||
|
// This operation may fail, in which case the returned file handle will be
|
||||||
|
// invalid.
|
||||||
|
mozilla::UniqueFileHandle CloneHandle();
|
||||||
|
|
||||||
|
// Make the shared memory object read-only, such that it cannot be
|
||||||
|
// written even if it's sent to an untrusted process. If it was
|
||||||
|
// mapped in this process, it will be unmapped. The object must
|
||||||
|
// have been created with CreateFreezeable(), and must not have
|
||||||
|
// already been shared to another process.
|
||||||
|
//
|
||||||
|
// (See bug 1479960 comment #0 for OS-specific implementation
|
||||||
|
// details.)
|
||||||
|
[[nodiscard]] bool Freeze() {
|
||||||
|
Unmap();
|
||||||
|
return ReadOnlyCopy(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to Freeze(), but assigns the read-only capability to
|
||||||
|
// another SharedMemory object and leaves this object's mapping in
|
||||||
|
// place and writeable. This can be used to broadcast data to
|
||||||
|
// several untrusted readers without copying.
|
||||||
|
//
|
||||||
|
// The other constraints of Freeze() still apply: this object closes
|
||||||
|
// its handle (as if by `Close(false)`), it cannot have been
|
||||||
|
// previously shared, and the read-only handle cannot be used to
|
||||||
|
// write the memory even by a malicious process.
|
||||||
|
//
|
||||||
|
// (The out parameter can currently be the same as `this` if and
|
||||||
|
// only if the memory was unmapped, but this is an implementation
|
||||||
|
// detail and shouldn't be relied on; for that use case Freeze()
|
||||||
|
// should be used instead.)
|
||||||
|
[[nodiscard]] bool ReadOnlyCopy(SharedMemory* ro_out);
|
||||||
|
|
||||||
|
// Closes the open shared memory segment.
|
||||||
|
// It is safe to call Close repeatedly.
|
||||||
|
void Close(bool unmap_view = true);
|
||||||
|
|
||||||
|
// Returns a page-aligned address at which the given number of bytes could
|
||||||
|
// probably be mapped. Returns NULL on error or if there is insufficient
|
||||||
|
// contiguous address space to map the required number of pages.
|
||||||
|
//
|
||||||
|
// Note that there is no guarantee that the given address space will actually
|
||||||
|
// be free by the time this function returns, since another thread might map
|
||||||
|
// something there in the meantime.
|
||||||
|
static void* FindFreeAddressSpace(size_t size);
|
||||||
|
|
||||||
|
#ifdef XP_UNIX
|
||||||
|
// If named POSIX shm is being used, append the prefix (including
|
||||||
|
// the leading '/') that would be used by a process with the given
|
||||||
|
// pid to the given string and return true. If not, return false.
|
||||||
|
// (This is public so that the Linux sandboxing code can use it.)
|
||||||
|
static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
|
||||||
|
// Similar, but simply returns whether POSIX shm is in use.
|
||||||
|
static bool UsingPosixShm();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CreateInternal(size_t size, bool freezeable);
|
||||||
|
|
||||||
|
// Unmapping shared memory requires the mapped size on Unix but not
|
||||||
|
// Windows; this encapsulates that difference.
|
||||||
|
struct MappingDeleter {
|
||||||
|
#ifdef XP_UNIX
|
||||||
|
// A default-constructed deleter must be used only with nullptr
|
||||||
|
// (to allow default-constructing UniqueMapping). A deleter with
|
||||||
|
// a size must be used at most once.
|
||||||
|
size_t mapped_size_ = 0;
|
||||||
|
explicit MappingDeleter(size_t size) : mapped_size_(size) {}
|
||||||
|
#endif
|
||||||
|
MappingDeleter() = default;
|
||||||
|
void operator()(void* ptr);
|
||||||
|
};
|
||||||
|
using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;
|
||||||
|
|
||||||
|
UniqueMapping memory_;
|
||||||
|
size_t max_size_ = 0;
|
||||||
|
mozilla::UniqueFileHandle mapped_file_;
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
// If true indicates this came from an external source so needs extra checks
|
||||||
|
// before being mapped.
|
||||||
|
bool external_section_ = false;
|
||||||
|
#elif !defined(ANDROID)
|
||||||
|
mozilla::UniqueFileHandle frozen_file_;
|
||||||
|
bool is_memfd_ = false;
|
||||||
|
#endif
|
||||||
|
bool read_only_ = false;
|
||||||
|
bool freezeable_ = false;
|
||||||
|
|
||||||
|
DISALLOW_EVIL_CONSTRUCTORS(SharedMemory);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
|
|
||||||
|
#endif // BASE_SHARED_MEMORY_H_
|
||||||
563
ipc/chromium/src/base/shared_memory_posix.cc
Normal file
563
ipc/chromium/src/base/shared_memory_posix.cc
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef ANDROID
|
||||||
|
# include "mozilla/Ashmem.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XP_LINUX
|
||||||
|
# include "linux_memfd_defs.h"
|
||||||
|
#endif
|
||||||
|
#ifdef MOZ_WIDGET_GTK
|
||||||
|
# include "mozilla/WidgetUtilsGtk.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
# include <sys/capsicum.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MOZ_VALGRIND
|
||||||
|
# include <valgrind/valgrind.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "base/eintr_wrapper.h"
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/string_util.h"
|
||||||
|
#include "mozilla/Atomics.h"
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
|
#include "mozilla/ProfilerThreadSleep.h"
|
||||||
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
|
#include "prenv.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
void SharedMemory::MappingDeleter::operator()(void* ptr) {
|
||||||
|
// Check that this isn't a default-constructed deleter. (`munmap`
|
||||||
|
// is specified to fail with `EINVAL` if the length is 0, so this
|
||||||
|
// assertion isn't load-bearing.)
|
||||||
|
DCHECK(mapped_size_ != 0);
|
||||||
|
munmap(ptr, mapped_size_);
|
||||||
|
// Guard against multiple calls of the same deleter, which shouldn't
|
||||||
|
// happen (but could, if `UniquePtr::reset` were used). Calling
|
||||||
|
// `munmap` with an incorrect non-zero length would be bad.
|
||||||
|
mapped_size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemory::~SharedMemory() {
|
||||||
|
// This is almost equal to the default destructor, except for the
|
||||||
|
// warning message about unfrozen freezable memory.
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) {
|
||||||
|
DCHECK(!mapped_file_);
|
||||||
|
#ifndef ANDROID
|
||||||
|
DCHECK(!frozen_file_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
freezeable_ = false;
|
||||||
|
mapped_file_ = std::move(handle);
|
||||||
|
read_only_ = read_only;
|
||||||
|
// is_memfd_ only matters for freezing, which isn't possible
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
|
||||||
|
return handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
SharedMemoryHandle SharedMemory::NULLHandle() { return nullptr; }
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool SharedMemory::UsingPosixShm() {
|
||||||
|
// Undocumented feature of AppendPosixShmPrefix to reduce code
|
||||||
|
// duplication: if the string pointer is null, it's ignored.
|
||||||
|
return AppendPosixShmPrefix(nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ANDROID
|
||||||
|
|
||||||
|
// Android has its own shared memory API, ashmem. It doesn't support
|
||||||
|
// POSIX shm_open, and the memfd support (see below) also doesn't work
|
||||||
|
// because its SELinux policy prevents the procfs operations we'd use
|
||||||
|
// (see bug 1670277 for more details).
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
|
||||||
|
read_only_ = false;
|
||||||
|
|
||||||
|
DCHECK(size > 0);
|
||||||
|
DCHECK(!mapped_file_);
|
||||||
|
|
||||||
|
int fd = mozilla::android::ashmem_create(nullptr, size);
|
||||||
|
if (fd < 0) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_file_.reset(fd);
|
||||||
|
max_size_ = size;
|
||||||
|
freezeable_ = freezeable;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||||
|
DCHECK(mapped_file_);
|
||||||
|
DCHECK(!read_only_);
|
||||||
|
CHECK(freezeable_);
|
||||||
|
|
||||||
|
if (ro_out == this) {
|
||||||
|
DCHECK(!memory_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mozilla::android::ashmem_setProt(mapped_file_.get(), PROT_READ) != 0) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "failed to set ashmem read-only: "
|
||||||
|
<< strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mozilla::UniqueFileHandle ro_file = std::move(mapped_file_);
|
||||||
|
|
||||||
|
freezeable_ = false;
|
||||||
|
ro_out->Close();
|
||||||
|
ro_out->mapped_file_ = std::move(ro_file);
|
||||||
|
ro_out->max_size_ = max_size_;
|
||||||
|
ro_out->read_only_ = true;
|
||||||
|
ro_out->freezeable_ = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // not Android
|
||||||
|
|
||||||
|
// memfd_create is a nonstandard interface for creating anonymous
|
||||||
|
// shared memory accessible as a file descriptor but not tied to any
|
||||||
|
// filesystem. It first appeared in Linux 3.17, and was adopted by
|
||||||
|
// FreeBSD in version 13.
|
||||||
|
|
||||||
|
# if !defined(HAVE_MEMFD_CREATE) && defined(XP_LINUX) && \
|
||||||
|
defined(SYS_memfd_create)
|
||||||
|
|
||||||
|
// Older libc versions (e.g., glibc before 2.27) don't have the
|
||||||
|
// wrapper, but we can supply our own; see `linux_memfd_defs.h`.
|
||||||
|
|
||||||
|
static int memfd_create(const char* name, unsigned int flags) {
|
||||||
|
return syscall(SYS_memfd_create, name, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
# define HAVE_MEMFD_CREATE 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// memfd supports having "seals" applied to the file, to prevent
|
||||||
|
// various types of changes (which apply to all fds referencing the
|
||||||
|
// file). Unfortunately, we can't rely on F_SEAL_WRITE to implement
|
||||||
|
// Freeze(); see the comments in ReadOnlyCopy() below.
|
||||||
|
//
|
||||||
|
// Instead, to prevent a child process from regaining write access to
|
||||||
|
// a read-only copy, the OS must also provide a way to remove write
|
||||||
|
// permissions at the file descriptor level. This next section
|
||||||
|
// attempts to accomplish that.
|
||||||
|
|
||||||
|
# ifdef HAVE_MEMFD_CREATE
|
||||||
|
# ifdef XP_LINUX
|
||||||
|
# define USE_MEMFD_CREATE 1
|
||||||
|
|
||||||
|
// To create a read-only duplicate of an fd, we can use procfs; the
|
||||||
|
// same operation could restore write access, but sandboxing prevents
|
||||||
|
// child processes from accessing /proc.
|
||||||
|
//
|
||||||
|
// (Note: if this ever changes to not use /proc, also reconsider how
|
||||||
|
// and if HaveMemfd should check whether this works.)
|
||||||
|
|
||||||
|
static int DupReadOnly(int fd) {
|
||||||
|
std::string path = StringPrintf("/proc/self/fd/%d", fd);
|
||||||
|
// procfs opens probably won't EINTR, but checking for it can't hurt
|
||||||
|
return HANDLE_EINTR(open(path.c_str(), O_RDONLY | O_CLOEXEC));
|
||||||
|
}
|
||||||
|
|
||||||
|
# elif defined(__FreeBSD__)
|
||||||
|
# define USE_MEMFD_CREATE 1
|
||||||
|
|
||||||
|
// FreeBSD's Capsicum framework allows irrevocably restricting the
|
||||||
|
// operations permitted on a file descriptor.
|
||||||
|
|
||||||
|
static int DupReadOnly(int fd) {
|
||||||
|
int rofd = dup(fd);
|
||||||
|
if (rofd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cap_rights_t rights;
|
||||||
|
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R);
|
||||||
|
if (cap_rights_limit(rofd, &rights) < 0) {
|
||||||
|
int err = errno;
|
||||||
|
close(rofd);
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rofd;
|
||||||
|
}
|
||||||
|
|
||||||
|
# else // unhandled OS
|
||||||
|
# warning "OS has memfd_create but no DupReadOnly implementation"
|
||||||
|
# endif // OS selection
|
||||||
|
# endif // HAVE_MEMFD_CREATE
|
||||||
|
|
||||||
|
// Runtime detection for memfd support.
|
||||||
|
static bool HaveMemfd() {
|
||||||
|
# ifdef USE_MEMFD_CREATE
|
||||||
|
static const bool kHave = [] {
|
||||||
|
mozilla::UniqueFileHandle fd(
|
||||||
|
memfd_create("mozilla-ipc-test", MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
||||||
|
if (!fd) {
|
||||||
|
DCHECK_EQ(errno, ENOSYS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that DupReadOnly works; on Linux it's known to fail if:
|
||||||
|
//
|
||||||
|
// * SELinux assigns the memfd a type for which this process's
|
||||||
|
// domain doesn't have "open" permission; this is always the
|
||||||
|
// case on Android but could occur on desktop as well
|
||||||
|
//
|
||||||
|
// * /proc (used by the DupReadOnly implementation) isn't mounted,
|
||||||
|
// which is a configuration that the Tor Browser project is
|
||||||
|
// interested in as a way to reduce fingerprinting risk
|
||||||
|
//
|
||||||
|
// Sandboxed processes on Linux also can't use it if sandboxing
|
||||||
|
// has already been started, but that's expected. It should be
|
||||||
|
// safe for sandboxed child processes to use memfd even if an
|
||||||
|
// unsandboxed process couldn't freeze them, because freezing
|
||||||
|
// isn't allowed (or meaningful) for memory created by another
|
||||||
|
// process.
|
||||||
|
|
||||||
|
if (!PR_GetEnv("MOZ_SANDBOXED")) {
|
||||||
|
mozilla::UniqueFileHandle rofd(DupReadOnly(fd.get()));
|
||||||
|
if (!rofd) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "read-only dup failed (" << strerror(errno)
|
||||||
|
<< "); not using memfd";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
return kHave;
|
||||||
|
# else
|
||||||
|
return false;
|
||||||
|
# endif // USE_MEMFD_CREATE
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
||||||
|
if (HaveMemfd()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// See also UsingPosixShm().
|
||||||
|
if (!str) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*str += '/';
|
||||||
|
# ifdef MOZ_WIDGET_GTK
|
||||||
|
// The Snap package environment doesn't provide a private /dev/shm
|
||||||
|
// (it's used for communication with services like PulseAudio);
|
||||||
|
// instead AppArmor is used to restrict access to it. Anything with
|
||||||
|
// this prefix is allowed:
|
||||||
|
if (const char* snap = mozilla::widget::GetSnapInstanceName()) {
|
||||||
|
StringAppendF(str, "snap.%s.", snap);
|
||||||
|
}
|
||||||
|
# endif // XP_LINUX
|
||||||
|
// Hopefully the "implementation defined" name length limit is long
|
||||||
|
// enough for this.
|
||||||
|
StringAppendF(str, "org.mozilla.ipc.%d.", static_cast<int>(pid));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
|
||||||
|
read_only_ = false;
|
||||||
|
|
||||||
|
DCHECK(size > 0);
|
||||||
|
DCHECK(!mapped_file_);
|
||||||
|
DCHECK(!frozen_file_);
|
||||||
|
|
||||||
|
mozilla::UniqueFileHandle fd;
|
||||||
|
mozilla::UniqueFileHandle frozen_fd;
|
||||||
|
bool is_memfd = false;
|
||||||
|
|
||||||
|
# ifdef USE_MEMFD_CREATE
|
||||||
|
if (HaveMemfd()) {
|
||||||
|
const unsigned flags = MFD_CLOEXEC | (freezeable ? MFD_ALLOW_SEALING : 0);
|
||||||
|
fd.reset(memfd_create("mozilla-ipc", flags));
|
||||||
|
if (!fd) {
|
||||||
|
// In general it's too late to fall back here -- in a sandboxed
|
||||||
|
// child process, shm_open is already blocked. And it shouldn't
|
||||||
|
// be necessary.
|
||||||
|
CHROMIUM_LOG(WARNING) << "failed to create memfd: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
is_memfd = true;
|
||||||
|
if (freezeable) {
|
||||||
|
frozen_fd.reset(DupReadOnly(fd.get()));
|
||||||
|
if (!frozen_fd) {
|
||||||
|
CHROMIUM_LOG(WARNING)
|
||||||
|
<< "failed to create read-only memfd: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (!fd) {
|
||||||
|
// Generic Unix: shm_open + shm_unlink
|
||||||
|
do {
|
||||||
|
// The names don't need to be unique, but it saves time if they
|
||||||
|
// usually are.
|
||||||
|
static mozilla::Atomic<size_t> sNameCounter;
|
||||||
|
std::string name;
|
||||||
|
CHECK(AppendPosixShmPrefix(&name, getpid()));
|
||||||
|
StringAppendF(&name, "%zu", sNameCounter++);
|
||||||
|
// O_EXCL means the names being predictable shouldn't be a problem.
|
||||||
|
fd.reset(HANDLE_EINTR(
|
||||||
|
shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)));
|
||||||
|
if (fd) {
|
||||||
|
if (freezeable) {
|
||||||
|
frozen_fd.reset(HANDLE_EINTR(shm_open(name.c_str(), O_RDONLY, 0400)));
|
||||||
|
if (!frozen_fd) {
|
||||||
|
int open_err = errno;
|
||||||
|
shm_unlink(name.c_str());
|
||||||
|
DLOG(FATAL) << "failed to re-open freezeable shm: "
|
||||||
|
<< strerror(open_err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shm_unlink(name.c_str()) != 0) {
|
||||||
|
// This shouldn't happen, but if it does: assume the file is
|
||||||
|
// in fact leaked, and bail out now while it's still 0-length.
|
||||||
|
DLOG(FATAL) << "failed to unlink shm: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!fd && errno == EEXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fd) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mozilla::Maybe<int> fallocateError;
|
||||||
|
# if defined(HAVE_POSIX_FALLOCATE)
|
||||||
|
// Using posix_fallocate will ensure that there's actually space for this
|
||||||
|
// file. Otherwise we end up with a sparse file that can give SIGBUS if we
|
||||||
|
// run out of space while writing to it. (This doesn't apply to memfd.)
|
||||||
|
if (!is_memfd) {
|
||||||
|
int rv;
|
||||||
|
// Avoid repeated interruptions of posix_fallocate by the profiler's
|
||||||
|
// SIGPROF sampling signal. Indicating "thread sleep" here means we'll
|
||||||
|
// get up to one interruption but not more. See bug 1658847 for more.
|
||||||
|
// This has to be scoped outside the HANDLE_RV_EINTR retry loop.
|
||||||
|
{
|
||||||
|
AUTO_PROFILER_THREAD_SLEEP;
|
||||||
|
|
||||||
|
rv = HANDLE_RV_EINTR(
|
||||||
|
posix_fallocate(fd.get(), 0, static_cast<off_t>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some filesystems have trouble with posix_fallocate. For now, we must
|
||||||
|
// fallback ftruncate and accept the allocation failures like we do
|
||||||
|
// without posix_fallocate.
|
||||||
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1618914
|
||||||
|
if (rv != 0 && rv != EOPNOTSUPP && rv != EINVAL && rv != ENODEV) {
|
||||||
|
CHROMIUM_LOG(WARNING)
|
||||||
|
<< "fallocate failed to set shm size: " << strerror(rv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fallocateError = mozilla::Some(rv);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// If posix_fallocate isn't supported / relevant for this type of
|
||||||
|
// file (either failed with an expected error, or wasn't attempted),
|
||||||
|
// then set the size with ftruncate:
|
||||||
|
if (fallocateError != mozilla::Some(0)) {
|
||||||
|
int rv = HANDLE_EINTR(ftruncate(fd.get(), static_cast<off_t>(size)));
|
||||||
|
if (rv != 0) {
|
||||||
|
int ftruncate_errno = errno;
|
||||||
|
if (fallocateError) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "fallocate failed to set shm size: "
|
||||||
|
<< strerror(*fallocateError);
|
||||||
|
}
|
||||||
|
CHROMIUM_LOG(WARNING)
|
||||||
|
<< "ftruncate failed to set shm size: " << strerror(ftruncate_errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_file_ = std::move(fd);
|
||||||
|
frozen_file_ = std::move(frozen_fd);
|
||||||
|
max_size_ = size;
|
||||||
|
freezeable_ = freezeable;
|
||||||
|
is_memfd_ = is_memfd;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||||
|
DCHECK(mapped_file_);
|
||||||
|
DCHECK(!read_only_);
|
||||||
|
CHECK(freezeable_);
|
||||||
|
|
||||||
|
if (ro_out == this) {
|
||||||
|
DCHECK(!memory_);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef USE_MEMFD_CREATE
|
||||||
|
# ifdef MOZ_VALGRIND
|
||||||
|
// Valgrind allows memfd_create but doesn't understand F_ADD_SEALS.
|
||||||
|
static const bool haveSeals = RUNNING_ON_VALGRIND == 0;
|
||||||
|
# else
|
||||||
|
static const bool haveSeals = true;
|
||||||
|
# endif
|
||||||
|
static const bool useSeals = !PR_GetEnv("MOZ_SHM_NO_SEALS");
|
||||||
|
if (is_memfd_ && haveSeals && useSeals) {
|
||||||
|
// Seals are added to the file as defense-in-depth. The primary
|
||||||
|
// method of access control is creating a read-only fd (using
|
||||||
|
// procfs in this case) and requiring that sandboxes processes not
|
||||||
|
// have access to /proc/self/fd to regain write permission; this
|
||||||
|
// is the same as with shm_open.
|
||||||
|
//
|
||||||
|
// Unfortunately, F_SEAL_WRITE is unreliable: if the process
|
||||||
|
// forked while there was a writeable mapping, it will inherit a
|
||||||
|
// copy of the mapping, which causes the seal to fail.
|
||||||
|
//
|
||||||
|
// (Also, in the future we may want to split this into separate
|
||||||
|
// classes for mappings and shared memory handles, which would
|
||||||
|
// complicate identifying the case where `F_SEAL_WRITE` would be
|
||||||
|
// possible even in the absence of races with fork.)
|
||||||
|
//
|
||||||
|
// However, Linux 5.1 added F_SEAL_FUTURE_WRITE, which prevents
|
||||||
|
// write operations afterwards, but existing writeable mappings
|
||||||
|
// are unaffected (similar to ashmem protection semantics).
|
||||||
|
|
||||||
|
const int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
|
||||||
|
int sealError = EINVAL;
|
||||||
|
|
||||||
|
# ifdef F_SEAL_FUTURE_WRITE
|
||||||
|
sealError =
|
||||||
|
fcntl(mapped_file_.get(), F_ADD_SEALS, seals | F_SEAL_FUTURE_WRITE) == 0
|
||||||
|
? 0
|
||||||
|
: errno;
|
||||||
|
# endif // F_SEAL_FUTURE_WRITE
|
||||||
|
if (sealError == EINVAL) {
|
||||||
|
sealError =
|
||||||
|
fcntl(mapped_file_.get(), F_ADD_SEALS, seals) == 0 ? 0 : errno;
|
||||||
|
}
|
||||||
|
if (sealError != 0) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "failed to seal memfd: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# else // !USE_MEMFD_CREATE
|
||||||
|
DCHECK(!is_memfd_);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
DCHECK(frozen_file_);
|
||||||
|
DCHECK(mapped_file_);
|
||||||
|
mapped_file_ = nullptr;
|
||||||
|
mozilla::UniqueFileHandle ro_file = std::move(frozen_file_);
|
||||||
|
|
||||||
|
DCHECK(ro_file);
|
||||||
|
freezeable_ = false;
|
||||||
|
ro_out->Close();
|
||||||
|
ro_out->mapped_file_ = std::move(ro_file);
|
||||||
|
ro_out->max_size_ = max_size_;
|
||||||
|
ro_out->read_only_ = true;
|
||||||
|
ro_out->freezeable_ = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // not Android
|
||||||
|
|
||||||
|
#ifndef MAP_NORESERVE
|
||||||
|
# define MAP_NORESERVE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
|
||||||
|
if (!mapped_file_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DCHECK(!memory_);
|
||||||
|
|
||||||
|
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
||||||
|
// replace pages that are alread mapped at that address.
|
||||||
|
void* mem =
|
||||||
|
mmap(fixed_address, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
|
||||||
|
MAP_SHARED, mapped_file_.get(), 0);
|
||||||
|
|
||||||
|
if (mem == MAP_FAILED) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixed_address && mem != fixed_address) {
|
||||||
|
bool munmap_succeeded = munmap(mem, bytes) == 0;
|
||||||
|
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_ = UniqueMapping(mem, MappingDeleter(bytes));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||||
|
void* memory = mmap(nullptr, size, PROT_NONE,
|
||||||
|
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
||||||
|
if (memory == MAP_FAILED) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
munmap(memory, size);
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryHandle SharedMemory::CloneHandle() {
|
||||||
|
freezeable_ = false;
|
||||||
|
const int new_fd = dup(mapped_file_.get());
|
||||||
|
if (new_fd < 0) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
|
||||||
|
<< strerror(errno);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return mozilla::UniqueFileHandle(new_fd);
|
||||||
|
}
|
||||||
|
void SharedMemory::Close(bool unmap_view) {
|
||||||
|
if (unmap_view) {
|
||||||
|
Unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_file_ = nullptr;
|
||||||
|
#ifndef ANDROID
|
||||||
|
if (frozen_file_) {
|
||||||
|
CHROMIUM_LOG(WARNING) << "freezeable shared memory was never frozen";
|
||||||
|
frozen_file_ = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
266
ipc/chromium/src/base/shared_memory_win.cc
Normal file
266
ipc/chromium/src/base/shared_memory_win.cc
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/win_util.h"
|
||||||
|
#include "base/string_util.h"
|
||||||
|
#include "mozilla/ipc/ProtocolUtils.h"
|
||||||
|
#include "mozilla/RandomNum.h"
|
||||||
|
#include "nsDebug.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
#ifdef MOZ_MEMORY
|
||||||
|
# include "mozmemory_utils.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// NtQuerySection is an internal (but believed to be stable) API and the
|
||||||
|
// structures it uses are defined in nt_internals.h.
|
||||||
|
// So we have to define them ourselves.
|
||||||
|
typedef enum _SECTION_INFORMATION_CLASS {
|
||||||
|
SectionBasicInformation,
|
||||||
|
} SECTION_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
typedef struct _SECTION_BASIC_INFORMATION {
|
||||||
|
PVOID BaseAddress;
|
||||||
|
ULONG Attributes;
|
||||||
|
LARGE_INTEGER Size;
|
||||||
|
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
||||||
|
|
||||||
|
typedef ULONG(__stdcall* NtQuerySectionType)(
|
||||||
|
HANDLE SectionHandle, SECTION_INFORMATION_CLASS SectionInformationClass,
|
||||||
|
PVOID SectionInformation, ULONG SectionInformationLength,
|
||||||
|
PULONG ResultLength);
|
||||||
|
|
||||||
|
// Checks if the section object is safe to map. At the moment this just means
|
||||||
|
// it's not an image section.
|
||||||
|
bool IsSectionSafeToMap(HANDLE handle) {
|
||||||
|
static NtQuerySectionType nt_query_section_func =
|
||||||
|
reinterpret_cast<NtQuerySectionType>(
|
||||||
|
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
|
||||||
|
DCHECK(nt_query_section_func);
|
||||||
|
|
||||||
|
// The handle must have SECTION_QUERY access for this to succeed.
|
||||||
|
SECTION_BASIC_INFORMATION basic_information = {};
|
||||||
|
ULONG status =
|
||||||
|
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
|
||||||
|
sizeof(basic_information), nullptr);
|
||||||
|
if (status) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
void SharedMemory::MappingDeleter::operator()(void* ptr) {
|
||||||
|
UnmapViewOfFile(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemory::~SharedMemory() = default;
|
||||||
|
|
||||||
|
bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) {
|
||||||
|
DCHECK(!mapped_file_);
|
||||||
|
|
||||||
|
external_section_ = true;
|
||||||
|
freezeable_ = false; // just in case
|
||||||
|
mapped_file_ = std::move(handle);
|
||||||
|
read_only_ = read_only;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
|
||||||
|
return handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
SharedMemoryHandle SharedMemory::NULLHandle() { return nullptr; }
|
||||||
|
|
||||||
|
// Wrapper around CreateFileMappingW for pagefile-backed regions. When out of
|
||||||
|
// memory, may attempt to stall and retry rather than returning immediately, in
|
||||||
|
// hopes that the page file is about to be expanded by Windows. (bug 1822383,
|
||||||
|
// bug 1716727)
|
||||||
|
//
|
||||||
|
// This method is largely a copy of the MozVirtualAlloc method from
|
||||||
|
// mozjemalloc.cpp, which implements this strategy for VirtualAlloc calls,
|
||||||
|
// except re-purposed to handle CreateFileMapping.
|
||||||
|
static HANDLE MozCreateFileMappingW(
|
||||||
|
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
|
||||||
|
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) {
|
||||||
|
#ifdef MOZ_MEMORY
|
||||||
|
constexpr auto IsOOMError = [] {
|
||||||
|
return ::GetLastError() == ERROR_COMMITMENT_LIMIT;
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
HANDLE handle = ::CreateFileMappingW(
|
||||||
|
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
||||||
|
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
||||||
|
if (MOZ_LIKELY(handle)) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
||||||
|
"::CreateFileMapping should return NULL, not "
|
||||||
|
"INVALID_HANDLE_VALUE, on failure");
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't do anything for errors other than OOM.
|
||||||
|
if (!IsOOMError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry as many times as desired (possibly zero).
|
||||||
|
const mozilla::StallSpecs stallSpecs = mozilla::GetAllocatorStallSpecs();
|
||||||
|
|
||||||
|
const auto ret =
|
||||||
|
stallSpecs.StallAndRetry(&::Sleep, [&]() -> std::optional<HANDLE> {
|
||||||
|
HANDLE handle = ::CreateFileMappingW(
|
||||||
|
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
||||||
|
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
||||||
|
|
||||||
|
if (handle) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
||||||
|
"::CreateFileMapping should return NULL, not "
|
||||||
|
"INVALID_HANDLE_VALUE, on failure");
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failure for some reason other than OOM.
|
||||||
|
if (!IsOOMError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret.value_or(nullptr);
|
||||||
|
#else
|
||||||
|
return ::CreateFileMappingW(INVALID_HANDLE_VALUE, lpFileMappingAttributes,
|
||||||
|
flProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
|
||||||
|
lpName);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
|
||||||
|
DCHECK(!mapped_file_);
|
||||||
|
read_only_ = false;
|
||||||
|
|
||||||
|
// If the shared memory object has no DACL, any process can
|
||||||
|
// duplicate its handles with any access rights; e.g., re-add write
|
||||||
|
// access to a read-only handle. To prevent that, we give it an
|
||||||
|
// empty DACL, so that no process can do that.
|
||||||
|
SECURITY_ATTRIBUTES sa, *psa = nullptr;
|
||||||
|
SECURITY_DESCRIPTOR sd;
|
||||||
|
ACL dacl;
|
||||||
|
|
||||||
|
if (freezeable) {
|
||||||
|
psa = &sa;
|
||||||
|
sa.nLength = sizeof(sa);
|
||||||
|
sa.lpSecurityDescriptor = &sd;
|
||||||
|
sa.bInheritHandle = FALSE;
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) ||
|
||||||
|
NS_WARN_IF(
|
||||||
|
!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ||
|
||||||
|
NS_WARN_IF(!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_file_.reset(MozCreateFileMappingW(psa, PAGE_READWRITE, 0,
|
||||||
|
static_cast<DWORD>(size), nullptr));
|
||||||
|
if (!mapped_file_) return false;
|
||||||
|
|
||||||
|
max_size_ = size;
|
||||||
|
freezeable_ = freezeable;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
||||||
|
DCHECK(!read_only_);
|
||||||
|
CHECK(freezeable_);
|
||||||
|
|
||||||
|
if (ro_out == this) {
|
||||||
|
DCHECK(!memory_);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE ro_handle;
|
||||||
|
if (!::DuplicateHandle(GetCurrentProcess(), mapped_file_.release(),
|
||||||
|
GetCurrentProcess(), &ro_handle,
|
||||||
|
GENERIC_READ | FILE_MAP_READ, false,
|
||||||
|
DUPLICATE_CLOSE_SOURCE)) {
|
||||||
|
// DUPLICATE_CLOSE_SOURCE applies even if there is an error.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
freezeable_ = false;
|
||||||
|
|
||||||
|
ro_out->Close();
|
||||||
|
ro_out->mapped_file_.reset(ro_handle);
|
||||||
|
ro_out->max_size_ = max_size_;
|
||||||
|
ro_out->read_only_ = true;
|
||||||
|
ro_out->freezeable_ = false;
|
||||||
|
ro_out->external_section_ = external_section_;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
|
||||||
|
if (!mapped_file_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (external_section_ && !IsSectionSafeToMap(mapped_file_.get())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mem = MapViewOfFileEx(
|
||||||
|
mapped_file_.get(),
|
||||||
|
read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, bytes,
|
||||||
|
fixed_address);
|
||||||
|
if (mem) {
|
||||||
|
MOZ_ASSERT(!fixed_address || mem == fixed_address,
|
||||||
|
"MapViewOfFileEx returned an expected address");
|
||||||
|
memory_.reset(mem);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||||
|
void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||||
|
if (memory) {
|
||||||
|
VirtualFree(memory, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryHandle SharedMemory::CloneHandle() {
|
||||||
|
freezeable_ = false;
|
||||||
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
|
if (DuplicateHandle(GetCurrentProcess(), mapped_file_.get(),
|
||||||
|
GetCurrentProcess(), &handle, 0, false,
|
||||||
|
DUPLICATE_SAME_ACCESS)) {
|
||||||
|
return SharedMemoryHandle(handle);
|
||||||
|
}
|
||||||
|
NS_WARNING("DuplicateHandle Failed!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMemory::Close(bool unmap_view) {
|
||||||
|
if (unmap_view) {
|
||||||
|
Unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_file_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "mozilla/ipc/BigBuffer.h"
|
#include "mozilla/ipc/BigBuffer.h"
|
||||||
|
|
||||||
#include "chrome/common/ipc_message_utils.h"
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "mozilla/ipc/SharedMemory.h"
|
||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ void IdleSchedulerChild::Init(IdlePeriodState* aIdlePeriodState) {
|
|||||||
auto resolve =
|
auto resolve =
|
||||||
[&](std::tuple<mozilla::Maybe<SharedMemoryHandle>, uint32_t>&& aResult) {
|
[&](std::tuple<mozilla::Maybe<SharedMemoryHandle>, uint32_t>&& aResult) {
|
||||||
if (std::get<0>(aResult)) {
|
if (std::get<0>(aResult)) {
|
||||||
mActiveCounter->SetHandle(std::move(*std::get<0>(aResult)),
|
mActiveCounter.SetHandle(std::move(*std::get<0>(aResult)), false);
|
||||||
SharedMemory::RightsReadWrite);
|
mActiveCounter.Map(sizeof(int32_t));
|
||||||
mActiveCounter->Map(sizeof(int32_t));
|
|
||||||
mChildId = std::get<1>(aResult);
|
mChildId = std::get<1>(aResult);
|
||||||
if (mChildId && mIdlePeriodState && mIdlePeriodState->IsActive()) {
|
if (mChildId && mIdlePeriodState && mIdlePeriodState->IsActive()) {
|
||||||
SetActive();
|
SetActive();
|
||||||
@@ -54,23 +53,23 @@ IPCResult IdleSchedulerChild::RecvIdleTime(uint64_t aId, TimeDuration aBudget) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IdleSchedulerChild::SetActive() {
|
void IdleSchedulerChild::SetActive() {
|
||||||
if (mChildId && CanSend() && mActiveCounter->Memory()) {
|
if (mChildId && CanSend() && mActiveCounter.memory()) {
|
||||||
++(static_cast<Atomic<int32_t>*>(
|
++(static_cast<Atomic<int32_t>*>(
|
||||||
mActiveCounter->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
mActiveCounter.memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
||||||
++(static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())[mChildId]);
|
++(static_cast<Atomic<int32_t>*>(mActiveCounter.memory())[mChildId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IdleSchedulerChild::SetPaused() {
|
bool IdleSchedulerChild::SetPaused() {
|
||||||
if (mChildId && CanSend() && mActiveCounter->Memory()) {
|
if (mChildId && CanSend() && mActiveCounter.memory()) {
|
||||||
--(static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())[mChildId]);
|
--(static_cast<Atomic<int32_t>*>(mActiveCounter.memory())[mChildId]);
|
||||||
// The following expression reduces the global activity count and checks if
|
// The following expression reduces the global activity count and checks if
|
||||||
// it drops below the cpu counter limit.
|
// it drops below the cpu counter limit.
|
||||||
return (static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())
|
return (static_cast<Atomic<int32_t>*>(
|
||||||
[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER])-- ==
|
|
||||||
static_cast<Atomic<int32_t>*>(
|
|
||||||
mActiveCounter
|
mActiveCounter
|
||||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
|
.memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER])-- ==
|
||||||
|
static_cast<Atomic<int32_t>*>(
|
||||||
|
mActiveCounter.memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -9,9 +9,7 @@
|
|||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/ipc/PIdleSchedulerChild.h"
|
#include "mozilla/ipc/PIdleSchedulerChild.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
class nsIIdlePeriod;
|
class nsIIdlePeriod;
|
||||||
|
|
||||||
@@ -58,7 +56,7 @@ class IdleSchedulerChild final : public PIdleSchedulerChild {
|
|||||||
friend class BackgroundChildImpl;
|
friend class BackgroundChildImpl;
|
||||||
|
|
||||||
// See IdleScheduleParent::sActiveChildCounter
|
// See IdleScheduleParent::sActiveChildCounter
|
||||||
RefPtr<SharedMemory> mActiveCounter = MakeRefPtr<SharedMemory>();
|
base::SharedMemory mActiveCounter;
|
||||||
|
|
||||||
IdlePeriodState* mIdlePeriodState = nullptr;
|
IdlePeriodState* mIdlePeriodState = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
namespace mozilla::ipc {
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
RefPtr<SharedMemory> IdleSchedulerParent::sActiveChildCounter = nullptr;
|
base::SharedMemory* IdleSchedulerParent::sActiveChildCounter = nullptr;
|
||||||
std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT>
|
std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT>
|
||||||
IdleSchedulerParent::sInUseChildCounters;
|
IdleSchedulerParent::sInUseChildCounters;
|
||||||
LinkedList<IdleSchedulerParent> IdleSchedulerParent::sIdleAndGCRequests;
|
LinkedList<IdleSchedulerParent> IdleSchedulerParent::sIdleAndGCRequests;
|
||||||
@@ -107,9 +107,9 @@ void IdleSchedulerParent::CalculateNumIdleTasks() {
|
|||||||
std::min(std::max(sNumCPUs / sPrefConcurrentGCsCPUDivisor, 1u),
|
std::min(std::max(sNumCPUs / sPrefConcurrentGCsCPUDivisor, 1u),
|
||||||
sPrefConcurrentGCsMax);
|
sPrefConcurrentGCsMax);
|
||||||
|
|
||||||
if (sActiveChildCounter && sActiveChildCounter->Memory()) {
|
if (sActiveChildCounter && sActiveChildCounter->memory()) {
|
||||||
static_cast<Atomic<int32_t>*>(
|
static_cast<Atomic<int32_t>*>(
|
||||||
sActiveChildCounter->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
sActiveChildCounter->memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
||||||
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
|
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
|
||||||
}
|
}
|
||||||
IdleSchedulerParent::Schedule(nullptr);
|
IdleSchedulerParent::Schedule(nullptr);
|
||||||
@@ -120,13 +120,13 @@ IdleSchedulerParent::~IdleSchedulerParent() {
|
|||||||
// that is the case.
|
// that is the case.
|
||||||
if (mChildId) {
|
if (mChildId) {
|
||||||
sInUseChildCounters[mChildId] = false;
|
sInUseChildCounters[mChildId] = false;
|
||||||
if (sActiveChildCounter && sActiveChildCounter->Memory() &&
|
if (sActiveChildCounter && sActiveChildCounter->memory() &&
|
||||||
static_cast<Atomic<int32_t>*>(
|
static_cast<Atomic<int32_t>*>(
|
||||||
sActiveChildCounter->Memory())[mChildId]) {
|
sActiveChildCounter->memory())[mChildId]) {
|
||||||
--static_cast<Atomic<int32_t>*>(
|
--static_cast<Atomic<int32_t>*>(
|
||||||
sActiveChildCounter
|
sActiveChildCounter
|
||||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
|
->memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
|
||||||
static_cast<Atomic<int32_t>*>(sActiveChildCounter->Memory())[mChildId] =
|
static_cast<Atomic<int32_t>*>(sActiveChildCounter->memory())[mChildId] =
|
||||||
0;
|
0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,6 +154,7 @@ IdleSchedulerParent::~IdleSchedulerParent() {
|
|||||||
sChildProcessesAlive--;
|
sChildProcessesAlive--;
|
||||||
if (sChildProcessesAlive == 0) {
|
if (sChildProcessesAlive == 0) {
|
||||||
MOZ_ASSERT(sIdleAndGCRequests.isEmpty());
|
MOZ_ASSERT(sIdleAndGCRequests.isEmpty());
|
||||||
|
delete sActiveChildCounter;
|
||||||
sActiveChildCounter = nullptr;
|
sActiveChildCounter = nullptr;
|
||||||
|
|
||||||
if (sStarvationPreventer) {
|
if (sStarvationPreventer) {
|
||||||
@@ -177,23 +178,24 @@ IPCResult IdleSchedulerParent::RecvInitForIdleUse(
|
|||||||
// Create a shared memory object which is shared across all the relevant
|
// Create a shared memory object which is shared across all the relevant
|
||||||
// processes.
|
// processes.
|
||||||
if (!sActiveChildCounter) {
|
if (!sActiveChildCounter) {
|
||||||
sActiveChildCounter = MakeRefPtr<SharedMemory>();
|
sActiveChildCounter = new base::SharedMemory();
|
||||||
size_t shmemSize = NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT * sizeof(int32_t);
|
size_t shmemSize = NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT * sizeof(int32_t);
|
||||||
if (sActiveChildCounter->Create(shmemSize) &&
|
if (sActiveChildCounter->Create(shmemSize) &&
|
||||||
sActiveChildCounter->Map(shmemSize)) {
|
sActiveChildCounter->Map(shmemSize)) {
|
||||||
memset(sActiveChildCounter->Memory(), 0, shmemSize);
|
memset(sActiveChildCounter->memory(), 0, shmemSize);
|
||||||
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER] = true;
|
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER] = true;
|
||||||
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] = true;
|
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] = true;
|
||||||
static_cast<Atomic<int32_t>*>(
|
static_cast<Atomic<int32_t>*>(
|
||||||
sActiveChildCounter
|
sActiveChildCounter
|
||||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
->memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
|
||||||
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
|
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
|
||||||
} else {
|
} else {
|
||||||
|
delete sActiveChildCounter;
|
||||||
sActiveChildCounter = nullptr;
|
sActiveChildCounter = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Maybe<SharedMemory::Handle> activeCounter;
|
Maybe<SharedMemoryHandle> activeCounter;
|
||||||
if (SharedMemory::Handle handle =
|
if (SharedMemoryHandle handle =
|
||||||
sActiveChildCounter ? sActiveChildCounter->CloneHandle() : nullptr) {
|
sActiveChildCounter ? sActiveChildCounter->CloneHandle() : nullptr) {
|
||||||
activeCounter.emplace(std::move(handle));
|
activeCounter.emplace(std::move(handle));
|
||||||
}
|
}
|
||||||
@@ -210,7 +212,7 @@ IPCResult IdleSchedulerParent::RecvInitForIdleUse(
|
|||||||
// If there wasn't an empty item, we'll fallback to 0.
|
// If there wasn't an empty item, we'll fallback to 0.
|
||||||
mChildId = unusedId;
|
mChildId = unusedId;
|
||||||
|
|
||||||
aResolve(std::tuple<mozilla::Maybe<SharedMemory::Handle>&&, const uint32_t&>(
|
aResolve(std::tuple<mozilla::Maybe<SharedMemoryHandle>&&, const uint32_t&>(
|
||||||
std::move(activeCounter), mChildId));
|
std::move(activeCounter), mChildId));
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
@@ -320,7 +322,7 @@ int32_t IdleSchedulerParent::ActiveCount() {
|
|||||||
if (sActiveChildCounter) {
|
if (sActiveChildCounter) {
|
||||||
return (static_cast<Atomic<int32_t>*>(
|
return (static_cast<Atomic<int32_t>*>(
|
||||||
sActiveChildCounter
|
sActiveChildCounter
|
||||||
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
->memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,8 @@
|
|||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/ipc/PIdleSchedulerParent.h"
|
#include "mozilla/ipc/PIdleSchedulerParent.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "base/shared_memory.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
||||||
#define NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT 1024
|
#define NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT 1024
|
||||||
@@ -89,7 +88,7 @@ class IdleSchedulerParent final
|
|||||||
// This way the global activity can be checked in a fast way by just looking
|
// This way the global activity can be checked in a fast way by just looking
|
||||||
// at [0] value.
|
// at [0] value.
|
||||||
// [1] is used for cpu count for child processes.
|
// [1] is used for cpu count for child processes.
|
||||||
static RefPtr<SharedMemory> sActiveChildCounter;
|
static base::SharedMemory* sActiveChildCounter;
|
||||||
// A bit is set if there is a child with child Id as the offset.
|
// A bit is set if there is a child with child Id as the offset.
|
||||||
// The bit is used to check per child specific activity counters in
|
// The bit is used to check per child specific activity counters in
|
||||||
// sActiveChildCounter.
|
// sActiveChildCounter.
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
include protocol PBackground;
|
include protocol PBackground;
|
||||||
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
|
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
|
||||||
[MoveOnly] using mozilla::ipc::SharedMemoryHandle from "mozilla/ipc/SharedMemory.h";
|
[MoveOnly] using base::SharedMemoryHandle from "base/shared_memory.h";
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
||||||
@@ -32,7 +32,8 @@ namespace ipc {
|
|||||||
* process, child process informs the scheduler and the process is moved back
|
* process, child process informs the scheduler and the process is moved back
|
||||||
* to the default queue.
|
* to the default queue.
|
||||||
*/
|
*/
|
||||||
async protocol PIdleScheduler {
|
async protocol PIdleScheduler
|
||||||
|
{
|
||||||
manager PBackground;
|
manager PBackground;
|
||||||
|
|
||||||
child:
|
child:
|
||||||
@@ -43,8 +44,8 @@ parent:
|
|||||||
async RequestIdleTime(uint64_t id, TimeDuration budget);
|
async RequestIdleTime(uint64_t id, TimeDuration budget);
|
||||||
async IdleTimeUsed(uint64_t id);
|
async IdleTimeUsed(uint64_t id);
|
||||||
|
|
||||||
// Child can send explicit Schedule message to parent if it thinks parent
|
// Child can send explicit Schedule message to parent if it thinks parent process
|
||||||
// process might be able to let some other process to use idle time.
|
// might be able to let some other process to use idle time.
|
||||||
async Schedule();
|
async Schedule();
|
||||||
|
|
||||||
// Note, these two messages can be sent even before InitForIdleUse.
|
// Note, these two messages can be sent even before InitForIdleUse.
|
||||||
@@ -52,7 +53,7 @@ parent:
|
|||||||
async PrioritizedOperationDone();
|
async PrioritizedOperationDone();
|
||||||
|
|
||||||
// Ask if now would be a good time to GC
|
// Ask if now would be a good time to GC
|
||||||
async RequestGC() returns(bool may_gc);
|
async RequestGC() returns (bool may_gc);
|
||||||
|
|
||||||
// Let the parent know when we start a GC without asking first.
|
// Let the parent know when we start a GC without asking first.
|
||||||
async StartedGC();
|
async StartedGC();
|
||||||
@@ -60,10 +61,10 @@ parent:
|
|||||||
// Called for ending any kind of GC.
|
// Called for ending any kind of GC.
|
||||||
async DoneGC();
|
async DoneGC();
|
||||||
|
|
||||||
// This message is never sent. Each PIdleScheduler actor will stay alive as
|
// This message is never sent. Each PIdleScheduler actor will stay alive as long as
|
||||||
// long as its PBackground manager.
|
// its PBackground manager.
|
||||||
async __delete__();
|
async __delete__();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ void ProcessChild::AddPlatformBuildID(geckoargs::ChildProcessArgs& aExtraArgs) {
|
|||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
bool ProcessChild::InitPrefs(int aArgc, char* aArgv[]) {
|
bool ProcessChild::InitPrefs(int aArgc, char* aArgv[]) {
|
||||||
Maybe<SharedMemoryHandle> prefsHandle =
|
Maybe<UniqueFileHandle> prefsHandle =
|
||||||
geckoargs::sPrefsHandle.Get(aArgc, aArgv);
|
geckoargs::sPrefsHandle.Get(aArgc, aArgv);
|
||||||
Maybe<SharedMemoryHandle> prefMapHandle =
|
Maybe<UniqueFileHandle> prefMapHandle =
|
||||||
geckoargs::sPrefMapHandle.Get(aArgc, aArgv);
|
geckoargs::sPrefMapHandle.Get(aArgc, aArgv);
|
||||||
Maybe<uint64_t> prefsLen = geckoargs::sPrefsLen.Get(aArgc, aArgv);
|
Maybe<uint64_t> prefsLen = geckoargs::sPrefsLen.Get(aArgc, aArgv);
|
||||||
Maybe<uint64_t> prefMapSize = geckoargs::sPrefMapSize.Get(aArgc, aArgv);
|
Maybe<uint64_t> prefMapSize = geckoargs::sPrefMapSize.Get(aArgc, aArgv);
|
||||||
|
|||||||
@@ -12,10 +12,9 @@
|
|||||||
|
|
||||||
#include "mozilla/GeckoArgs.h"
|
#include "mozilla/GeckoArgs.h"
|
||||||
#include "mozilla/ipc/FileDescriptor.h"
|
#include "mozilla/ipc/FileDescriptor.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "nsXULAppAPI.h"
|
#include "nsXULAppAPI.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@@ -39,9 +38,9 @@ class SharedPreferenceSerializer final {
|
|||||||
size_t GetPrefMapSize() const { return mPrefMapSize; }
|
size_t GetPrefMapSize() const { return mPrefMapSize; }
|
||||||
size_t GetPrefsLength() const { return mPrefsLength; }
|
size_t GetPrefsLength() const { return mPrefsLength; }
|
||||||
|
|
||||||
const SharedMemoryHandle& GetPrefsHandle() const { return mPrefsHandle; }
|
const UniqueFileHandle& GetPrefsHandle() const { return mPrefsHandle; }
|
||||||
|
|
||||||
const SharedMemoryHandle& GetPrefMapHandle() const { return mPrefMapHandle; }
|
const UniqueFileHandle& GetPrefMapHandle() const { return mPrefMapHandle; }
|
||||||
|
|
||||||
void AddSharedPrefCmdLineArgs(GeckoChildProcessHost& procHost,
|
void AddSharedPrefCmdLineArgs(GeckoChildProcessHost& procHost,
|
||||||
geckoargs::ChildProcessArgs& aExtraOpts) const;
|
geckoargs::ChildProcessArgs& aExtraOpts) const;
|
||||||
@@ -50,8 +49,8 @@ class SharedPreferenceSerializer final {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceSerializer);
|
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceSerializer);
|
||||||
size_t mPrefMapSize;
|
size_t mPrefMapSize;
|
||||||
size_t mPrefsLength;
|
size_t mPrefsLength;
|
||||||
SharedMemoryHandle mPrefMapHandle;
|
UniqueFileHandle mPrefMapHandle;
|
||||||
SharedMemoryHandle mPrefsHandle;
|
UniqueFileHandle mPrefsHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedPreferenceDeserializer final {
|
class SharedPreferenceDeserializer final {
|
||||||
@@ -59,18 +58,18 @@ class SharedPreferenceDeserializer final {
|
|||||||
SharedPreferenceDeserializer();
|
SharedPreferenceDeserializer();
|
||||||
~SharedPreferenceDeserializer();
|
~SharedPreferenceDeserializer();
|
||||||
|
|
||||||
bool DeserializeFromSharedMemory(SharedMemoryHandle aPrefsHandle,
|
bool DeserializeFromSharedMemory(UniqueFileHandle aPrefsHandle,
|
||||||
SharedMemoryHandle aPrefMapHandle,
|
UniqueFileHandle aPrefMapHandle,
|
||||||
uint64_t aPrefsLen, uint64_t aPrefMapSize);
|
uint64_t aPrefsLen, uint64_t aPrefMapSize);
|
||||||
|
|
||||||
const SharedMemoryHandle& GetPrefMapHandle() const;
|
const FileDescriptor& GetPrefMapHandle() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceDeserializer);
|
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceDeserializer);
|
||||||
Maybe<SharedMemoryHandle> mPrefMapHandle;
|
Maybe<FileDescriptor> mPrefMapHandle;
|
||||||
Maybe<size_t> mPrefsLen;
|
Maybe<size_t> mPrefsLen;
|
||||||
Maybe<size_t> mPrefMapSize;
|
Maybe<size_t> mPrefMapSize;
|
||||||
RefPtr<SharedMemory> mShmem = MakeRefPtr<SharedMemory>();
|
base::SharedMemory mShmem;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate command line argument to spawn a child process. If the shared memory
|
// Generate command line argument to spawn a child process. If the shared memory
|
||||||
@@ -80,7 +79,7 @@ void ExportSharedJSInit(GeckoChildProcessHost& procHost,
|
|||||||
|
|
||||||
// Initialize the content used by the JS engine during the initialization of a
|
// Initialize the content used by the JS engine during the initialization of a
|
||||||
// JS::Runtime.
|
// JS::Runtime.
|
||||||
bool ImportSharedJSInit(SharedMemoryHandle aJsInitHandle, uint64_t aJsInitLen);
|
bool ImportSharedJSInit(UniqueFileHandle aJsInitHandle, uint64_t aJsInitLen);
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/GeckoArgs.h"
|
#include "mozilla/GeckoArgs.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/dom/RemoteType.h"
|
#include "mozilla/dom/RemoteType.h"
|
||||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
@@ -40,7 +39,8 @@ SharedPreferenceSerializer::SharedPreferenceSerializer(
|
|||||||
bool SharedPreferenceSerializer::SerializeToSharedMemory(
|
bool SharedPreferenceSerializer::SerializeToSharedMemory(
|
||||||
const GeckoProcessType aDestinationProcessType,
|
const GeckoProcessType aDestinationProcessType,
|
||||||
const nsACString& aDestinationRemoteType) {
|
const nsACString& aDestinationRemoteType) {
|
||||||
mPrefMapHandle = Preferences::EnsureSnapshot(&mPrefMapSize);
|
mPrefMapHandle =
|
||||||
|
Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
|
||||||
|
|
||||||
bool destIsWebContent =
|
bool destIsWebContent =
|
||||||
aDestinationProcessType == GeckoProcessType_Content &&
|
aDestinationProcessType == GeckoProcessType_Content &&
|
||||||
@@ -52,31 +52,30 @@ bool SharedPreferenceSerializer::SerializeToSharedMemory(
|
|||||||
Preferences::SerializePreferences(prefs, destIsWebContent);
|
Preferences::SerializePreferences(prefs, destIsWebContent);
|
||||||
mPrefsLength = prefs.Length();
|
mPrefsLength = prefs.Length();
|
||||||
|
|
||||||
RefPtr<SharedMemory> shm = MakeRefPtr<SharedMemory>();
|
base::SharedMemory shm;
|
||||||
// Set up the shared memory.
|
// Set up the shared memory.
|
||||||
if (!shm->Create(prefs.Length())) {
|
if (!shm.Create(prefs.Length())) {
|
||||||
NS_ERROR("failed to create shared memory in the parent");
|
NS_ERROR("failed to create shared memory in the parent");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!shm->Map(prefs.Length())) {
|
if (!shm.Map(prefs.Length())) {
|
||||||
NS_ERROR("failed to map shared memory in the parent");
|
NS_ERROR("failed to map shared memory in the parent");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the serialized prefs into the shared memory.
|
// Copy the serialized prefs into the shared memory.
|
||||||
memcpy(static_cast<char*>(shm->Memory()), prefs.get(), mPrefsLength);
|
memcpy(static_cast<char*>(shm.memory()), prefs.get(), mPrefsLength);
|
||||||
|
|
||||||
mPrefsHandle = shm->TakeHandleAndUnmap();
|
mPrefsHandle = shm.TakeHandle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
|
void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
|
||||||
mozilla::ipc::GeckoChildProcessHost& procHost,
|
mozilla::ipc::GeckoChildProcessHost& procHost,
|
||||||
geckoargs::ChildProcessArgs& aExtraOpts) const {
|
geckoargs::ChildProcessArgs& aExtraOpts) const {
|
||||||
SharedMemoryHandle prefsHandle = SharedMemory::CloneHandle(GetPrefsHandle());
|
UniqueFileHandle prefsHandle = DuplicateFileHandle(GetPrefsHandle());
|
||||||
MOZ_RELEASE_ASSERT(prefsHandle, "failed to duplicate prefs handle");
|
MOZ_RELEASE_ASSERT(prefsHandle, "failed to duplicate prefs handle");
|
||||||
SharedMemoryHandle prefMapHandle =
|
UniqueFileHandle prefMapHandle = DuplicateFileHandle(GetPrefMapHandle());
|
||||||
SharedMemory::CloneHandle(GetPrefMapHandle());
|
|
||||||
MOZ_RELEASE_ASSERT(prefMapHandle, "failed to duplicate pref map handle");
|
MOZ_RELEASE_ASSERT(prefMapHandle, "failed to duplicate pref map handle");
|
||||||
|
|
||||||
// Pass the handles and lengths via command line flags.
|
// Pass the handles and lengths via command line flags.
|
||||||
@@ -95,7 +94,7 @@ SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
|
bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
|
||||||
SharedMemoryHandle aPrefsHandle, SharedMemoryHandle aPrefMapHandle,
|
UniqueFileHandle aPrefsHandle, UniqueFileHandle aPrefMapHandle,
|
||||||
uint64_t aPrefsLen, uint64_t aPrefMapSize) {
|
uint64_t aPrefsLen, uint64_t aPrefMapSize) {
|
||||||
if (!aPrefsHandle || !aPrefMapHandle || !aPrefsLen || !aPrefMapSize) {
|
if (!aPrefsHandle || !aPrefMapHandle || !aPrefsLen || !aPrefMapSize) {
|
||||||
return false;
|
return false;
|
||||||
@@ -112,23 +111,21 @@ bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
|
|||||||
Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
|
Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
|
||||||
|
|
||||||
// Set up early prefs from the shared memory.
|
// Set up early prefs from the shared memory.
|
||||||
if (!mShmem->SetHandle(std::move(aPrefsHandle),
|
if (!mShmem.SetHandle(std::move(aPrefsHandle), /* read_only */ true)) {
|
||||||
SharedMemory::RightsReadOnly)) {
|
|
||||||
NS_ERROR("failed to open shared memory in the child");
|
NS_ERROR("failed to open shared memory in the child");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!mShmem->Map(*mPrefsLen)) {
|
if (!mShmem.Map(*mPrefsLen)) {
|
||||||
NS_ERROR("failed to map shared memory in the child");
|
NS_ERROR("failed to map shared memory in the child");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Preferences::DeserializePreferences(static_cast<char*>(mShmem->Memory()),
|
Preferences::DeserializePreferences(static_cast<char*>(mShmem.memory()),
|
||||||
*mPrefsLen);
|
*mPrefsLen);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SharedMemoryHandle& SharedPreferenceDeserializer::GetPrefMapHandle()
|
const FileDescriptor& SharedPreferenceDeserializer::GetPrefMapHandle() const {
|
||||||
const {
|
|
||||||
MOZ_ASSERT(mPrefMapHandle.isSome());
|
MOZ_ASSERT(mPrefMapHandle.isSome());
|
||||||
|
|
||||||
return mPrefMapHandle.ref();
|
return mPrefMapHandle.ref();
|
||||||
@@ -141,12 +138,12 @@ void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
|
|||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
auto& shmem = xpc::SelfHostedShmem::GetSingleton();
|
auto& shmem = xpc::SelfHostedShmem::GetSingleton();
|
||||||
SharedMemoryHandle handle = SharedMemory::CloneHandle(shmem.Handle());
|
UniqueFileHandle handle = DuplicateFileHandle(shmem.Handle());
|
||||||
size_t len = shmem.Content().Length();
|
size_t len = shmem.Content().Length();
|
||||||
|
|
||||||
// If the file is not found or the content is empty, then we would start the
|
// If the file is not found or the content is empty, then we would start the
|
||||||
// content process without this optimization.
|
// content process without this optimization.
|
||||||
if (!SharedMemory::IsHandleValid(handle) || !len) {
|
if (!handle || !len) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +153,7 @@ void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImportSharedJSInit(SharedMemoryHandle aJsInitHandle, uint64_t aJsInitLen) {
|
bool ImportSharedJSInit(UniqueFileHandle aJsInitHandle, uint64_t aJsInitLen) {
|
||||||
// This is an optimization, and as such we can safely recover if the command
|
// This is an optimization, and as such we can safely recover if the command
|
||||||
// line argument are not provided.
|
// line argument are not provided.
|
||||||
if (!aJsInitLen || !aJsInitHandle) {
|
if (!aJsInitLen || !aJsInitHandle) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#ifndef MOZILLA_IPC_RAWSHMEM_H_
|
#ifndef MOZILLA_IPC_RAWSHMEM_H_
|
||||||
#define MOZILLA_IPC_RAWSHMEM_H_
|
#define MOZILLA_IPC_RAWSHMEM_H_
|
||||||
|
|
||||||
#include "chrome/common/ipc_message_utils.h"
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "mozilla/ipc/SharedMemory.h"
|
||||||
#include "mozilla/Span.h"
|
#include "mozilla/Span.h"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|||||||
@@ -4,14 +4,8 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* This source code was derived from Chromium code, and as such is also subject
|
|
||||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
|
||||||
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "mozilla/ipc/SharedMemory.h"
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "chrome/common/ipc_message_utils.h"
|
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "nsIMemoryReporter.h"
|
#include "nsIMemoryReporter.h"
|
||||||
|
|
||||||
@@ -59,7 +53,6 @@ SharedMemory::SharedMemory() : mAllocSize(0), mMappedSize(0) {
|
|||||||
SharedMemory::~SharedMemory() {
|
SharedMemory::~SharedMemory() {
|
||||||
Unmap();
|
Unmap();
|
||||||
CloseHandle();
|
CloseHandle();
|
||||||
ResetImpl();
|
|
||||||
|
|
||||||
MOZ_ASSERT(gShmemAllocated >= mAllocSize,
|
MOZ_ASSERT(gShmemAllocated >= mAllocSize,
|
||||||
"Can't destroy more than allocated");
|
"Can't destroy more than allocated");
|
||||||
@@ -67,108 +60,8 @@ SharedMemory::~SharedMemory() {
|
|||||||
mAllocSize = 0;
|
mAllocSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SharedMemory::Create(size_t aNBytes, bool freezable) {
|
|
||||||
MOZ_ASSERT(!IsValid(), "already initialized");
|
|
||||||
bool ok = CreateImpl(aNBytes, freezable);
|
|
||||||
if (ok) {
|
|
||||||
mAllocSize = aNBytes;
|
|
||||||
mFreezable = freezable;
|
|
||||||
mReadOnly = false;
|
|
||||||
mExternalHandle = false;
|
|
||||||
gShmemAllocated += mAllocSize;
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::Map(size_t aNBytes, void* fixedAddress) {
|
|
||||||
if (!mHandle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(!mMemory, "can't map memory when a mapping already exists");
|
|
||||||
auto address = MapImpl(aNBytes, fixedAddress);
|
|
||||||
if (address) {
|
|
||||||
mMappedSize = aNBytes;
|
|
||||||
mMemory = UniqueMapping(*address, MappingDeleter(mMappedSize));
|
|
||||||
gShmemMapped += mMappedSize;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::Unmap() {
|
|
||||||
if (!mMemory) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(gShmemMapped >= mMappedSize, "Can't unmap more than mapped");
|
|
||||||
mMemory = nullptr;
|
|
||||||
gShmemMapped -= std::exchange(mMappedSize, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* SharedMemory::Memory() const {
|
|
||||||
#ifdef FUZZING
|
|
||||||
return SharedMemoryFuzzer::MutateSharedMemory(mMemory.get(), mAllocSize);
|
|
||||||
#else
|
|
||||||
return mMemory.get();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Span<uint8_t> SharedMemory::TakeMapping() {
|
|
||||||
// NOTE: this doesn't reduce gShmemMapped since it _is_ still mapped memory
|
|
||||||
// (and will be until the process terminates).
|
|
||||||
return {static_cast<uint8_t*>(mMemory.release()),
|
|
||||||
std::exchange(mMappedSize, 0)};
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedMemory::Handle SharedMemory::TakeHandle() {
|
|
||||||
gShmemAllocated -= mAllocSize;
|
|
||||||
mAllocSize = 0;
|
|
||||||
return std::move(mHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::SetHandle(Handle aHandle, OpenRights aRights) {
|
|
||||||
MOZ_ASSERT(!IsValid(),
|
|
||||||
"SetHandle cannot be called when a valid handle is already held");
|
|
||||||
ResetImpl();
|
|
||||||
mHandle = std::move(aHandle);
|
|
||||||
mAllocSize = 0;
|
|
||||||
mMappedSize = 0;
|
|
||||||
mFreezable = false;
|
|
||||||
mReadOnly = aRights == OpenRights::RightsReadOnly;
|
|
||||||
mExternalHandle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
|
|
||||||
MOZ_ASSERT(mHandle);
|
|
||||||
MOZ_ASSERT(!mReadOnly);
|
|
||||||
MOZ_ASSERT(mFreezable);
|
|
||||||
if (ro_out == this) {
|
|
||||||
MOZ_ASSERT(
|
|
||||||
!mMemory,
|
|
||||||
"Memory cannot be mapped when creating a read-only copy of this.");
|
|
||||||
}
|
|
||||||
auto handle = ReadOnlyCopyImpl();
|
|
||||||
auto allocSize = mAllocSize;
|
|
||||||
TakeHandle();
|
|
||||||
if (!handle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mFreezable = false;
|
|
||||||
|
|
||||||
// Reset ro_out (unmapping, etc).
|
|
||||||
ro_out->~SharedMemory();
|
|
||||||
|
|
||||||
ro_out->mHandle = std::move(*handle);
|
|
||||||
ro_out->mAllocSize = allocSize;
|
|
||||||
gShmemAllocated += ro_out->mAllocSize;
|
|
||||||
ro_out->mReadOnly = true;
|
|
||||||
ro_out->mFreezable = false;
|
|
||||||
ro_out->mExternalHandle = mExternalHandle;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::WriteHandle(IPC::MessageWriter* aWriter) {
|
bool SharedMemory::WriteHandle(IPC::MessageWriter* aWriter) {
|
||||||
Handle handle = CloneHandle(mHandle);
|
Handle handle = CloneHandle();
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -183,9 +76,6 @@ bool SharedMemory::ReadHandle(IPC::MessageReader* aReader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SharedMemory::Protect(char* aAddr, size_t aSize, int aRights) {
|
void SharedMemory::Protect(char* aAddr, size_t aSize, int aRights) {
|
||||||
// Don't allow altering of rights on freezable shared memory handles.
|
|
||||||
MOZ_ASSERT(!mFreezable);
|
|
||||||
|
|
||||||
char* memStart = reinterpret_cast<char*>(Memory());
|
char* memStart = reinterpret_cast<char*>(Memory());
|
||||||
if (!memStart) MOZ_CRASH("SharedMemory region points at NULL!");
|
if (!memStart) MOZ_CRASH("SharedMemory region points at NULL!");
|
||||||
char* memEnd = memStart + Size();
|
char* memEnd = memStart + Size();
|
||||||
@@ -208,4 +98,37 @@ size_t SharedMemory::PageAlignedSize(size_t aSize) {
|
|||||||
return pageSize * nPagesNeeded;
|
return pageSize * nPagesNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::Create(size_t aNBytes) {
|
||||||
|
bool ok = CreateImpl(aNBytes);
|
||||||
|
if (ok) {
|
||||||
|
mAllocSize = aNBytes;
|
||||||
|
gShmemAllocated += mAllocSize;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemory::Map(size_t aNBytes, void* fixedAddress) {
|
||||||
|
bool ok = MapImpl(aNBytes, fixedAddress);
|
||||||
|
if (ok) {
|
||||||
|
mMappedSize = aNBytes;
|
||||||
|
gShmemMapped += mMappedSize;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMemory::Unmap() {
|
||||||
|
MOZ_ASSERT(gShmemMapped >= mMappedSize, "Can't unmap more than mapped");
|
||||||
|
UnmapImpl(mMappedSize);
|
||||||
|
gShmemMapped -= mMappedSize;
|
||||||
|
mMappedSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SharedMemory::Memory() const {
|
||||||
|
#ifdef FUZZING
|
||||||
|
return SharedMemoryFuzzer::MutateSharedMemory(MemoryImpl(), mAllocSize);
|
||||||
|
#else
|
||||||
|
return MemoryImpl();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
} // namespace mozilla::ipc
|
||||||
|
|||||||
@@ -4,56 +4,27 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* This source code was derived from Chromium code, and as such is also subject
|
|
||||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
|
||||||
|
|
||||||
#ifndef mozilla_ipc_SharedMemory_h
|
#ifndef mozilla_ipc_SharedMemory_h
|
||||||
#define mozilla_ipc_SharedMemory_h
|
#define mozilla_ipc_SharedMemory_h
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include "mozilla/Maybe.h"
|
#include "chrome/common/ipc_message_utils.h"
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
|
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
|
||||||
|
|
||||||
#if !(defined(XP_DARWIN) || defined(XP_WIN))
|
#ifdef XP_DARWIN
|
||||||
# include <string>
|
# include "mozilla/ipc/SharedMemoryImpl_mach.h"
|
||||||
|
#else
|
||||||
|
# include "mozilla/ipc/SharedMemoryImpl_chromium.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace IPC {
|
|
||||||
class MessageWriter;
|
|
||||||
class MessageReader;
|
|
||||||
} // namespace IPC
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
// Rust Bindgen code doesn't actually use these types, but `UniqueFileHandle`
|
class SharedMemory : public SharedMemoryImpl {
|
||||||
// and `UniqueMachSendRight` aren't defined and some headers need to type check,
|
|
||||||
// so we define a dummy type.
|
|
||||||
#if defined(RUST_BINDGEN)
|
|
||||||
using SharedMemoryHandle = void*;
|
|
||||||
#elif defined(XP_DARWIN)
|
|
||||||
using SharedMemoryHandle = mozilla::UniqueMachSendRight;
|
|
||||||
#else
|
|
||||||
using SharedMemoryHandle = mozilla::UniqueFileHandle;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class SharedMemory {
|
|
||||||
~SharedMemory();
|
~SharedMemory();
|
||||||
|
|
||||||
/// # Provided methods
|
|
||||||
public:
|
public:
|
||||||
using Handle = SharedMemoryHandle;
|
|
||||||
|
|
||||||
enum OpenRights {
|
|
||||||
RightsReadOnly = RightsRead,
|
|
||||||
RightsReadWrite = RightsRead | RightsWrite,
|
|
||||||
};
|
|
||||||
|
|
||||||
SharedMemory();
|
SharedMemory();
|
||||||
|
|
||||||
// bug 1168843, compositor thread may create shared memory instances that are
|
// bug 1168843, compositor thread may create shared memory instances that are
|
||||||
@@ -62,123 +33,32 @@ class SharedMemory {
|
|||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)
|
||||||
|
|
||||||
size_t Size() const { return mMappedSize; }
|
size_t Size() const { return mMappedSize; }
|
||||||
size_t MaxSize() const { return mAllocSize; }
|
|
||||||
|
|
||||||
bool Create(size_t nBytes, bool freezable = false);
|
|
||||||
bool Map(size_t nBytes, void* fixedAddress = nullptr);
|
|
||||||
void Unmap();
|
|
||||||
void* Memory() const;
|
|
||||||
/// Take the mapping memory.
|
|
||||||
///
|
|
||||||
/// This prevents unmapping the memory.
|
|
||||||
Span<uint8_t> TakeMapping();
|
|
||||||
|
|
||||||
Handle TakeHandleAndUnmap() {
|
|
||||||
auto handle = TakeHandle();
|
|
||||||
Unmap();
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
Handle TakeHandle();
|
|
||||||
Handle CloneHandle() {
|
|
||||||
mFreezable = false;
|
|
||||||
return SharedMemory::CloneHandle(mHandle);
|
|
||||||
}
|
|
||||||
void CloseHandle() { TakeHandle(); }
|
void CloseHandle() { TakeHandle(); }
|
||||||
bool SetHandle(Handle aHandle, OpenRights aRights);
|
|
||||||
bool IsValid() const { return IsHandleValid(mHandle); }
|
|
||||||
static bool IsHandleValid(const Handle& aHandle) {
|
|
||||||
// `operator!=` had ambiguous overload resolution with the windows Handle
|
|
||||||
// (mozilla::UniqueFileHandle), so invert `operator==` instead.
|
|
||||||
return !(aHandle == NULLHandle());
|
|
||||||
}
|
|
||||||
static Handle NULLHandle() { return nullptr; }
|
|
||||||
|
|
||||||
bool CreateFreezable(size_t nBytes) { return Create(nBytes, true); }
|
|
||||||
|
|
||||||
[[nodiscard]] bool Freeze() {
|
|
||||||
Unmap();
|
|
||||||
return ReadOnlyCopy(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WriteHandle(IPC::MessageWriter* aWriter);
|
bool WriteHandle(IPC::MessageWriter* aWriter);
|
||||||
bool ReadHandle(IPC::MessageReader* aReader);
|
bool ReadHandle(IPC::MessageReader* aReader);
|
||||||
void Protect(char* aAddr, size_t aSize, int aRights);
|
void Protect(char* aAddr, size_t aSize, int aRights);
|
||||||
|
|
||||||
static size_t PageAlignedSize(size_t aSize);
|
|
||||||
|
|
||||||
/// Public methods which should be defined as part of each implementation.
|
|
||||||
public:
|
|
||||||
[[nodiscard]] bool ReadOnlyCopy(SharedMemory* ro_out);
|
|
||||||
|
|
||||||
static void SystemProtect(char* aAddr, size_t aSize, int aRights);
|
static void SystemProtect(char* aAddr, size_t aSize, int aRights);
|
||||||
[[nodiscard]] static bool SystemProtectFallible(char* aAddr, size_t aSize,
|
[[nodiscard]] static bool SystemProtectFallible(char* aAddr, size_t aSize,
|
||||||
int aRights);
|
int aRights);
|
||||||
static Handle CloneHandle(const Handle& aHandle);
|
|
||||||
static size_t SystemPageSize();
|
static size_t SystemPageSize();
|
||||||
static void* FindFreeAddressSpace(size_t size);
|
static size_t PageAlignedSize(size_t aSize);
|
||||||
|
|
||||||
|
bool Create(size_t nBytes);
|
||||||
|
bool Map(size_t nBytes, void* fixedAddress = nullptr);
|
||||||
|
void Unmap();
|
||||||
|
void* Memory() const;
|
||||||
|
|
||||||
/// Private methods which should be defined as part of each implementation.
|
|
||||||
private:
|
private:
|
||||||
bool CreateImpl(size_t size, bool freezable);
|
|
||||||
Maybe<void*> MapImpl(size_t nBytes, void* fixedAddress);
|
|
||||||
static void UnmapImpl(size_t nBytes, void* address);
|
|
||||||
Maybe<Handle> ReadOnlyCopyImpl();
|
|
||||||
void ResetImpl();
|
|
||||||
|
|
||||||
/// Common members
|
|
||||||
private:
|
|
||||||
struct MappingDeleter {
|
|
||||||
size_t mMappedSize = 0;
|
|
||||||
explicit MappingDeleter(size_t size) : mMappedSize(size) {}
|
|
||||||
MappingDeleter() = default;
|
|
||||||
void operator()(void* ptr) {
|
|
||||||
MOZ_ASSERT(mMappedSize != 0);
|
|
||||||
UnmapImpl(mMappedSize, ptr);
|
|
||||||
// Guard against multiple calls of the same deleter, which shouldn't
|
|
||||||
// happen (but could, if `UniquePtr::reset` were used). Calling
|
|
||||||
// `munmap` with an incorrect non-zero length would be bad.
|
|
||||||
mMappedSize = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;
|
|
||||||
|
|
||||||
// The held handle, if any.
|
|
||||||
Handle mHandle = NULLHandle();
|
|
||||||
// The size of the shmem region requested in Create(), if
|
// The size of the shmem region requested in Create(), if
|
||||||
// successful. SharedMemory instances that are opened from a
|
// successful. SharedMemory instances that are opened from a
|
||||||
// foreign handle have an alloc size of 0, even though they have
|
// foreign handle have an alloc size of 0, even though they have
|
||||||
// access to the alloc-size information.
|
// access to the alloc-size information.
|
||||||
size_t mAllocSize;
|
size_t mAllocSize;
|
||||||
// The memory mapping, if any.
|
|
||||||
UniqueMapping mMemory;
|
|
||||||
// The size of the region mapped in Map(), if successful. All
|
// The size of the region mapped in Map(), if successful. All
|
||||||
// SharedMemorys that are mapped have a non-zero mapped size.
|
// SharedMemorys that are mapped have a non-zero mapped size.
|
||||||
size_t mMappedSize;
|
size_t mMappedSize;
|
||||||
// Whether the handle held is freezable.
|
|
||||||
bool mFreezable = false;
|
|
||||||
// Whether the handle held is read-only.
|
|
||||||
bool mReadOnly = false;
|
|
||||||
// Whether the handle held is external (set with `SetHandle`).
|
|
||||||
bool mExternalHandle = false;
|
|
||||||
|
|
||||||
#if !defined(XP_DARWIN) && !defined(XP_WIN)
|
|
||||||
/// # Unix/POSIX-specific methods and members.
|
|
||||||
public:
|
|
||||||
// If named POSIX shm is being used, append the prefix (including
|
|
||||||
// the leading '/') that would be used by a process with the given
|
|
||||||
// pid to the given string and return true. If not, return false.
|
|
||||||
// (This is public so that the Linux sandboxing code can use it.)
|
|
||||||
static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
|
|
||||||
|
|
||||||
// Similar, but simply returns whether POSIX shm is in use.
|
|
||||||
static bool UsingPosixShm();
|
|
||||||
|
|
||||||
# if !defined(ANDROID) && !defined(RUST_BINDGEN)
|
|
||||||
private:
|
|
||||||
mozilla::UniqueFileHandle mFrozenFile;
|
|
||||||
bool mIsMemfd = false;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
} // namespace mozilla::ipc
|
||||||
|
|||||||
47
ipc/glue/SharedMemoryImpl_chromium.cpp
Normal file
47
ipc/glue/SharedMemoryImpl_chromium.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#include "mozilla/ipc/SharedMemoryImpl_chromium.h"
|
||||||
|
|
||||||
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
|
SharedMemoryImpl::Handle SharedMemoryImpl::CloneHandle() {
|
||||||
|
return mSharedMemory.CloneHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryImpl::Handle SharedMemoryImpl::TakeHandle() {
|
||||||
|
return mSharedMemory.TakeHandle(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::IsHandleValid(const Handle& aHandle) const {
|
||||||
|
return base::SharedMemory::IsHandleValid(aHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::SetHandle(Handle aHandle, OpenRights aRights) {
|
||||||
|
return mSharedMemory.SetHandle(std::move(aHandle), aRights == RightsReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryImpl::Handle SharedMemoryImpl::NULLHandle() {
|
||||||
|
return base::SharedMemory::NULLHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SharedMemoryImpl::FindFreeAddressSpace(size_t size) {
|
||||||
|
return base::SharedMemory::FindFreeAddressSpace(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::CreateImpl(size_t size) {
|
||||||
|
return mSharedMemory.Create(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::MapImpl(size_t nBytes, void* fixedAddress) {
|
||||||
|
return mSharedMemory.Map(nBytes, fixedAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMemoryImpl::UnmapImpl(size_t mappedSize) { mSharedMemory.Unmap(); }
|
||||||
|
|
||||||
|
void* SharedMemoryImpl::MemoryImpl() const { return mSharedMemory.memory(); }
|
||||||
|
|
||||||
|
} // namespace mozilla::ipc
|
||||||
51
ipc/glue/SharedMemoryImpl_chromium.h
Normal file
51
ipc/glue/SharedMemoryImpl_chromium.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_ipc_SharedMemoryImpl_posix_h
|
||||||
|
#define mozilla_ipc_SharedMemoryImpl_posix_h
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
|
class SharedMemoryImpl {
|
||||||
|
public:
|
||||||
|
using Handle = base::SharedMemoryHandle;
|
||||||
|
|
||||||
|
enum OpenRights {
|
||||||
|
RightsReadOnly = RightsRead,
|
||||||
|
RightsReadWrite = RightsRead | RightsWrite,
|
||||||
|
};
|
||||||
|
|
||||||
|
Handle CloneHandle();
|
||||||
|
Handle TakeHandle();
|
||||||
|
|
||||||
|
bool IsHandleValid(const Handle& aHandle) const;
|
||||||
|
bool SetHandle(Handle aHandle, OpenRights aRights);
|
||||||
|
|
||||||
|
static Handle NULLHandle();
|
||||||
|
static void* FindFreeAddressSpace(size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SharedMemoryImpl() = default;
|
||||||
|
~SharedMemoryImpl() {}
|
||||||
|
|
||||||
|
bool CreateImpl(size_t size);
|
||||||
|
bool MapImpl(size_t nBytes, void* fixedAddress);
|
||||||
|
void UnmapImpl(size_t mappedSize);
|
||||||
|
void* MemoryImpl() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
base::SharedMemory mSharedMemory;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::ipc
|
||||||
|
|
||||||
|
#endif
|
||||||
170
ipc/glue/SharedMemoryImpl_mach.cpp
Normal file
170
ipc/glue/SharedMemoryImpl_mach.cpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#include "mozilla/ipc/SharedMemoryImpl_mach.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <mach/vm_map.h>
|
||||||
|
#include <mach/mach_port.h>
|
||||||
|
#if defined(XP_IOS)
|
||||||
|
# include <mach/vm_map.h>
|
||||||
|
# define mach_vm_address_t vm_address_t
|
||||||
|
# define mach_vm_map vm_map
|
||||||
|
# define mach_vm_read vm_read
|
||||||
|
# define mach_vm_region_recurse vm_region_recurse_64
|
||||||
|
# define mach_vm_size_t vm_size_t
|
||||||
|
#else
|
||||||
|
# include <mach/mach_vm.h>
|
||||||
|
#endif
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "mozilla/IntegerPrintfMacros.h"
|
||||||
|
#include "mozilla/Printf.h"
|
||||||
|
#include "mozilla/StaticMutex.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define LOG_ERROR(str, args...) \
|
||||||
|
PR_BEGIN_MACRO \
|
||||||
|
mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
|
||||||
|
NS_WARNING(msg.get()); \
|
||||||
|
PR_END_MACRO
|
||||||
|
#else
|
||||||
|
# define LOG_ERROR(str, args...) \
|
||||||
|
do { /* nothing */ \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
|
SharedMemoryImpl::SharedMemoryImpl()
|
||||||
|
: mPort(MACH_PORT_NULL), mMemory(nullptr), mOpenRights(RightsReadWrite) {}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::SetHandle(Handle aHandle, OpenRights aRights) {
|
||||||
|
MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
|
||||||
|
|
||||||
|
mPort = std::move(aHandle);
|
||||||
|
mOpenRights = aRights;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void* toPointer(mach_vm_address_t address) {
|
||||||
|
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mach_vm_address_t toVMAddress(void* pointer) {
|
||||||
|
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::CreateImpl(size_t size) {
|
||||||
|
MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized");
|
||||||
|
|
||||||
|
memory_object_size_t memoryObjectSize = round_page(size);
|
||||||
|
|
||||||
|
kern_return_t kr =
|
||||||
|
mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
||||||
|
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
||||||
|
getter_Transfers(mPort), MACH_PORT_NULL);
|
||||||
|
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
|
||||||
|
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
|
||||||
|
mach_error_string(kr), kr);
|
||||||
|
TakeHandle();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::MapImpl(size_t size, void* fixedAddress) {
|
||||||
|
MOZ_ASSERT(mMemory == nullptr);
|
||||||
|
|
||||||
|
if (MACH_PORT_NULL == mPort) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_return_t kr;
|
||||||
|
mach_vm_address_t address = toVMAddress(fixedAddress);
|
||||||
|
|
||||||
|
vm_prot_t vmProtection = VM_PROT_READ;
|
||||||
|
if (mOpenRights == RightsReadWrite) {
|
||||||
|
vmProtection |= VM_PROT_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
||||||
|
fixedAddress ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
|
||||||
|
mPort.get(), 0, false, vmProtection, vmProtection,
|
||||||
|
VM_INHERIT_NONE);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
if (!fixedAddress) {
|
||||||
|
LOG_ERROR(
|
||||||
|
"Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
||||||
|
size, mach_task_self(), mach_port_t(mPort.get()),
|
||||||
|
mach_error_string(kr), kr);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixedAddress && fixedAddress != toPointer(address)) {
|
||||||
|
kr = vm_deallocate(mach_task_self(), address, size);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR(
|
||||||
|
"Failed to unmap shared memory at unsuitable address "
|
||||||
|
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
||||||
|
size, mach_task_self(), mach_port_t(mPort.get()),
|
||||||
|
mach_error_string(kr), kr);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMemory = toPointer(address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SharedMemoryImpl::FindFreeAddressSpace(size_t size) {
|
||||||
|
mach_vm_address_t address = 0;
|
||||||
|
size = round_page(size);
|
||||||
|
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
|
||||||
|
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
|
||||||
|
VM_INHERIT_NONE) != KERN_SUCCESS ||
|
||||||
|
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return toPointer(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SharedMemoryImpl::CloneHandle() -> Handle {
|
||||||
|
return mozilla::RetainMachSendRight(mPort.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SharedMemoryImpl::TakeHandle() -> Handle {
|
||||||
|
mOpenRights = RightsReadWrite;
|
||||||
|
return std::move(mPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMemoryImpl::UnmapImpl(size_t mappedSize) {
|
||||||
|
if (!mMemory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vm_address_t address = toVMAddress(mMemory);
|
||||||
|
kern_return_t kr =
|
||||||
|
vm_deallocate(mach_task_self(), address, round_page(mappedSize));
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
||||||
|
mach_error_string(kr), kr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mMemory = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* SharedMemoryImpl::MemoryImpl() const { return mMemory; }
|
||||||
|
|
||||||
|
bool SharedMemoryImpl::IsHandleValid(const Handle& aHandle) const {
|
||||||
|
return aHandle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SharedMemoryImpl::NULLHandle() -> Handle { return Handle(); }
|
||||||
|
|
||||||
|
} // namespace mozilla::ipc
|
||||||
56
ipc/glue/SharedMemoryImpl_mach.h
Normal file
56
ipc/glue/SharedMemoryImpl_mach.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_ipc_SharedMemoryImpl_mach_h
|
||||||
|
#define mozilla_ipc_SharedMemoryImpl_mach_h
|
||||||
|
|
||||||
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
|
#include <mach/port.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
|
class SharedMemoryImpl {
|
||||||
|
public:
|
||||||
|
using Handle = mozilla::UniqueMachSendRight;
|
||||||
|
|
||||||
|
enum OpenRights {
|
||||||
|
RightsReadOnly = RightsRead,
|
||||||
|
RightsReadWrite = RightsRead | RightsWrite,
|
||||||
|
};
|
||||||
|
|
||||||
|
Handle CloneHandle();
|
||||||
|
Handle TakeHandle();
|
||||||
|
|
||||||
|
bool IsHandleValid(const Handle& aHandle) const;
|
||||||
|
bool SetHandle(Handle aHandle, OpenRights aRights);
|
||||||
|
|
||||||
|
static Handle NULLHandle();
|
||||||
|
static void* FindFreeAddressSpace(size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SharedMemoryImpl();
|
||||||
|
~SharedMemoryImpl() {}
|
||||||
|
|
||||||
|
bool CreateImpl(size_t size);
|
||||||
|
bool MapImpl(size_t nBytes, void* fixedAddress);
|
||||||
|
void UnmapImpl(size_t mappedSize);
|
||||||
|
void* MemoryImpl() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
mozilla::UniqueMachSendRight mPort;
|
||||||
|
// Pointer to mapped region, null if unmapped.
|
||||||
|
void* mMemory;
|
||||||
|
// Access rights to map an existing region with.
|
||||||
|
OpenRights mOpenRights;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::ipc
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/* This source code was derived from Chromium code, and as such is also subject
|
|
||||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
|
||||||
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "mozilla/Ashmem.h"
|
|
||||||
|
|
||||||
#ifdef MOZ_VALGRIND
|
|
||||||
# include <valgrind/valgrind.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "base/eintr_wrapper.h"
|
|
||||||
#include "base/logging.h"
|
|
||||||
#include "base/string_util.h"
|
|
||||||
#include "mozilla/Atomics.h"
|
|
||||||
#include "mozilla/Maybe.h"
|
|
||||||
#include "mozilla/ProfilerThreadSleep.h"
|
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
|
||||||
#include "prenv.h"
|
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
|
||||||
|
|
||||||
void SharedMemory::ResetImpl() {};
|
|
||||||
|
|
||||||
SharedMemory::Handle SharedMemory::CloneHandle(const Handle& aHandle) {
|
|
||||||
const int new_fd = dup(aHandle.get());
|
|
||||||
if (new_fd < 0) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
|
|
||||||
<< strerror(errno);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return mozilla::UniqueFileHandle(new_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
|
||||||
void* memory = mmap(nullptr, size, PROT_NONE,
|
|
||||||
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
|
||||||
if (memory == MAP_FAILED) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
munmap(memory, size);
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<void*> SharedMemory::MapImpl(size_t nBytes, void* fixedAddress) {
|
|
||||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
|
||||||
// replace pages that are alread mapped at that address.
|
|
||||||
void* mem =
|
|
||||||
mmap(fixedAddress, nBytes, PROT_READ | (mReadOnly ? 0 : PROT_WRITE),
|
|
||||||
MAP_SHARED, mHandle.get(), 0);
|
|
||||||
|
|
||||||
if (mem == MAP_FAILED) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixedAddress && mem != fixedAddress) {
|
|
||||||
bool munmap_succeeded = munmap(mem, nBytes) == 0;
|
|
||||||
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
|
||||||
munmap(address, nBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Android has its own shared memory API, ashmem. It doesn't support POSIX
|
|
||||||
// shm_open, and the memfd support (see posix impl) also doesn't work because
|
|
||||||
// its SELinux policy prevents the procfs operations we'd use (see bug 1670277
|
|
||||||
// for more details).
|
|
||||||
|
|
||||||
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::UsingPosixShm() { return false; }
|
|
||||||
|
|
||||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
|
||||||
DCHECK(size > 0);
|
|
||||||
DCHECK(!mHandle);
|
|
||||||
|
|
||||||
int fd = mozilla::android::ashmem_create(nullptr, size);
|
|
||||||
if (fd < 0) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mHandle.reset(fd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
|
||||||
if (mozilla::android::ashmem_setProt(mHandle.get(), PROT_READ) != 0) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to set ashmem read-only: "
|
|
||||||
<< strerror(errno);
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::UniqueFileHandle ro_file = std::move(mHandle);
|
|
||||||
|
|
||||||
return Some(std::move(ro_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
|
||||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
|
||||||
MOZ_CRASH("can't mprotect()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::SystemProtectFallible(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;
|
|
||||||
|
|
||||||
return 0 == mprotect(aAddr, aSize, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SharedMemory::SystemPageSize() { return sysconf(_SC_PAGESIZE); }
|
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <mach/vm_map.h>
|
|
||||||
#include <mach/mach_port.h>
|
|
||||||
#if defined(XP_IOS)
|
|
||||||
# include <mach/vm_map.h>
|
|
||||||
# define mach_vm_address_t vm_address_t
|
|
||||||
# define mach_vm_map vm_map
|
|
||||||
# define mach_vm_read vm_read
|
|
||||||
# define mach_vm_region_recurse vm_region_recurse_64
|
|
||||||
# define mach_vm_size_t vm_size_t
|
|
||||||
#else
|
|
||||||
# include <mach/mach_vm.h>
|
|
||||||
#endif
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/mman.h> // mprotect
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
|
||||||
# include "prenv.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mozilla/IntegerPrintfMacros.h"
|
|
||||||
#include "mozilla/Printf.h"
|
|
||||||
#include "mozilla/StaticMutex.h"
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
# define LOG_ERROR(str, args...) \
|
|
||||||
PR_BEGIN_MACRO \
|
|
||||||
mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
|
|
||||||
NS_WARNING(msg.get()); \
|
|
||||||
PR_END_MACRO
|
|
||||||
#else
|
|
||||||
# define LOG_ERROR(str, args...) \
|
|
||||||
do { /* nothing */ \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
|
||||||
|
|
||||||
static inline void* toPointer(mach_vm_address_t address) {
|
|
||||||
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline mach_vm_address_t toVMAddress(void* pointer) {
|
|
||||||
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::ResetImpl() {};
|
|
||||||
|
|
||||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
|
||||||
memory_object_size_t memoryObjectSize = round_page(size);
|
|
||||||
|
|
||||||
kern_return_t kr =
|
|
||||||
mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
|
||||||
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
|
||||||
getter_Transfers(mHandle), MACH_PORT_NULL);
|
|
||||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
|
|
||||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
|
|
||||||
mach_error_string(kr), kr);
|
|
||||||
TakeHandle();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<void*> MapMemory(size_t size, void* fixedAddress,
|
|
||||||
const mozilla::UniqueMachSendRight& port,
|
|
||||||
bool readOnly) {
|
|
||||||
kern_return_t kr;
|
|
||||||
mach_vm_address_t address = toVMAddress(fixedAddress);
|
|
||||||
|
|
||||||
vm_prot_t vmProtection = VM_PROT_READ;
|
|
||||||
if (!readOnly) {
|
|
||||||
vmProtection |= VM_PROT_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
kr =
|
|
||||||
mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
|
||||||
fixedAddress ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE, port.get(),
|
|
||||||
0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
|
|
||||||
if (kr != KERN_SUCCESS) {
|
|
||||||
if (!fixedAddress) {
|
|
||||||
LOG_ERROR(
|
|
||||||
"Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
|
||||||
size, mach_task_self(), mach_port_t(port.get()),
|
|
||||||
mach_error_string(kr), kr);
|
|
||||||
}
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixedAddress && fixedAddress != toPointer(address)) {
|
|
||||||
kr = vm_deallocate(mach_task_self(), address, size);
|
|
||||||
if (kr != KERN_SUCCESS) {
|
|
||||||
LOG_ERROR(
|
|
||||||
"Failed to unmap shared memory at unsuitable address "
|
|
||||||
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
|
||||||
size, mach_task_self(), mach_port_t(port.get()),
|
|
||||||
mach_error_string(kr), kr);
|
|
||||||
}
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(toPointer(address));
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<void*> SharedMemory::MapImpl(size_t size, void* fixedAddress) {
|
|
||||||
return MapMemory(size, fixedAddress, mHandle, mReadOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
|
||||||
mach_vm_address_t address = 0;
|
|
||||||
size = round_page(size);
|
|
||||||
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
|
|
||||||
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
|
|
||||||
VM_INHERIT_NONE) != KERN_SUCCESS ||
|
|
||||||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return toPointer(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SharedMemory::CloneHandle(const Handle& aHandle) -> Handle {
|
|
||||||
return mozilla::RetainMachSendRight(aHandle.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
|
||||||
vm_address_t vm_address = toVMAddress(address);
|
|
||||||
kern_return_t kr =
|
|
||||||
vm_deallocate(mach_task_self(), vm_address, round_page(nBytes));
|
|
||||||
if (kr != KERN_SUCCESS) {
|
|
||||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
|
||||||
mach_error_string(kr), kr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
|
||||||
memory_object_size_t memoryObjectSize = round_page(mAllocSize);
|
|
||||||
|
|
||||||
mozilla::UniqueMachSendRight port;
|
|
||||||
|
|
||||||
void* address = mMemory.get();
|
|
||||||
bool unmap = false;
|
|
||||||
|
|
||||||
if (!address) {
|
|
||||||
// Temporarily map memory (as readonly) to get an address.
|
|
||||||
if (auto memory = MapMemory(memoryObjectSize, nullptr, mHandle, true)) {
|
|
||||||
address = *memory;
|
|
||||||
unmap = true;
|
|
||||||
} else {
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_return_t kr = mach_make_memory_entry_64(
|
|
||||||
mach_task_self(), &memoryObjectSize,
|
|
||||||
static_cast<memory_object_offset_t>(reinterpret_cast<uintptr_t>(address)),
|
|
||||||
VM_PROT_READ, getter_Transfers(port), MACH_PORT_NULL);
|
|
||||||
|
|
||||||
if (unmap) {
|
|
||||||
kern_return_t kr =
|
|
||||||
vm_deallocate(mach_task_self(), toVMAddress(address), memoryObjectSize);
|
|
||||||
if (kr != KERN_SUCCESS) {
|
|
||||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
|
||||||
mach_error_string(kr), kr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(mAllocSize)) {
|
|
||||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", mAllocSize,
|
|
||||||
mach_error_string(kr), kr);
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(std::move(port));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
|
||||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
|
||||||
MOZ_CRASH("can't mprotect()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::SystemProtectFallible(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;
|
|
||||||
|
|
||||||
return 0 == mprotect(aAddr, aSize, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
|
||||||
std::atomic<size_t> sPageSizeOverride = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t SharedMemory::SystemPageSize() {
|
|
||||||
#if defined(XP_MACOSX) && defined(__x86_64__)
|
|
||||||
if (sPageSizeOverride == 0) {
|
|
||||||
if (PR_GetEnv("MOZ_SHMEM_PAGESIZE_16K")) {
|
|
||||||
sPageSizeOverride = 16 * 1024;
|
|
||||||
} else {
|
|
||||||
sPageSizeOverride = sysconf(_SC_PAGESIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sPageSizeOverride;
|
|
||||||
#else
|
|
||||||
return sysconf(_SC_PAGESIZE);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
|
||||||
@@ -4,418 +4,21 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* This source code was derived from Chromium code, and as such is also subject
|
#include <sys/mman.h> // mprotect
|
||||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
#include <unistd.h> // sysconf
|
||||||
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "mozilla/ipc/SharedMemory.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||||
#include <fcntl.h>
|
# include "prenv.h"
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifdef XP_LINUX
|
|
||||||
# include "base/linux_memfd_defs.h"
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_WIDGET_GTK
|
|
||||||
# include "mozilla/WidgetUtilsGtk.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
# include <sys/capsicum.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_VALGRIND
|
|
||||||
# include <valgrind/valgrind.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "base/eintr_wrapper.h"
|
|
||||||
#include "base/logging.h"
|
|
||||||
#include "base/string_util.h"
|
|
||||||
#include "mozilla/Atomics.h"
|
|
||||||
#include "mozilla/Maybe.h"
|
|
||||||
#include "mozilla/ProfilerThreadSleep.h"
|
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
|
||||||
#include "prenv.h"
|
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
void SharedMemory::ResetImpl() {
|
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||||
if (mFrozenFile) {
|
std::atomic<size_t> sPageSizeOverride = 0;
|
||||||
CHROMIUM_LOG(WARNING) << "freezable shared memory was never frozen";
|
|
||||||
mFrozenFile = nullptr;
|
|
||||||
}
|
|
||||||
mIsMemfd = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
SharedMemory::Handle SharedMemory::CloneHandle(const Handle& aHandle) {
|
|
||||||
const int new_fd = dup(aHandle.get());
|
|
||||||
if (new_fd < 0) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
|
|
||||||
<< strerror(errno);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return mozilla::UniqueFileHandle(new_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
|
||||||
void* memory = mmap(nullptr, size, PROT_NONE,
|
|
||||||
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
|
||||||
if (memory == MAP_FAILED) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
munmap(memory, size);
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<void*> SharedMemory::MapImpl(size_t nBytes, void* fixedAddress) {
|
|
||||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
|
||||||
// replace pages that are alread mapped at that address.
|
|
||||||
void* mem =
|
|
||||||
mmap(fixedAddress, nBytes, PROT_READ | (mReadOnly ? 0 : PROT_WRITE),
|
|
||||||
MAP_SHARED, mHandle.get(), 0);
|
|
||||||
|
|
||||||
if (mem == MAP_FAILED) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixedAddress && mem != fixedAddress) {
|
|
||||||
bool munmap_succeeded = munmap(mem, nBytes) == 0;
|
|
||||||
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
|
||||||
munmap(address, nBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// memfd_create is a nonstandard interface for creating anonymous
|
|
||||||
// shared memory accessible as a file descriptor but not tied to any
|
|
||||||
// filesystem. It first appeared in Linux 3.17, and was adopted by
|
|
||||||
// FreeBSD in version 13.
|
|
||||||
|
|
||||||
#if !defined(HAVE_MEMFD_CREATE) && defined(XP_LINUX) && \
|
|
||||||
defined(SYS_memfd_create)
|
|
||||||
|
|
||||||
// Older libc versions (e.g., glibc before 2.27) don't have the
|
|
||||||
// wrapper, but we can supply our own; see `linux_memfd_defs.h`.
|
|
||||||
|
|
||||||
static int memfd_create(const char* name, unsigned int flags) {
|
|
||||||
return syscall(SYS_memfd_create, name, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
# define HAVE_MEMFD_CREATE 1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// memfd supports having "seals" applied to the file, to prevent
|
|
||||||
// various types of changes (which apply to all fds referencing the
|
|
||||||
// file). Unfortunately, we can't rely on F_SEAL_WRITE to implement
|
|
||||||
// Freeze(); see the comments in ReadOnlyCopy() below.
|
|
||||||
//
|
|
||||||
// Instead, to prevent a child process from regaining write access to
|
|
||||||
// a read-only copy, the OS must also provide a way to remove write
|
|
||||||
// permissions at the file descriptor level. This next section
|
|
||||||
// attempts to accomplish that.
|
|
||||||
|
|
||||||
#ifdef HAVE_MEMFD_CREATE
|
|
||||||
# ifdef XP_LINUX
|
|
||||||
# define USE_MEMFD_CREATE 1
|
|
||||||
|
|
||||||
// To create a read-only duplicate of an fd, we can use procfs; the
|
|
||||||
// same operation could restore write access, but sandboxing prevents
|
|
||||||
// child processes from accessing /proc.
|
|
||||||
//
|
|
||||||
// (Note: if this ever changes to not use /proc, also reconsider how
|
|
||||||
// and if HaveMemfd should check whether this works.)
|
|
||||||
|
|
||||||
static int DupReadOnly(int fd) {
|
|
||||||
std::string path = StringPrintf("/proc/self/fd/%d", fd);
|
|
||||||
// procfs opens probably won't EINTR, but checking for it can't hurt
|
|
||||||
return HANDLE_EINTR(open(path.c_str(), O_RDONLY | O_CLOEXEC));
|
|
||||||
}
|
|
||||||
|
|
||||||
# elif defined(__FreeBSD__)
|
|
||||||
# define USE_MEMFD_CREATE 1
|
|
||||||
|
|
||||||
// FreeBSD's Capsicum framework allows irrevocably restricting the
|
|
||||||
// operations permitted on a file descriptor.
|
|
||||||
|
|
||||||
static int DupReadOnly(int fd) {
|
|
||||||
int rofd = dup(fd);
|
|
||||||
if (rofd < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cap_rights_t rights;
|
|
||||||
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R);
|
|
||||||
if (cap_rights_limit(rofd, &rights) < 0) {
|
|
||||||
int err = errno;
|
|
||||||
close(rofd);
|
|
||||||
errno = err;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rofd;
|
|
||||||
}
|
|
||||||
|
|
||||||
# else // unhandled OS
|
|
||||||
# warning "OS has memfd_create but no DupReadOnly implementation"
|
|
||||||
# endif // OS selection
|
|
||||||
#endif // HAVE_MEMFD_CREATE
|
|
||||||
|
|
||||||
// Runtime detection for memfd support.
|
|
||||||
static bool HaveMemfd() {
|
|
||||||
#ifdef USE_MEMFD_CREATE
|
|
||||||
static const bool kHave = [] {
|
|
||||||
mozilla::UniqueFileHandle fd(
|
|
||||||
memfd_create("mozilla-ipc-test", MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
|
||||||
if (!fd) {
|
|
||||||
DCHECK_EQ(errno, ENOSYS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that DupReadOnly works; on Linux it's known to fail if:
|
|
||||||
//
|
|
||||||
// * SELinux assigns the memfd a type for which this process's
|
|
||||||
// domain doesn't have "open" permission; this is always the
|
|
||||||
// case on Android but could occur on desktop as well
|
|
||||||
//
|
|
||||||
// * /proc (used by the DupReadOnly implementation) isn't mounted,
|
|
||||||
// which is a configuration that the Tor Browser project is
|
|
||||||
// interested in as a way to reduce fingerprinting risk
|
|
||||||
//
|
|
||||||
// Sandboxed processes on Linux also can't use it if sandboxing
|
|
||||||
// has already been started, but that's expected. It should be
|
|
||||||
// safe for sandboxed child processes to use memfd even if an
|
|
||||||
// unsandboxed process couldn't freeze them, because freezing
|
|
||||||
// isn't allowed (or meaningful) for memory created by another
|
|
||||||
// process.
|
|
||||||
|
|
||||||
if (!PR_GetEnv("MOZ_SANDBOXED")) {
|
|
||||||
mozilla::UniqueFileHandle rofd(DupReadOnly(fd.get()));
|
|
||||||
if (!rofd) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "read-only dup failed (" << strerror(errno)
|
|
||||||
<< "); not using memfd";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}();
|
|
||||||
return kHave;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif // USE_MEMFD_CREATE
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
|
|
||||||
if (HaveMemfd()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*str += '/';
|
|
||||||
#ifdef MOZ_WIDGET_GTK
|
|
||||||
// The Snap package environment doesn't provide a private /dev/shm
|
|
||||||
// (it's used for communication with services like PulseAudio);
|
|
||||||
// instead AppArmor is used to restrict access to it. Anything with
|
|
||||||
// this prefix is allowed:
|
|
||||||
if (const char* snap = mozilla::widget::GetSnapInstanceName()) {
|
|
||||||
StringAppendF(str, "snap.%s.", snap);
|
|
||||||
}
|
|
||||||
#endif // XP_LINUX
|
|
||||||
// Hopefully the "implementation defined" name length limit is long
|
|
||||||
// enough for this.
|
|
||||||
StringAppendF(str, "org.mozilla.ipc.%d.", static_cast<int>(pid));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
|
||||||
DCHECK(size > 0);
|
|
||||||
DCHECK(!mHandle);
|
|
||||||
DCHECK(!mFrozenFile);
|
|
||||||
|
|
||||||
mozilla::UniqueFileHandle fd;
|
|
||||||
mozilla::UniqueFileHandle frozen_fd;
|
|
||||||
bool is_memfd = false;
|
|
||||||
|
|
||||||
#ifdef USE_MEMFD_CREATE
|
|
||||||
if (HaveMemfd()) {
|
|
||||||
const unsigned flags = MFD_CLOEXEC | (freezable ? MFD_ALLOW_SEALING : 0);
|
|
||||||
fd.reset(memfd_create("mozilla-ipc", flags));
|
|
||||||
if (!fd) {
|
|
||||||
// In general it's too late to fall back here -- in a sandboxed
|
|
||||||
// child process, shm_open is already blocked. And it shouldn't
|
|
||||||
// be necessary.
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to create memfd: " << strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
is_memfd = true;
|
|
||||||
if (freezable) {
|
|
||||||
frozen_fd.reset(DupReadOnly(fd.get()));
|
|
||||||
if (!frozen_fd) {
|
|
||||||
CHROMIUM_LOG(WARNING)
|
|
||||||
<< "failed to create read-only memfd: " << strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!fd) {
|
|
||||||
// Generic Unix: shm_open + shm_unlink
|
|
||||||
do {
|
|
||||||
// The names don't need to be unique, but it saves time if they
|
|
||||||
// usually are.
|
|
||||||
static mozilla::Atomic<size_t> sNameCounter;
|
|
||||||
std::string name;
|
|
||||||
CHECK(AppendPosixShmPrefix(&name, getpid()));
|
|
||||||
StringAppendF(&name, "%zu", sNameCounter++);
|
|
||||||
// O_EXCL means the names being predictable shouldn't be a problem.
|
|
||||||
fd.reset(HANDLE_EINTR(
|
|
||||||
shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)));
|
|
||||||
if (fd) {
|
|
||||||
if (freezable) {
|
|
||||||
frozen_fd.reset(HANDLE_EINTR(shm_open(name.c_str(), O_RDONLY, 0400)));
|
|
||||||
if (!frozen_fd) {
|
|
||||||
int open_err = errno;
|
|
||||||
shm_unlink(name.c_str());
|
|
||||||
DLOG(FATAL) << "failed to re-open freezable shm: "
|
|
||||||
<< strerror(open_err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shm_unlink(name.c_str()) != 0) {
|
|
||||||
// This shouldn't happen, but if it does: assume the file is
|
|
||||||
// in fact leaked, and bail out now while it's still 0-length.
|
|
||||||
DLOG(FATAL) << "failed to unlink shm: " << strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (!fd && errno == EEXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fd) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::Maybe<int> fallocateError;
|
|
||||||
#if defined(HAVE_POSIX_FALLOCATE)
|
|
||||||
// Using posix_fallocate will ensure that there's actually space for this
|
|
||||||
// file. Otherwise we end up with a sparse file that can give SIGBUS if we
|
|
||||||
// run out of space while writing to it. (This doesn't apply to memfd.)
|
|
||||||
if (!is_memfd) {
|
|
||||||
int rv;
|
|
||||||
// Avoid repeated interruptions of posix_fallocate by the profiler's
|
|
||||||
// SIGPROF sampling signal. Indicating "thread sleep" here means we'll
|
|
||||||
// get up to one interruption but not more. See bug 1658847 for more.
|
|
||||||
// This has to be scoped outside the HANDLE_RV_EINTR retry loop.
|
|
||||||
{
|
|
||||||
AUTO_PROFILER_THREAD_SLEEP;
|
|
||||||
|
|
||||||
rv = HANDLE_RV_EINTR(
|
|
||||||
posix_fallocate(fd.get(), 0, static_cast<off_t>(size)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some filesystems have trouble with posix_fallocate. For now, we must
|
|
||||||
// fallback ftruncate and accept the allocation failures like we do
|
|
||||||
// without posix_fallocate.
|
|
||||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1618914
|
|
||||||
if (rv != 0 && rv != EOPNOTSUPP && rv != EINVAL && rv != ENODEV) {
|
|
||||||
CHROMIUM_LOG(WARNING)
|
|
||||||
<< "fallocate failed to set shm size: " << strerror(rv);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fallocateError = mozilla::Some(rv);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If posix_fallocate isn't supported / relevant for this type of
|
|
||||||
// file (either failed with an expected error, or wasn't attempted),
|
|
||||||
// then set the size with ftruncate:
|
|
||||||
if (fallocateError != mozilla::Some(0)) {
|
|
||||||
int rv = HANDLE_EINTR(ftruncate(fd.get(), static_cast<off_t>(size)));
|
|
||||||
if (rv != 0) {
|
|
||||||
int ftruncate_errno = errno;
|
|
||||||
if (fallocateError) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "fallocate failed to set shm size: "
|
|
||||||
<< strerror(*fallocateError);
|
|
||||||
}
|
|
||||||
CHROMIUM_LOG(WARNING)
|
|
||||||
<< "ftruncate failed to set shm size: " << strerror(ftruncate_errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mHandle = std::move(fd);
|
|
||||||
mFrozenFile = std::move(frozen_fd);
|
|
||||||
mIsMemfd = is_memfd;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
|
||||||
#ifdef USE_MEMFD_CREATE
|
|
||||||
# ifdef MOZ_VALGRIND
|
|
||||||
// Valgrind allows memfd_create but doesn't understand F_ADD_SEALS.
|
|
||||||
static const bool haveSeals = RUNNING_ON_VALGRIND == 0;
|
|
||||||
# else
|
|
||||||
static const bool haveSeals = true;
|
|
||||||
# endif
|
|
||||||
static const bool useSeals = !PR_GetEnv("MOZ_SHM_NO_SEALS");
|
|
||||||
if (mIsMemfd && haveSeals && useSeals) {
|
|
||||||
// Seals are added to the file as defense-in-depth. The primary
|
|
||||||
// method of access control is creating a read-only fd (using
|
|
||||||
// procfs in this case) and requiring that sandboxes processes not
|
|
||||||
// have access to /proc/self/fd to regain write permission; this
|
|
||||||
// is the same as with shm_open.
|
|
||||||
//
|
|
||||||
// Unfortunately, F_SEAL_WRITE is unreliable: if the process
|
|
||||||
// forked while there was a writeable mapping, it will inherit a
|
|
||||||
// copy of the mapping, which causes the seal to fail.
|
|
||||||
//
|
|
||||||
// (Also, in the future we may want to split this into separate
|
|
||||||
// classes for mappings and shared memory handles, which would
|
|
||||||
// complicate identifying the case where `F_SEAL_WRITE` would be
|
|
||||||
// possible even in the absence of races with fork.)
|
|
||||||
//
|
|
||||||
// However, Linux 5.1 added F_SEAL_FUTURE_WRITE, which prevents
|
|
||||||
// write operations afterwards, but existing writeable mappings
|
|
||||||
// are unaffected (similar to ashmem protection semantics).
|
|
||||||
|
|
||||||
const int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
|
|
||||||
int sealError = EINVAL;
|
|
||||||
|
|
||||||
# ifdef F_SEAL_FUTURE_WRITE
|
|
||||||
sealError =
|
|
||||||
fcntl(mHandle.get(), F_ADD_SEALS, seals | F_SEAL_FUTURE_WRITE) == 0
|
|
||||||
? 0
|
|
||||||
: errno;
|
|
||||||
# endif // F_SEAL_FUTURE_WRITE
|
|
||||||
if (sealError == EINVAL) {
|
|
||||||
sealError = fcntl(mHandle.get(), F_ADD_SEALS, seals) == 0 ? 0 : errno;
|
|
||||||
}
|
|
||||||
if (sealError != 0) {
|
|
||||||
CHROMIUM_LOG(WARNING) << "failed to seal memfd: " << strerror(errno);
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else // !USE_MEMFD_CREATE
|
|
||||||
DCHECK(!mIsMemfd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DCHECK(mFrozenFile);
|
|
||||||
DCHECK(mHandle);
|
|
||||||
mozilla::UniqueFileHandle ro_file = std::move(mFrozenFile);
|
|
||||||
|
|
||||||
DCHECK(ro_file);
|
|
||||||
|
|
||||||
return Some(std::move(ro_file));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||||
MOZ_CRASH("can't mprotect()");
|
MOZ_CRASH("can't mprotect()");
|
||||||
@@ -432,8 +35,19 @@ bool SharedMemory::SystemProtectFallible(char* aAddr, size_t aSize,
|
|||||||
return 0 == mprotect(aAddr, aSize, flags);
|
return 0 == mprotect(aAddr, aSize, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SharedMemory::SystemPageSize() { return sysconf(_SC_PAGESIZE); }
|
size_t SharedMemory::SystemPageSize() {
|
||||||
|
#if defined(XP_MACOSX) && defined(__x86_64__)
|
||||||
bool SharedMemory::UsingPosixShm() { return !HaveMemfd(); }
|
if (sPageSizeOverride == 0) {
|
||||||
|
if (PR_GetEnv("MOZ_SHMEM_PAGESIZE_16K")) {
|
||||||
|
sPageSizeOverride = 16 * 1024;
|
||||||
|
} else {
|
||||||
|
sPageSizeOverride = sysconf(_SC_PAGESIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sPageSizeOverride;
|
||||||
|
#else
|
||||||
|
return sysconf(_SC_PAGESIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
} // namespace mozilla::ipc
|
||||||
|
|||||||
@@ -4,211 +4,12 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* This source code was derived from Chromium code, and as such is also subject
|
|
||||||
* to the [Chromium license](ipc/chromium/src/LICENSE). */
|
|
||||||
|
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "mozilla/ipc/SharedMemory.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include "base/logging.h"
|
|
||||||
#include "base/win_util.h"
|
|
||||||
#include "base/string_util.h"
|
|
||||||
#include "mozilla/ipc/ProtocolUtils.h"
|
|
||||||
#include "mozilla/RandomNum.h"
|
|
||||||
#include "nsDebug.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#ifdef MOZ_MEMORY
|
|
||||||
# include "mozmemory_utils.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// NtQuerySection is an internal (but believed to be stable) API and the
|
|
||||||
// structures it uses are defined in nt_internals.h.
|
|
||||||
// So we have to define them ourselves.
|
|
||||||
typedef enum _SECTION_INFORMATION_CLASS {
|
|
||||||
SectionBasicInformation,
|
|
||||||
} SECTION_INFORMATION_CLASS;
|
|
||||||
|
|
||||||
typedef struct _SECTION_BASIC_INFORMATION {
|
|
||||||
PVOID BaseAddress;
|
|
||||||
ULONG Attributes;
|
|
||||||
LARGE_INTEGER Size;
|
|
||||||
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
|
||||||
|
|
||||||
typedef ULONG(__stdcall* NtQuerySectionType)(
|
|
||||||
HANDLE SectionHandle, SECTION_INFORMATION_CLASS SectionInformationClass,
|
|
||||||
PVOID SectionInformation, ULONG SectionInformationLength,
|
|
||||||
PULONG ResultLength);
|
|
||||||
|
|
||||||
// Checks if the section object is safe to map. At the moment this just means
|
|
||||||
// it's not an image section.
|
|
||||||
bool IsSectionSafeToMap(HANDLE handle) {
|
|
||||||
static NtQuerySectionType nt_query_section_func =
|
|
||||||
reinterpret_cast<NtQuerySectionType>(
|
|
||||||
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
|
|
||||||
DCHECK(nt_query_section_func);
|
|
||||||
|
|
||||||
// The handle must have SECTION_QUERY access for this to succeed.
|
|
||||||
SECTION_BASIC_INFORMATION basic_information = {};
|
|
||||||
ULONG status =
|
|
||||||
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
|
|
||||||
sizeof(basic_information), nullptr);
|
|
||||||
if (status) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace mozilla::ipc {
|
namespace mozilla::ipc {
|
||||||
|
|
||||||
void SharedMemory::ResetImpl() {};
|
|
||||||
|
|
||||||
SharedMemory::Handle SharedMemory::CloneHandle(const Handle& aHandle) {
|
|
||||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
|
||||||
if (DuplicateHandle(GetCurrentProcess(), aHandle.get(), GetCurrentProcess(),
|
|
||||||
&handle, 0, false, DUPLICATE_SAME_ACCESS)) {
|
|
||||||
return SharedMemoryHandle(handle);
|
|
||||||
}
|
|
||||||
NS_WARNING("DuplicateHandle Failed!");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
|
||||||
void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
|
||||||
if (memory) {
|
|
||||||
VirtualFree(memory, 0, MEM_RELEASE);
|
|
||||||
}
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<void*> SharedMemory::MapImpl(size_t nBytes, void* fixedAddress) {
|
|
||||||
if (mExternalHandle && !IsSectionSafeToMap(mHandle.get())) {
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mem = MapViewOfFileEx(
|
|
||||||
mHandle.get(), mReadOnly ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
|
|
||||||
0, 0, nBytes, fixedAddress);
|
|
||||||
if (mem) {
|
|
||||||
MOZ_ASSERT(!fixedAddress || mem == fixedAddress,
|
|
||||||
"MapViewOfFileEx returned an expected address");
|
|
||||||
return Some(mem);
|
|
||||||
}
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::UnmapImpl(size_t nBytes, void* address) {
|
|
||||||
UnmapViewOfFile(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper around CreateFileMappingW for pagefile-backed regions. When out of
|
|
||||||
// memory, may attempt to stall and retry rather than returning immediately, in
|
|
||||||
// hopes that the page file is about to be expanded by Windows. (bug 1822383,
|
|
||||||
// bug 1716727)
|
|
||||||
//
|
|
||||||
// This method is largely a copy of the MozVirtualAlloc method from
|
|
||||||
// mozjemalloc.cpp, which implements this strategy for VirtualAlloc calls,
|
|
||||||
// except re-purposed to handle CreateFileMapping.
|
|
||||||
static HANDLE MozCreateFileMappingW(
|
|
||||||
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
|
|
||||||
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) {
|
|
||||||
#ifdef MOZ_MEMORY
|
|
||||||
constexpr auto IsOOMError = [] {
|
|
||||||
return ::GetLastError() == ERROR_COMMITMENT_LIMIT;
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
HANDLE handle = ::CreateFileMappingW(
|
|
||||||
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
|
||||||
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
|
||||||
if (MOZ_LIKELY(handle)) {
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
|
||||||
"::CreateFileMapping should return NULL, not "
|
|
||||||
"INVALID_HANDLE_VALUE, on failure");
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't do anything for errors other than OOM.
|
|
||||||
if (!IsOOMError()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retry as many times as desired (possibly zero).
|
|
||||||
const mozilla::StallSpecs stallSpecs = mozilla::GetAllocatorStallSpecs();
|
|
||||||
|
|
||||||
const auto ret =
|
|
||||||
stallSpecs.StallAndRetry(&::Sleep, [&]() -> std::optional<HANDLE> {
|
|
||||||
HANDLE handle = ::CreateFileMappingW(
|
|
||||||
INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
|
|
||||||
dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
|
|
||||||
|
|
||||||
if (handle) {
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
|
|
||||||
"::CreateFileMapping should return NULL, not "
|
|
||||||
"INVALID_HANDLE_VALUE, on failure");
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failure for some reason other than OOM.
|
|
||||||
if (!IsOOMError()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret.value_or(nullptr);
|
|
||||||
#else
|
|
||||||
return ::CreateFileMappingW(INVALID_HANDLE_VALUE, lpFileMappingAttributes,
|
|
||||||
flProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
|
|
||||||
lpName);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::CreateImpl(size_t size, bool freezable) {
|
|
||||||
// If the shared memory object has no DACL, any process can
|
|
||||||
// duplicate its handles with any access rights; e.g., re-add write
|
|
||||||
// access to a read-only handle. To prevent that, we give it an
|
|
||||||
// empty DACL, so that no process can do that.
|
|
||||||
SECURITY_ATTRIBUTES sa, *psa = nullptr;
|
|
||||||
SECURITY_DESCRIPTOR sd;
|
|
||||||
ACL dacl;
|
|
||||||
|
|
||||||
if (freezable) {
|
|
||||||
psa = &sa;
|
|
||||||
sa.nLength = sizeof(sa);
|
|
||||||
sa.lpSecurityDescriptor = &sd;
|
|
||||||
sa.bInheritHandle = FALSE;
|
|
||||||
|
|
||||||
if (NS_WARN_IF(!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) ||
|
|
||||||
NS_WARN_IF(
|
|
||||||
!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ||
|
|
||||||
NS_WARN_IF(!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mHandle.reset(MozCreateFileMappingW(psa, PAGE_READWRITE, 0,
|
|
||||||
static_cast<DWORD>(size), nullptr));
|
|
||||||
return (bool)mHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<SharedMemory::Handle> SharedMemory::ReadOnlyCopyImpl() {
|
|
||||||
HANDLE ro_handle;
|
|
||||||
if (!::DuplicateHandle(GetCurrentProcess(), mHandle.get(),
|
|
||||||
GetCurrentProcess(), &ro_handle,
|
|
||||||
GENERIC_READ | FILE_MAP_READ, false, 0)) {
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(ro_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||||
MOZ_CRASH("can't VirtualProtect()");
|
MOZ_CRASH("can't VirtualProtect()");
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "base/process.h"
|
#include "base/process.h"
|
||||||
#include "chrome/common/ipc_message_utils.h"
|
|
||||||
|
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
|
|||||||
@@ -79,7 +79,14 @@ EXPORTS.mozilla.ipc += [
|
|||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG["OS_ARCH"] == "WINNT":
|
if CONFIG["OS_ARCH"] == "WINNT":
|
||||||
SOURCES += ["WindowsMessageLoop.cpp"]
|
SOURCES += [
|
||||||
|
"SharedMemory_windows.cpp",
|
||||||
|
"WindowsMessageLoop.cpp",
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
UNIFIED_SOURCES += [
|
||||||
|
"SharedMemory_posix.cpp",
|
||||||
|
]
|
||||||
|
|
||||||
if CONFIG["OS_ARCH"] == "WINNT":
|
if CONFIG["OS_ARCH"] == "WINNT":
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
@@ -108,14 +115,11 @@ else:
|
|||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG["OS_ARCH"] == "Darwin":
|
if CONFIG["OS_ARCH"] == "Darwin":
|
||||||
SOURCES += ["SharedMemory_mach.cpp"]
|
EXPORTS.mozilla.ipc += ["SharedMemoryImpl_mach.h"]
|
||||||
elif CONFIG["OS_ARCH"] == "WINNT":
|
SOURCES += ["SharedMemoryImpl_mach.cpp"]
|
||||||
SOURCES += ["SharedMemory_windows.cpp"]
|
|
||||||
elif CONFIG["OS_TARGET"] == "Android":
|
|
||||||
SOURCES += ["SharedMemory_android.cpp"]
|
|
||||||
else:
|
else:
|
||||||
SOURCES += ["SharedMemory_posix.cpp"]
|
EXPORTS.mozilla.ipc += ["SharedMemoryImpl_chromium.h"]
|
||||||
|
SOURCES += ["SharedMemoryImpl_chromium.cpp"]
|
||||||
|
|
||||||
if CONFIG["OS_ARCH"] == "Linux":
|
if CONFIG["OS_ARCH"] == "Linux":
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
#include "mozilla/ipc/SharedMemory.h"
|
||||||
|
|
||||||
@@ -28,29 +30,28 @@ namespace mozilla {
|
|||||||
// compromised and then receives a frozen handle.
|
// compromised and then receives a frozen handle.
|
||||||
TEST(IPCSharedMemory, FreezeAndMapRW)
|
TEST(IPCSharedMemory, FreezeAndMapRW)
|
||||||
{
|
{
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shm;
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shm->Map(1));
|
ASSERT_TRUE(shm.Map(1));
|
||||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||||
ASSERT_TRUE(mem);
|
ASSERT_TRUE(mem);
|
||||||
*mem = 'A';
|
*mem = 'A';
|
||||||
|
|
||||||
// Freeze
|
// Freeze
|
||||||
ASSERT_TRUE(shm->Freeze());
|
ASSERT_TRUE(shm.Freeze());
|
||||||
ASSERT_FALSE(shm->Memory());
|
ASSERT_FALSE(shm.memory());
|
||||||
|
|
||||||
// Re-create as writeable
|
// Re-create as writeable
|
||||||
auto handle = shm->TakeHandleAndUnmap();
|
auto handle = shm.TakeHandle();
|
||||||
ASSERT_TRUE(shm->IsHandleValid(handle));
|
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||||
ASSERT_FALSE(shm->IsValid());
|
ASSERT_FALSE(shm.IsValid());
|
||||||
ASSERT_TRUE(shm->SetHandle(std::move(handle),
|
ASSERT_TRUE(shm.SetHandle(std::move(handle), /* read-only */ false));
|
||||||
ipc::SharedMemory::OpenRights::RightsReadWrite));
|
ASSERT_TRUE(shm.IsValid());
|
||||||
ASSERT_TRUE(shm->IsValid());
|
|
||||||
|
|
||||||
// This should fail
|
// This should fail
|
||||||
EXPECT_FALSE(shm->Map(1));
|
EXPECT_FALSE(shm.Map(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to restore write permissions to a frozen mapping. Threat
|
// Try to restore write permissions to a frozen mapping. Threat
|
||||||
@@ -59,22 +60,22 @@ TEST(IPCSharedMemory, FreezeAndMapRW)
|
|||||||
// proof-of-concept at https://crbug.com/project-zero/1671 ).
|
// proof-of-concept at https://crbug.com/project-zero/1671 ).
|
||||||
TEST(IPCSharedMemory, FreezeAndReprotect)
|
TEST(IPCSharedMemory, FreezeAndReprotect)
|
||||||
{
|
{
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shm;
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shm->Map(1));
|
ASSERT_TRUE(shm.Map(1));
|
||||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||||
ASSERT_TRUE(mem);
|
ASSERT_TRUE(mem);
|
||||||
*mem = 'A';
|
*mem = 'A';
|
||||||
|
|
||||||
// Freeze
|
// Freeze
|
||||||
ASSERT_TRUE(shm->Freeze());
|
ASSERT_TRUE(shm.Freeze());
|
||||||
ASSERT_FALSE(shm->Memory());
|
ASSERT_FALSE(shm.memory());
|
||||||
|
|
||||||
// Re-map
|
// Re-map
|
||||||
ASSERT_TRUE(shm->Map(1));
|
ASSERT_TRUE(shm.Map(1));
|
||||||
mem = reinterpret_cast<char*>(shm->Memory());
|
mem = reinterpret_cast<char*>(shm.memory());
|
||||||
ASSERT_EQ(*mem, 'A');
|
ASSERT_EQ(*mem, 'A');
|
||||||
|
|
||||||
// Try to alter protection; should fail
|
// Try to alter protection; should fail
|
||||||
@@ -82,39 +83,32 @@ TEST(IPCSharedMemory, FreezeAndReprotect)
|
|||||||
mem, 1, ipc::SharedMemory::RightsReadWrite));
|
mem, 1, ipc::SharedMemory::RightsReadWrite));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(XP_WIN) && !defined(XP_DARWIN)
|
#ifndef XP_WIN
|
||||||
// This essentially tests whether FreezeAndReprotect would have failed
|
// This essentially tests whether FreezeAndReprotect would have failed
|
||||||
// without the freeze.
|
// without the freeze. It doesn't work on Windows: VirtualProtect
|
||||||
//
|
// can't exceed the permissions set in MapViewOfFile regardless of the
|
||||||
// It doesn't work on Windows: VirtualProtect can't exceed the permissions set
|
// security status of the original handle.
|
||||||
// in MapViewOfFile regardless of the security status of the original handle.
|
|
||||||
//
|
|
||||||
// It doesn't work on MacOS: we can set a higher max_protection for the memory
|
|
||||||
// when creating the handle, but we wouldn't want to do this for freezable
|
|
||||||
// handles (to prevent creating additional RW mappings that break the memory
|
|
||||||
// freezing invariants).
|
|
||||||
TEST(IPCSharedMemory, Reprotect)
|
TEST(IPCSharedMemory, Reprotect)
|
||||||
{
|
{
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shm;
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shm->Map(1));
|
ASSERT_TRUE(shm.Map(1));
|
||||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||||
ASSERT_TRUE(mem);
|
ASSERT_TRUE(mem);
|
||||||
*mem = 'A';
|
*mem = 'A';
|
||||||
|
|
||||||
// Re-create as read-only
|
// Re-create as read-only
|
||||||
auto handle = shm->TakeHandleAndUnmap();
|
auto handle = shm.TakeHandle();
|
||||||
ASSERT_TRUE(shm->IsHandleValid(handle));
|
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||||
ASSERT_FALSE(shm->IsValid());
|
ASSERT_FALSE(shm.IsValid());
|
||||||
ASSERT_TRUE(shm->SetHandle(std::move(handle),
|
ASSERT_TRUE(shm.SetHandle(std::move(handle), /* read-only */ true));
|
||||||
ipc::SharedMemory::OpenRights::RightsReadOnly));
|
ASSERT_TRUE(shm.IsValid());
|
||||||
ASSERT_TRUE(shm->IsValid());
|
|
||||||
|
|
||||||
// Re-map
|
// Re-map
|
||||||
ASSERT_TRUE(shm->Map(1));
|
ASSERT_TRUE(shm.Map(1));
|
||||||
mem = reinterpret_cast<char*>(shm->Memory());
|
mem = reinterpret_cast<char*>(shm.memory());
|
||||||
ASSERT_EQ(*mem, 'A');
|
ASSERT_EQ(*mem, 'A');
|
||||||
|
|
||||||
// Try to alter protection; should succeed, because not frozen
|
// Try to alter protection; should succeed, because not frozen
|
||||||
@@ -129,23 +123,23 @@ TEST(IPCSharedMemory, Reprotect)
|
|||||||
// See also https://crbug.com/338538
|
// See also https://crbug.com/338538
|
||||||
TEST(IPCSharedMemory, WinUnfreeze)
|
TEST(IPCSharedMemory, WinUnfreeze)
|
||||||
{
|
{
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shm;
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shm->CreateFreezable(1));
|
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shm->Map(1));
|
ASSERT_TRUE(shm.Map(1));
|
||||||
auto* mem = reinterpret_cast<char*>(shm->Memory());
|
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||||
ASSERT_TRUE(mem);
|
ASSERT_TRUE(mem);
|
||||||
*mem = 'A';
|
*mem = 'A';
|
||||||
|
|
||||||
// Freeze
|
// Freeze
|
||||||
ASSERT_TRUE(shm->Freeze());
|
ASSERT_TRUE(shm.Freeze());
|
||||||
ASSERT_FALSE(shm->Memory());
|
ASSERT_FALSE(shm.memory());
|
||||||
|
|
||||||
// Extract handle.
|
// Extract handle.
|
||||||
auto handle = shm->TakeHandleAndUnmap();
|
auto handle = shm.TakeHandle();
|
||||||
ASSERT_TRUE(shm->IsHandleValid(handle));
|
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||||
ASSERT_FALSE(shm->IsValid());
|
ASSERT_FALSE(shm.IsValid());
|
||||||
|
|
||||||
// Unfreeze.
|
// Unfreeze.
|
||||||
HANDLE newHandle = INVALID_HANDLE_VALUE;
|
HANDLE newHandle = INVALID_HANDLE_VALUE;
|
||||||
@@ -160,25 +154,24 @@ TEST(IPCSharedMemory, WinUnfreeze)
|
|||||||
// mapping in the case that the page wasn't accessed before the copy.
|
// mapping in the case that the page wasn't accessed before the copy.
|
||||||
TEST(IPCSharedMemory, ROCopyAndWrite)
|
TEST(IPCSharedMemory, ROCopyAndWrite)
|
||||||
{
|
{
|
||||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shmRW, shmRO;
|
||||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shmRW->Map(1));
|
ASSERT_TRUE(shmRW.Map(1));
|
||||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||||
ASSERT_TRUE(memRW);
|
ASSERT_TRUE(memRW);
|
||||||
|
|
||||||
// Create read-only copy
|
// Create read-only copy
|
||||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||||
EXPECT_FALSE(shmRW->IsValid());
|
EXPECT_FALSE(shmRW.IsValid());
|
||||||
ASSERT_EQ(shmRW->Memory(), memRW);
|
ASSERT_EQ(shmRW.memory(), memRW);
|
||||||
ASSERT_EQ(shmRO->MaxSize(), size_t(1));
|
ASSERT_EQ(shmRO.max_size(), size_t(1));
|
||||||
|
|
||||||
// Map read-only
|
// Map read-only
|
||||||
ASSERT_TRUE(shmRO->IsValid());
|
ASSERT_TRUE(shmRO.IsValid());
|
||||||
ASSERT_TRUE(shmRO->Map(1));
|
ASSERT_TRUE(shmRO.Map(1));
|
||||||
const auto* memRO = reinterpret_cast<const char*>(shmRO->Memory());
|
auto memRO = reinterpret_cast<const char*>(shmRO.memory());
|
||||||
ASSERT_TRUE(memRO);
|
ASSERT_TRUE(memRO);
|
||||||
ASSERT_NE(memRW, memRO);
|
ASSERT_NE(memRW, memRO);
|
||||||
|
|
||||||
@@ -192,26 +185,25 @@ TEST(IPCSharedMemory, ROCopyAndWrite)
|
|||||||
// (and, before that, sees the state as of when the copy was made).
|
// (and, before that, sees the state as of when the copy was made).
|
||||||
TEST(IPCSharedMemory, ROCopyAndRewrite)
|
TEST(IPCSharedMemory, ROCopyAndRewrite)
|
||||||
{
|
{
|
||||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shmRW, shmRO;
|
||||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shmRW->Map(1));
|
ASSERT_TRUE(shmRW.Map(1));
|
||||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||||
ASSERT_TRUE(memRW);
|
ASSERT_TRUE(memRW);
|
||||||
*memRW = 'A';
|
*memRW = 'A';
|
||||||
|
|
||||||
// Create read-only copy
|
// Create read-only copy
|
||||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||||
EXPECT_FALSE(shmRW->IsValid());
|
EXPECT_FALSE(shmRW.IsValid());
|
||||||
ASSERT_EQ(shmRW->Memory(), memRW);
|
ASSERT_EQ(shmRW.memory(), memRW);
|
||||||
ASSERT_EQ(shmRO->MaxSize(), size_t(1));
|
ASSERT_EQ(shmRO.max_size(), size_t(1));
|
||||||
|
|
||||||
// Map read-only
|
// Map read-only
|
||||||
ASSERT_TRUE(shmRO->IsValid());
|
ASSERT_TRUE(shmRO.IsValid());
|
||||||
ASSERT_TRUE(shmRO->Map(1));
|
ASSERT_TRUE(shmRO.Map(1));
|
||||||
const auto* memRO = reinterpret_cast<const char*>(shmRO->Memory());
|
auto memRO = reinterpret_cast<const char*>(shmRO.memory());
|
||||||
ASSERT_TRUE(memRO);
|
ASSERT_TRUE(memRO);
|
||||||
ASSERT_NE(memRW, memRO);
|
ASSERT_NE(memRW, memRO);
|
||||||
|
|
||||||
@@ -225,52 +217,49 @@ TEST(IPCSharedMemory, ROCopyAndRewrite)
|
|||||||
// See FreezeAndMapRW.
|
// See FreezeAndMapRW.
|
||||||
TEST(IPCSharedMemory, ROCopyAndMapRW)
|
TEST(IPCSharedMemory, ROCopyAndMapRW)
|
||||||
{
|
{
|
||||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shmRW, shmRO;
|
||||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shmRW->Map(1));
|
ASSERT_TRUE(shmRW.Map(1));
|
||||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||||
ASSERT_TRUE(memRW);
|
ASSERT_TRUE(memRW);
|
||||||
*memRW = 'A';
|
*memRW = 'A';
|
||||||
|
|
||||||
// Create read-only copy
|
// Create read-only copy
|
||||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||||
ASSERT_TRUE(shmRO->IsValid());
|
ASSERT_TRUE(shmRO.IsValid());
|
||||||
|
|
||||||
// Re-create as writeable
|
// Re-create as writeable
|
||||||
auto handle = shmRO->TakeHandleAndUnmap();
|
auto handle = shmRO.TakeHandle();
|
||||||
ASSERT_TRUE(shmRO->IsHandleValid(handle));
|
ASSERT_TRUE(shmRO.IsHandleValid(handle));
|
||||||
ASSERT_FALSE(shmRO->IsValid());
|
ASSERT_FALSE(shmRO.IsValid());
|
||||||
ASSERT_TRUE(shmRO->SetHandle(std::move(handle),
|
ASSERT_TRUE(shmRO.SetHandle(std::move(handle), /* read-only */ false));
|
||||||
ipc::SharedMemory::OpenRights::RightsReadWrite));
|
ASSERT_TRUE(shmRO.IsValid());
|
||||||
ASSERT_TRUE(shmRO->IsValid());
|
|
||||||
|
|
||||||
// This should fail
|
// This should fail
|
||||||
EXPECT_FALSE(shmRO->Map(1));
|
EXPECT_FALSE(shmRO.Map(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// See FreezeAndReprotect
|
// See FreezeAndReprotect
|
||||||
TEST(IPCSharedMemory, ROCopyAndReprotect)
|
TEST(IPCSharedMemory, ROCopyAndReprotect)
|
||||||
{
|
{
|
||||||
auto shmRW = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shmRW, shmRO;
|
||||||
auto shmRO = MakeRefPtr<ipc::SharedMemory>();
|
|
||||||
|
|
||||||
// Create and initialize
|
// Create and initialize
|
||||||
ASSERT_TRUE(shmRW->CreateFreezable(1));
|
ASSERT_TRUE(shmRW.CreateFreezeable(1));
|
||||||
ASSERT_TRUE(shmRW->Map(1));
|
ASSERT_TRUE(shmRW.Map(1));
|
||||||
auto* memRW = reinterpret_cast<char*>(shmRW->Memory());
|
auto memRW = reinterpret_cast<char*>(shmRW.memory());
|
||||||
ASSERT_TRUE(memRW);
|
ASSERT_TRUE(memRW);
|
||||||
*memRW = 'A';
|
*memRW = 'A';
|
||||||
|
|
||||||
// Create read-only copy
|
// Create read-only copy
|
||||||
ASSERT_TRUE(shmRW->ReadOnlyCopy(shmRO));
|
ASSERT_TRUE(shmRW.ReadOnlyCopy(&shmRO));
|
||||||
ASSERT_TRUE(shmRO->IsValid());
|
ASSERT_TRUE(shmRO.IsValid());
|
||||||
|
|
||||||
// Re-map
|
// Re-map
|
||||||
ASSERT_TRUE(shmRO->Map(1));
|
ASSERT_TRUE(shmRO.Map(1));
|
||||||
auto* memRO = reinterpret_cast<char*>(shmRO->Memory());
|
auto memRO = reinterpret_cast<char*>(shmRO.memory());
|
||||||
ASSERT_EQ(*memRO, 'A');
|
ASSERT_EQ(*memRO, 'A');
|
||||||
|
|
||||||
// Try to alter protection; should fail
|
// Try to alter protection; should fail
|
||||||
@@ -278,6 +267,20 @@ TEST(IPCSharedMemory, ROCopyAndReprotect)
|
|||||||
memRO, 1, ipc::SharedMemory::RightsReadWrite));
|
memRO, 1, ipc::SharedMemory::RightsReadWrite));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(IPCSharedMemory, IsZero)
|
||||||
|
{
|
||||||
|
base::SharedMemory shm;
|
||||||
|
|
||||||
|
static constexpr size_t kSize = 65536;
|
||||||
|
ASSERT_TRUE(shm.Create(kSize));
|
||||||
|
ASSERT_TRUE(shm.Map(kSize));
|
||||||
|
|
||||||
|
auto* mem = reinterpret_cast<char*>(shm.memory());
|
||||||
|
for (size_t i = 0; i < kSize; ++i) {
|
||||||
|
ASSERT_EQ(mem[i], 0) << "offset " << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef FUZZING
|
#ifndef FUZZING
|
||||||
TEST(IPCSharedMemory, BasicIsZero)
|
TEST(IPCSharedMemory, BasicIsZero)
|
||||||
{
|
{
|
||||||
@@ -311,10 +314,9 @@ TEST(IPCSharedMemory, IsMemfd)
|
|||||||
ASSERT_EQ(sscanf(uts.release, "%d.%d", &major, &minor), 2);
|
ASSERT_EQ(sscanf(uts.release, "%d.%d", &major, &minor), 2);
|
||||||
bool expectMemfd = major > kMajor || (major == kMajor && minor >= kMinor);
|
bool expectMemfd = major > kMajor || (major == kMajor && minor >= kMinor);
|
||||||
|
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
base::SharedMemory shm;
|
||||||
|
ASSERT_TRUE(shm.Create(1));
|
||||||
ASSERT_TRUE(shm->Create(1));
|
UniqueFileHandle fd = shm.TakeHandle();
|
||||||
UniqueFileHandle fd = shm->TakeHandleAndUnmap();
|
|
||||||
ASSERT_TRUE(fd);
|
ASSERT_TRUE(fd);
|
||||||
|
|
||||||
struct statfs fs;
|
struct statfs fs;
|
||||||
|
|||||||
@@ -92,8 +92,50 @@ Result<Ok, nsresult> AutoMemMap::initInternal(PRFileMapProtect prot,
|
|||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
|
||||||
|
Result<Ok, nsresult> AutoMemMap::initWithHandle(const FileDescriptor& file,
|
||||||
|
size_t size,
|
||||||
|
PRFileMapProtect prot) {
|
||||||
|
MOZ_ASSERT(!fd);
|
||||||
|
MOZ_ASSERT(!handle_);
|
||||||
|
if (!file.IsValid()) {
|
||||||
|
return Err(NS_ERROR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_ = file.ClonePlatformHandle().release();
|
||||||
|
|
||||||
|
MOZ_ASSERT(!addr);
|
||||||
|
|
||||||
|
size_ = size;
|
||||||
|
|
||||||
|
addr = MapViewOfFile(
|
||||||
|
handle_, prot == PR_PROT_READONLY ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
|
||||||
|
0, 0, size);
|
||||||
|
if (!addr) {
|
||||||
|
return Err(NS_ERROR_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDescriptor AutoMemMap::cloneHandle() const {
|
||||||
|
return FileDescriptor(handle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
Result<Ok, nsresult> AutoMemMap::initWithHandle(const FileDescriptor& file,
|
||||||
|
size_t size,
|
||||||
|
PRFileMapProtect prot) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(size > 0);
|
||||||
|
return init(file, prot, size);
|
||||||
|
}
|
||||||
|
|
||||||
FileDescriptor AutoMemMap::cloneHandle() const { return cloneFileDescriptor(); }
|
FileDescriptor AutoMemMap::cloneHandle() const { return cloneFileDescriptor(); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void AutoMemMap::reset() {
|
void AutoMemMap::reset() {
|
||||||
if (addr && !persistent_) {
|
if (addr && !persistent_) {
|
||||||
Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
|
Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
|
||||||
@@ -103,6 +145,12 @@ void AutoMemMap::reset() {
|
|||||||
Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
|
Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
|
||||||
fileMap = nullptr;
|
fileMap = nullptr;
|
||||||
}
|
}
|
||||||
|
#ifdef XP_WIN
|
||||||
|
if (handle_) {
|
||||||
|
CloseHandle(handle_);
|
||||||
|
handle_ = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
fd = nullptr;
|
fd = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ class AutoMemMap {
|
|||||||
PRFileMapProtect prot = PR_PROT_READONLY,
|
PRFileMapProtect prot = PR_PROT_READONLY,
|
||||||
size_t maybeSize = 0);
|
size_t maybeSize = 0);
|
||||||
|
|
||||||
|
// Initializes the mapped memory with a shared memory handle. On
|
||||||
|
// Unix-like systems, this is identical to the above init() method. On
|
||||||
|
// Windows, the FileDescriptor must be a handle for a file mapping,
|
||||||
|
// rather than a file descriptor.
|
||||||
|
Result<Ok, nsresult> initWithHandle(const FileDescriptor& file, size_t size,
|
||||||
|
PRFileMapProtect prot = PR_PROT_READONLY);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
bool initialized() const { return addr; }
|
bool initialized() const { return addr; }
|
||||||
@@ -71,6 +78,13 @@ class AutoMemMap {
|
|||||||
AutoFDClose fd;
|
AutoFDClose fd;
|
||||||
PRFileMap* fileMap = nullptr;
|
PRFileMap* fileMap = nullptr;
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
// We can't include windows.h in this header, since it gets included
|
||||||
|
// by some binding headers (which are explicitly incompatible with
|
||||||
|
// windows.h). So we can't use the HANDLE type here.
|
||||||
|
void* handle_ = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t size_ = 0;
|
uint32_t size_ = 0;
|
||||||
void* addr = nullptr;
|
void* addr = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ void xpc::SelfHostedShmem::InitFromParent(ContentType aXdr) {
|
|||||||
MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
|
MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
|
||||||
|
|
||||||
size_t len = aXdr.Length();
|
size_t len = aXdr.Length();
|
||||||
auto shm = mozilla::MakeRefPtr<mozilla::ipc::SharedMemory>();
|
auto shm = mozilla::MakeUnique<base::SharedMemory>();
|
||||||
if (NS_WARN_IF(!shm->CreateFreezable(len))) {
|
if (NS_WARN_IF(!shm->CreateFreezeable(len))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,29 +52,27 @@ void xpc::SelfHostedShmem::InitFromParent(ContentType aXdr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* address = shm->Memory();
|
void* address = shm->memory();
|
||||||
memcpy(address, aXdr.Elements(), aXdr.LengthBytes());
|
memcpy(address, aXdr.Elements(), aXdr.LengthBytes());
|
||||||
|
|
||||||
RefPtr<mozilla::ipc::SharedMemory> roCopy =
|
base::SharedMemory roCopy;
|
||||||
mozilla::MakeRefPtr<mozilla::ipc::SharedMemory>();
|
if (NS_WARN_IF(!shm->ReadOnlyCopy(&roCopy))) {
|
||||||
if (NS_WARN_IF(!shm->ReadOnlyCopy(&*roCopy))) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mMem = std::move(shm);
|
mMem = std::move(shm);
|
||||||
mHandle = roCopy->TakeHandleAndUnmap();
|
mHandle = roCopy.TakeHandle();
|
||||||
mLen = len;
|
mLen = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xpc::SelfHostedShmem::InitFromChild(
|
bool xpc::SelfHostedShmem::InitFromChild(::base::SharedMemoryHandle aHandle,
|
||||||
mozilla::ipc::SharedMemoryHandle aHandle, size_t aLen) {
|
size_t aLen) {
|
||||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
|
MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
|
||||||
|
|
||||||
auto shm = mozilla::MakeRefPtr<mozilla::ipc::SharedMemory>();
|
auto shm = mozilla::MakeUnique<base::SharedMemory>();
|
||||||
if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle),
|
if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle), /* read_only */ true))) {
|
||||||
mozilla::ipc::SharedMemory::RightsReadOnly))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +92,10 @@ xpc::SelfHostedShmem::ContentType xpc::SelfHostedShmem::Content() const {
|
|||||||
MOZ_ASSERT(mLen == 0);
|
MOZ_ASSERT(mLen == 0);
|
||||||
return ContentType();
|
return ContentType();
|
||||||
}
|
}
|
||||||
return ContentType(reinterpret_cast<uint8_t*>(mMem->Memory()), mLen);
|
return ContentType(reinterpret_cast<uint8_t*>(mMem->memory()), mLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mozilla::ipc::SharedMemoryHandle& xpc::SelfHostedShmem::Handle() const {
|
const mozilla::UniqueFileHandle& xpc::SelfHostedShmem::Handle() const {
|
||||||
return mHandle;
|
return mHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,11 @@
|
|||||||
#ifndef xpcselfhostedshmem_h___
|
#ifndef xpcselfhostedshmem_h___
|
||||||
#define xpcselfhostedshmem_h___
|
#define xpcselfhostedshmem_h___
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/Span.h"
|
#include "mozilla/Span.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsIMemoryReporter.h"
|
#include "nsIMemoryReporter.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
#include "nsIThread.h"
|
#include "nsIThread.h"
|
||||||
@@ -48,14 +47,14 @@ class SelfHostedShmem final : public nsIMemoryReporter {
|
|||||||
//
|
//
|
||||||
// This function is not thread-safe and should be call at most once and from
|
// This function is not thread-safe and should be call at most once and from
|
||||||
// the main thread.
|
// the main thread.
|
||||||
[[nodiscard]] bool InitFromChild(mozilla::ipc::SharedMemoryHandle aHandle,
|
[[nodiscard]] bool InitFromChild(base::SharedMemoryHandle aHandle,
|
||||||
size_t aLen);
|
size_t aLen);
|
||||||
|
|
||||||
// Return a span over the read-only XDR content of the self-hosted stencil.
|
// Return a span over the read-only XDR content of the self-hosted stencil.
|
||||||
ContentType Content() const;
|
ContentType Content() const;
|
||||||
|
|
||||||
// Return the file handle which is under which the content is mapped.
|
// Return the file handle which is under which the content is mapped.
|
||||||
const mozilla::ipc::SharedMemoryHandle& Handle() const;
|
const mozilla::UniqueFileHandle& Handle() const;
|
||||||
|
|
||||||
// Register this class to the memory reporter service.
|
// Register this class to the memory reporter service.
|
||||||
void InitMemoryReporter();
|
void InitMemoryReporter();
|
||||||
@@ -76,10 +75,10 @@ class SelfHostedShmem final : public nsIMemoryReporter {
|
|||||||
|
|
||||||
// read-only file Handle used to transfer from the parent process to content
|
// read-only file Handle used to transfer from the parent process to content
|
||||||
// processes.
|
// processes.
|
||||||
mozilla::ipc::SharedMemoryHandle mHandle;
|
mozilla::UniqueFileHandle mHandle;
|
||||||
|
|
||||||
// Shared memory used by JS runtime initialization.
|
// Shared memory used by JS runtime initialization.
|
||||||
RefPtr<mozilla::ipc::SharedMemory> mMem;
|
mozilla::UniquePtr<base::SharedMemory> mMem;
|
||||||
|
|
||||||
// Length of the content within the shared memory.
|
// Length of the content within the shared memory.
|
||||||
size_t mLen = 0;
|
size_t mLen = 0;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "nsAppDirectoryServiceDefs.h"
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
#include "nsExceptionHandler.h"
|
#include "nsExceptionHandler.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/NeverDestroyed.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/StaticPrefs_layout.h"
|
#include "mozilla/StaticPrefs_layout.h"
|
||||||
#include "mozilla/StyleSheet.h"
|
#include "mozilla/StyleSheet.h"
|
||||||
@@ -105,11 +104,6 @@ namespace mozilla {
|
|||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace css;
|
using namespace css;
|
||||||
|
|
||||||
mozilla::ipc::SharedMemoryHandle& sSharedMemoryHandle() {
|
|
||||||
static NeverDestroyed<mozilla::ipc::SharedMemoryHandle> handle;
|
|
||||||
return *handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PREF_LEGACY_STYLESHEET_CUSTOMIZATION \
|
#define PREF_LEGACY_STYLESHEET_CUSTOMIZATION \
|
||||||
"toolkit.legacyUserProfileCustomizations.stylesheets"
|
"toolkit.legacyUserProfileCustomizations.stylesheets"
|
||||||
|
|
||||||
@@ -179,7 +173,7 @@ GlobalStyleSheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
|
|||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
MOZ_COLLECT_REPORT(
|
MOZ_COLLECT_REPORT(
|
||||||
"explicit/layout/style-sheet-cache/shared", KIND_NONHEAP, UNITS_BYTES,
|
"explicit/layout/style-sheet-cache/shared", KIND_NONHEAP, UNITS_BYTES,
|
||||||
sSharedMemory.IsEmpty() ? 0 : sUsedSharedMemory,
|
sSharedMemory ? sUsedSharedMemory : 0,
|
||||||
"Memory used for built-in style sheets that are shared to "
|
"Memory used for built-in style sheets that are shared to "
|
||||||
"child processes.");
|
"child processes.");
|
||||||
}
|
}
|
||||||
@@ -242,10 +236,10 @@ GlobalStyleSheetCache::GlobalStyleSheetCache() {
|
|||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
// Load the style sheets and store them in a new shared memory buffer.
|
// Load the style sheets and store them in a new shared memory buffer.
|
||||||
InitSharedSheetsInParent();
|
InitSharedSheetsInParent();
|
||||||
} else if (!sSharedMemory.IsEmpty()) {
|
} else if (sSharedMemory) {
|
||||||
// Use the shared memory that was given to us by a SetSharedMemory call
|
// Use the shared memory handle that was given to us by a SetSharedMemory
|
||||||
// under ContentChild::InitXPCOM.
|
// call under ContentChild::InitXPCOM.
|
||||||
MOZ_ASSERT(sSharedMemory.data(),
|
MOZ_ASSERT(sSharedMemory->memory(),
|
||||||
"GlobalStyleSheetCache::SetSharedMemory should have mapped "
|
"GlobalStyleSheetCache::SetSharedMemory should have mapped "
|
||||||
"the shared memory");
|
"the shared memory");
|
||||||
}
|
}
|
||||||
@@ -264,8 +258,8 @@ GlobalStyleSheetCache::GlobalStyleSheetCache() {
|
|||||||
// In the parent process, this means we'll just leave our eagerly loaded
|
// In the parent process, this means we'll just leave our eagerly loaded
|
||||||
// non-shared sheets in the mFooSheet fields. In a content process, we'll
|
// non-shared sheets in the mFooSheet fields. In a content process, we'll
|
||||||
// lazily load our own copies of the sheets later.
|
// lazily load our own copies of the sheets later.
|
||||||
if (!sSharedMemory.IsEmpty()) {
|
if (sSharedMemory) {
|
||||||
if (auto* header = reinterpret_cast<Header*>(sSharedMemory.data())) {
|
if (auto* header = static_cast<Header*>(sSharedMemory->memory())) {
|
||||||
MOZ_RELEASE_ASSERT(header->mMagic == Header::kMagic);
|
MOZ_RELEASE_ASSERT(header->mMagic == Header::kMagic);
|
||||||
|
|
||||||
#define STYLE_SHEET(identifier_, url_, shared_) \
|
#define STYLE_SHEET(identifier_, url_, shared_) \
|
||||||
@@ -305,10 +299,10 @@ void GlobalStyleSheetCache::LoadSheetFromSharedMemory(
|
|||||||
|
|
||||||
void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
MOZ_RELEASE_ASSERT(sSharedMemory.IsEmpty());
|
MOZ_RELEASE_ASSERT(!sSharedMemory);
|
||||||
|
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
auto shm = MakeUnique<base::SharedMemory>();
|
||||||
if (NS_WARN_IF(!shm->CreateFreezable(kSharedMemorySize))) {
|
if (NS_WARN_IF(!shm->CreateFreezeable(kSharedMemorySize))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +334,7 @@ void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void* address = nullptr;
|
void* address = nullptr;
|
||||||
if (void* p = ipc::SharedMemory::FindFreeAddressSpace(2 * kOffset)) {
|
if (void* p = base::SharedMemory::FindFreeAddressSpace(2 * kOffset)) {
|
||||||
address = reinterpret_cast<void*>(uintptr_t(p) + kOffset);
|
address = reinterpret_cast<void*>(uintptr_t(p) + kOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +346,7 @@ void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
address = shm->Memory();
|
address = shm->memory();
|
||||||
|
|
||||||
auto* header = static_cast<Header*>(address);
|
auto* header = static_cast<Header*>(address);
|
||||||
header->mMagic = Header::kMagic;
|
header->mMagic = Header::kMagic;
|
||||||
@@ -411,8 +405,7 @@ void GlobalStyleSheetCache::InitSharedSheetsInParent() {
|
|||||||
(Servo_SharedMemoryBuilder_GetLength(builder.get()) + pageSize - 1) &
|
(Servo_SharedMemoryBuilder_GetLength(builder.get()) + pageSize - 1) &
|
||||||
~(pageSize - 1);
|
~(pageSize - 1);
|
||||||
|
|
||||||
sSharedMemory = shm->TakeMapping();
|
sSharedMemory = shm.release();
|
||||||
sSharedMemoryHandle() = shm->TakeHandle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalStyleSheetCache::~GlobalStyleSheetCache() {
|
GlobalStyleSheetCache::~GlobalStyleSheetCache() {
|
||||||
@@ -535,26 +528,25 @@ RefPtr<StyleSheet> GlobalStyleSheetCache::LoadSheet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void GlobalStyleSheetCache::SetSharedMemory(
|
/* static */ void GlobalStyleSheetCache::SetSharedMemory(
|
||||||
ipc::SharedMemory::Handle aHandle, uintptr_t aAddress) {
|
base::SharedMemoryHandle aHandle, uintptr_t aAddress) {
|
||||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||||
MOZ_ASSERT(!gStyleCache, "Too late, GlobalStyleSheetCache already created!");
|
MOZ_ASSERT(!gStyleCache, "Too late, GlobalStyleSheetCache already created!");
|
||||||
MOZ_ASSERT(sSharedMemory.IsEmpty(), "Shouldn't call this more than once");
|
MOZ_ASSERT(!sSharedMemory, "Shouldn't call this more than once");
|
||||||
|
|
||||||
auto shm = MakeRefPtr<ipc::SharedMemory>();
|
auto shm = MakeUnique<base::SharedMemory>();
|
||||||
if (!shm->SetHandle(std::move(aHandle), ipc::SharedMemory::RightsReadOnly)) {
|
if (!shm->SetHandle(std::move(aHandle), /* read_only */ true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shm->Map(kSharedMemorySize, reinterpret_cast<void*>(aAddress))) {
|
if (shm->Map(kSharedMemorySize, reinterpret_cast<void*>(aAddress))) {
|
||||||
sSharedMemory = shm->TakeMapping();
|
sSharedMemory = shm.release();
|
||||||
sSharedMemoryHandle() = shm->TakeHandle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipc::SharedMemoryHandle GlobalStyleSheetCache::CloneHandle() {
|
base::SharedMemoryHandle GlobalStyleSheetCache::CloneHandle() {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
if (ipc::SharedMemory::IsHandleValid(sSharedMemoryHandle())) {
|
if (sSharedMemory) {
|
||||||
return ipc::SharedMemory::CloneHandle(sSharedMemoryHandle());
|
return sSharedMemory->CloneHandle();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -563,7 +555,7 @@ StaticRefPtr<GlobalStyleSheetCache> GlobalStyleSheetCache::gStyleCache;
|
|||||||
StaticRefPtr<css::Loader> GlobalStyleSheetCache::gCSSLoader;
|
StaticRefPtr<css::Loader> GlobalStyleSheetCache::gCSSLoader;
|
||||||
StaticRefPtr<nsIURI> GlobalStyleSheetCache::gUserContentSheetURL;
|
StaticRefPtr<nsIURI> GlobalStyleSheetCache::gUserContentSheetURL;
|
||||||
|
|
||||||
Span<uint8_t> GlobalStyleSheetCache::sSharedMemory;
|
StaticAutoPtr<base::SharedMemory> GlobalStyleSheetCache::sSharedMemory;
|
||||||
size_t GlobalStyleSheetCache::sUsedSharedMemory;
|
size_t GlobalStyleSheetCache::sUsedSharedMemory;
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "nsIMemoryReporter.h"
|
#include "nsIMemoryReporter.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/PreferenceSheet.h"
|
#include "mozilla/PreferenceSheet.h"
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/UserAgentStyleSheetID.h"
|
#include "mozilla/UserAgentStyleSheetID.h"
|
||||||
#include "mozilla/css/Loader.h"
|
#include "mozilla/css/Loader.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
class nsIFile;
|
class nsIFile;
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
@@ -60,18 +60,18 @@ class GlobalStyleSheetCache final : public nsIObserver,
|
|||||||
// Called early on in a content process' life from
|
// Called early on in a content process' life from
|
||||||
// ContentChild::InitSharedUASheets, before the GlobalStyleSheetCache
|
// ContentChild::InitSharedUASheets, before the GlobalStyleSheetCache
|
||||||
// singleton has been created.
|
// singleton has been created.
|
||||||
static void SetSharedMemory(mozilla::ipc::SharedMemory::Handle aHandle,
|
static void SetSharedMemory(base::SharedMemoryHandle aHandle,
|
||||||
uintptr_t aAddress);
|
uintptr_t aAddress);
|
||||||
|
|
||||||
// Obtain a shared memory handle for the shared UA sheets to pass into a
|
// Obtain a shared memory handle for the shared UA sheets to pass into a
|
||||||
// content process. Called by ContentParent::InitInternal shortly after
|
// content process. Called by ContentParent::InitInternal shortly after
|
||||||
// a content process has been created.
|
// a content process has been created.
|
||||||
mozilla::ipc::SharedMemoryHandle CloneHandle();
|
base::SharedMemoryHandle CloneHandle();
|
||||||
|
|
||||||
// Returns the address of the shared memory segment that holds the shared UA
|
// Returns the address of the shared memory segment that holds the shared UA
|
||||||
// sheets.
|
// sheets.
|
||||||
uintptr_t GetSharedMemoryAddress() {
|
uintptr_t GetSharedMemoryAddress() {
|
||||||
return sSharedMemory.IsEmpty() ? 0 : uintptr_t(sSharedMemory.data());
|
return sSharedMemory ? uintptr_t(sSharedMemory->memory()) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size of the shared memory buffer we'll create to store the shared UA
|
// Size of the shared memory buffer we'll create to store the shared UA
|
||||||
@@ -120,7 +120,7 @@ class GlobalStyleSheetCache final : public nsIObserver,
|
|||||||
RefPtr<StyleSheet> mUserContentSheet;
|
RefPtr<StyleSheet> mUserContentSheet;
|
||||||
|
|
||||||
// Shared memory segment storing shared style sheets.
|
// Shared memory segment storing shared style sheets.
|
||||||
static Span<uint8_t> sSharedMemory;
|
static StaticAutoPtr<base::SharedMemory> sSharedMemory;
|
||||||
|
|
||||||
// How much of the shared memory buffer we ended up using. Used for memory
|
// How much of the shared memory buffer we ended up using. Used for memory
|
||||||
// reporting in the parent process.
|
// reporting in the parent process.
|
||||||
|
|||||||
@@ -3833,7 +3833,7 @@ void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) {
|
FileDescriptor Preferences::EnsureSnapshot(size_t* aSize) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
@@ -3883,12 +3883,11 @@ mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*aSize = gSharedMap->MapSize();
|
*aSize = gSharedMap->MapSize();
|
||||||
return gSharedMap->CloneHandle();
|
return gSharedMap->CloneFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void Preferences::InitSnapshot(const mozilla::ipc::SharedMemoryHandle& aHandle,
|
void Preferences::InitSnapshot(const FileDescriptor& aHandle, size_t aSize) {
|
||||||
size_t aSize) {
|
|
||||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||||
MOZ_ASSERT(!gSharedMap);
|
MOZ_ASSERT(!gSharedMap);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/MozPromise.h"
|
#include "mozilla/MozPromise.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
#include "nsIPrefBranch.h"
|
#include "nsIPrefBranch.h"
|
||||||
@@ -410,11 +409,8 @@ class Preferences final : public nsIPrefService,
|
|||||||
bool aIsDestinationWebContentProcess);
|
bool aIsDestinationWebContentProcess);
|
||||||
static void DeserializePreferences(char* aStr, size_t aPrefsLen);
|
static void DeserializePreferences(char* aStr, size_t aPrefsLen);
|
||||||
|
|
||||||
#ifndef RUST_BINDGEN
|
static mozilla::ipc::FileDescriptor EnsureSnapshot(size_t* aSize);
|
||||||
static mozilla::ipc::SharedMemoryHandle EnsureSnapshot(size_t* aSize);
|
static void InitSnapshot(const mozilla::ipc::FileDescriptor&, size_t aSize);
|
||||||
static void InitSnapshot(const mozilla::ipc::SharedMemoryHandle&,
|
|
||||||
size_t aSize);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// When a single pref is changed in the parent process, these methods are
|
// When a single pref is changed in the parent process, these methods are
|
||||||
// used to pass the update to content processes.
|
// used to pass the update to content processes.
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#include "mozilla/Try.h"
|
#include "mozilla/Try.h"
|
||||||
#include "mozilla/ipc/FileDescriptor.h"
|
#include "mozilla/ipc/FileDescriptor.h"
|
||||||
|
|
||||||
|
using namespace mozilla::loader;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
using namespace ipc;
|
using namespace ipc;
|
||||||
@@ -22,38 +24,24 @@ static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
|
|||||||
return mod ? aAlign - mod : 0;
|
return mod ? aAlign - mod : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPrefMap::SharedPrefMap(const SharedMemoryHandle& aMapHandle,
|
SharedPrefMap::SharedPrefMap(const FileDescriptor& aMapFile, size_t aMapSize) {
|
||||||
size_t aMapSize) {
|
auto result = mMap.initWithHandle(aMapFile, aMapSize);
|
||||||
auto map = MakeRefPtr<SharedMemory>();
|
MOZ_RELEASE_ASSERT(result.isOk());
|
||||||
{
|
|
||||||
auto result = map->SetHandle(SharedMemory::CloneHandle(aMapHandle),
|
|
||||||
SharedMemory::OpenRights::RightsReadOnly);
|
|
||||||
MOZ_RELEASE_ASSERT(result);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto result = map->Map(aMapSize);
|
|
||||||
MOZ_RELEASE_ASSERT(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We return literal nsCStrings pointing to the mapped data for preference
|
// We return literal nsCStrings pointing to the mapped data for preference
|
||||||
// names and string values, which means that we may still have references to
|
// names and string values, which means that we may still have references to
|
||||||
// the mapped data even after this instance is destroyed. That means that we
|
// the mapped data even after this instance is destroyed. That means that we
|
||||||
// need to keep the mapping alive until process shutdown, in order to be safe.
|
// need to keep the mapping alive until process shutdown, in order to be safe.
|
||||||
mMappedMemory = map->TakeMapping();
|
mMap.setPersistent();
|
||||||
mHandle = map->TakeHandle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) {
|
SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) {
|
||||||
RefPtr<SharedMemory> map;
|
auto result = aBuilder.Finalize(mMap);
|
||||||
auto result = aBuilder.Finalize(map);
|
MOZ_RELEASE_ASSERT(result.isOk());
|
||||||
MOZ_RELEASE_ASSERT(result.isOk() && map);
|
mMap.setPersistent();
|
||||||
|
|
||||||
mMappedMemory = map->TakeMapping();
|
|
||||||
mHandle = map->TakeHandle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::SharedMemoryHandle SharedPrefMap::CloneHandle() const {
|
mozilla::ipc::FileDescriptor SharedPrefMap::CloneFileDescriptor() const {
|
||||||
return SharedMemory::CloneHandle(mHandle);
|
return mMap.cloneHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SharedPrefMap::Has(const char* aKey) const {
|
bool SharedPrefMap::Has(const char* aKey) const {
|
||||||
@@ -148,8 +136,7 @@ void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(
|
Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(loader::AutoMemMap& aMap) {
|
||||||
RefPtr<SharedMemory>& aMap) {
|
|
||||||
using Header = SharedPrefMap::Header;
|
using Header = SharedPrefMap::Header;
|
||||||
|
|
||||||
// Create an array of entry pointers for the entry array, and sort it by
|
// Create an array of entry pointers for the entry array, and sort it by
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
#ifndef dom_ipc_SharedPrefMap_h
|
#ifndef dom_ipc_SharedPrefMap_h
|
||||||
#define dom_ipc_SharedPrefMap_h
|
#define dom_ipc_SharedPrefMap_h
|
||||||
|
|
||||||
|
#include "mozilla/AutoMemMap.h"
|
||||||
#include "mozilla/HashFunctions.h"
|
#include "mozilla/HashFunctions.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/Result.h"
|
#include "mozilla/Result.h"
|
||||||
#include "mozilla/dom/ipc/StringTable.h"
|
#include "mozilla/dom/ipc/StringTable.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsTHashMap.h"
|
#include "nsTHashMap.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@@ -52,6 +52,8 @@ class SharedPrefMapBuilder;
|
|||||||
// instance has been initialized, the memory that it allocates can never be
|
// instance has been initialized, the memory that it allocates can never be
|
||||||
// freed before process shutdown. Do not use it for short-lived mappings.
|
// freed before process shutdown. Do not use it for short-lived mappings.
|
||||||
class SharedPrefMap {
|
class SharedPrefMap {
|
||||||
|
using FileDescriptor = mozilla::ipc::FileDescriptor;
|
||||||
|
|
||||||
friend class SharedPrefMapBuilder;
|
friend class SharedPrefMapBuilder;
|
||||||
|
|
||||||
// Describes a block of memory within the shared memory region.
|
// Describes a block of memory within the shared memory region.
|
||||||
@@ -419,7 +421,7 @@ class SharedPrefMap {
|
|||||||
|
|
||||||
// Note: These constructors are infallible, because the preference database is
|
// Note: These constructors are infallible, because the preference database is
|
||||||
// critical to platform functionality, and we cannot operate without it.
|
// critical to platform functionality, and we cannot operate without it.
|
||||||
SharedPrefMap(const mozilla::ipc::SharedMemoryHandle&, size_t);
|
SharedPrefMap(const FileDescriptor&, size_t);
|
||||||
explicit SharedPrefMap(SharedPrefMapBuilder&&);
|
explicit SharedPrefMap(SharedPrefMapBuilder&&);
|
||||||
|
|
||||||
// Searches for the given preference in the map, and returns true if it
|
// Searches for the given preference in the map, and returns true if it
|
||||||
@@ -498,15 +500,15 @@ class SharedPrefMap {
|
|||||||
// makes its purpose slightly clearer.
|
// makes its purpose slightly clearer.
|
||||||
const SharedPrefMap& Iter() const { return *this; }
|
const SharedPrefMap& Iter() const { return *this; }
|
||||||
|
|
||||||
// Returns a copy of the read-only shared memory handle which backs the shared
|
// Returns a copy of the read-only file descriptor which backs the shared
|
||||||
// memory region for this map. The handle may be passed between processes, and
|
// memory region for this map. The file descriptor may be passed between
|
||||||
// used to construct new instances of SharedPrefMap with the same data as this
|
// processes, and used to construct new instances of SharedPrefMap with
|
||||||
// instance.
|
// the same data as this instance.
|
||||||
mozilla::ipc::SharedMemoryHandle CloneHandle() const;
|
FileDescriptor CloneFileDescriptor() const;
|
||||||
|
|
||||||
// Returns the size of the mapped memory region. This size must be passed to
|
// Returns the size of the mapped memory region. This size must be passed to
|
||||||
// the constructor when mapping the shared region in another process.
|
// the constructor when mapping the shared region in another process.
|
||||||
size_t MapSize() const { return mMappedMemory.size(); }
|
size_t MapSize() const { return mMap.size(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~SharedPrefMap() = default;
|
~SharedPrefMap() = default;
|
||||||
@@ -516,9 +518,7 @@ class SharedPrefMap {
|
|||||||
using StringTable = mozilla::dom::ipc::StringTable<T>;
|
using StringTable = mozilla::dom::ipc::StringTable<T>;
|
||||||
|
|
||||||
// Type-safe getters for values in the shared memory region:
|
// Type-safe getters for values in the shared memory region:
|
||||||
const Header& GetHeader() const {
|
const Header& GetHeader() const { return mMap.get<Header>()[0]; }
|
||||||
return *reinterpret_cast<const Header*>(mMappedMemory.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
RangedPtr<const Entry> Entries() const {
|
RangedPtr<const Entry> Entries() const {
|
||||||
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
|
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
|
||||||
@@ -528,7 +528,7 @@ class SharedPrefMap {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RangedPtr<const T> GetBlock(const DataBlock& aBlock) const {
|
RangedPtr<const T> GetBlock(const DataBlock& aBlock) const {
|
||||||
return RangedPtr<uint8_t>(&mMappedMemory.data()[aBlock.mOffset],
|
return RangedPtr<uint8_t>(&mMap.get<uint8_t>()[aBlock.mOffset],
|
||||||
aBlock.mSize)
|
aBlock.mSize)
|
||||||
.ReinterpretCast<const T>();
|
.ReinterpretCast<const T>();
|
||||||
}
|
}
|
||||||
@@ -549,19 +549,15 @@ class SharedPrefMap {
|
|||||||
|
|
||||||
StringTable<nsCString> KeyTable() const {
|
StringTable<nsCString> KeyTable() const {
|
||||||
auto& block = GetHeader().mKeyStrings;
|
auto& block = GetHeader().mKeyStrings;
|
||||||
return {{&mMappedMemory.data()[block.mOffset], block.mSize}};
|
return {{&mMap.get<uint8_t>()[block.mOffset], block.mSize}};
|
||||||
}
|
}
|
||||||
|
|
||||||
StringTable<nsCString> ValueTable() const {
|
StringTable<nsCString> ValueTable() const {
|
||||||
auto& block = GetHeader().mValueStrings;
|
auto& block = GetHeader().mValueStrings;
|
||||||
return {{&mMappedMemory.data()[block.mOffset], block.mSize}};
|
return {{&mMap.get<uint8_t>()[block.mOffset], block.mSize}};
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::SharedMemoryHandle mHandle;
|
loader::AutoMemMap mMap;
|
||||||
// This is a leaked shared memory mapping (see the constructor definition for
|
|
||||||
// an explanation). It replaces AutoMemMap::setPersistent behavior as part of
|
|
||||||
// bug 1454816.
|
|
||||||
Span<uint8_t> mMappedMemory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A helper class which builds the contiguous look-up table used by
|
// A helper class which builds the contiguous look-up table used by
|
||||||
@@ -591,13 +587,13 @@ class MOZ_RAII SharedPrefMapBuilder {
|
|||||||
const nsCString& aDefaultValue, const nsCString& aUserValue);
|
const nsCString& aDefaultValue, const nsCString& aUserValue);
|
||||||
|
|
||||||
// Finalizes the binary representation of the map, writes it to a shared
|
// Finalizes the binary representation of the map, writes it to a shared
|
||||||
// memory region, and then initializes the given SharedMemory with a reference
|
// memory region, and then initializes the given AutoMemMap with a reference
|
||||||
// to the read-only copy of it.
|
// to the read-only copy of it.
|
||||||
//
|
//
|
||||||
// This should generally not be used directly by callers. The
|
// This should generally not be used directly by callers. The
|
||||||
// SharedPrefMapBuilder instance should instead be passed to the SharedPrefMap
|
// SharedPrefMapBuilder instance should instead be passed to the SharedPrefMap
|
||||||
// constructor as a move reference.
|
// constructor as a move reference.
|
||||||
Result<Ok, nsresult> Finalize(RefPtr<mozilla::ipc::SharedMemory>& aMap);
|
Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using StringTableEntry = mozilla::dom::ipc::StringTableEntry;
|
using StringTableEntry = mozilla::dom::ipc::StringTableEntry;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "SocketProcessImpl.h"
|
#include "SocketProcessImpl.h"
|
||||||
|
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
#include "base/shared_memory.h"
|
||||||
#include "base/string_util.h"
|
#include "base/string_util.h"
|
||||||
#include "mozilla/BackgroundHangMonitor.h"
|
#include "mozilla/BackgroundHangMonitor.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "SandboxInfo.h"
|
#include "SandboxInfo.h"
|
||||||
#include "SandboxLogging.h"
|
#include "SandboxLogging.h"
|
||||||
|
|
||||||
|
#include "base/shared_memory.h"
|
||||||
#include "mozilla/Array.h"
|
#include "mozilla/Array.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/Omnijar.h"
|
#include "mozilla/Omnijar.h"
|
||||||
@@ -18,7 +19,6 @@
|
|||||||
#include "mozilla/StaticMutex.h"
|
#include "mozilla/StaticMutex.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
@@ -323,7 +323,7 @@ static void AddLdLibraryEnvPaths(SandboxBroker::Policy* aPolicy) {
|
|||||||
|
|
||||||
static void AddSharedMemoryPaths(SandboxBroker::Policy* aPolicy, pid_t aPid) {
|
static void AddSharedMemoryPaths(SandboxBroker::Policy* aPolicy, pid_t aPid) {
|
||||||
std::string shmPath("/dev/shm");
|
std::string shmPath("/dev/shm");
|
||||||
if (ipc::SharedMemory::AppendPosixShmPrefix(&shmPath, aPid)) {
|
if (base::SharedMemory::AppendPosixShmPrefix(&shmPath, aPid)) {
|
||||||
aPolicy->AddPrefix(rdwrcr, shmPath.c_str());
|
aPolicy->AddPrefix(rdwrcr, shmPath.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/UniquePtrExtensions.h"
|
#include "mozilla/UniquePtrExtensions.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@@ -188,14 +187,14 @@ static CommandLineArg<const char*> sProfile{"-profile", "profile"};
|
|||||||
|
|
||||||
static CommandLineArg<UniqueFileHandle> sIPCHandle{"-ipcHandle", "ipchandle"};
|
static CommandLineArg<UniqueFileHandle> sIPCHandle{"-ipcHandle", "ipchandle"};
|
||||||
|
|
||||||
static CommandLineArg<mozilla::ipc::SharedMemoryHandle> sJsInitHandle{
|
static CommandLineArg<UniqueFileHandle> sJsInitHandle{"-jsInitHandle",
|
||||||
"-jsInitHandle", "jsinithandle"};
|
"jsinithandle"};
|
||||||
static CommandLineArg<uint64_t> sJsInitLen{"-jsInitLen", "jsinitlen"};
|
static CommandLineArg<uint64_t> sJsInitLen{"-jsInitLen", "jsinitlen"};
|
||||||
static CommandLineArg<mozilla::ipc::SharedMemoryHandle> sPrefsHandle{
|
static CommandLineArg<UniqueFileHandle> sPrefsHandle{"-prefsHandle",
|
||||||
"-prefsHandle", "prefshandle"};
|
"prefshandle"};
|
||||||
static CommandLineArg<uint64_t> sPrefsLen{"-prefsLen", "prefslen"};
|
static CommandLineArg<uint64_t> sPrefsLen{"-prefsLen", "prefslen"};
|
||||||
static CommandLineArg<mozilla::ipc::SharedMemoryHandle> sPrefMapHandle{
|
static CommandLineArg<UniqueFileHandle> sPrefMapHandle{"-prefMapHandle",
|
||||||
"-prefMapHandle", "prefmaphandle"};
|
"prefmaphandle"};
|
||||||
static CommandLineArg<uint64_t> sPrefMapSize{"-prefMapSize", "prefmapsize"};
|
static CommandLineArg<uint64_t> sPrefMapSize{"-prefMapSize", "prefmapsize"};
|
||||||
|
|
||||||
static CommandLineArg<uint64_t> sSandboxingKind{"-sandboxingKind",
|
static CommandLineArg<uint64_t> sSandboxingKind{"-sandboxingKind",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ RefPtr<WaylandShmPool> WaylandShmPool::Create(nsWaylandDisplay* aWaylandDisplay,
|
|||||||
|
|
||||||
RefPtr<WaylandShmPool> shmPool = new WaylandShmPool();
|
RefPtr<WaylandShmPool> shmPool = new WaylandShmPool();
|
||||||
|
|
||||||
shmPool->mShm = MakeRefPtr<ipc::SharedMemory>();
|
shmPool->mShm = MakeUnique<base::SharedMemory>();
|
||||||
if (!shmPool->mShm->Create(aSize)) {
|
if (!shmPool->mShm->Create(aSize)) {
|
||||||
NS_WARNING("WaylandShmPool: Unable to allocate shared memory!");
|
NS_WARNING("WaylandShmPool: Unable to allocate shared memory!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -77,7 +77,7 @@ void* WaylandShmPool::GetImageData() {
|
|||||||
NS_WARNING("WaylandShmPool: Failed to map Shm!");
|
NS_WARNING("WaylandShmPool: Failed to map Shm!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
mImageData = mShm->Memory();
|
mImageData = mShm->memory();
|
||||||
return mImageData;
|
return mImageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,12 @@
|
|||||||
#include "DMABufSurface.h"
|
#include "DMABufSurface.h"
|
||||||
#include "GLContext.h"
|
#include "GLContext.h"
|
||||||
#include "MozFramebuffer.h"
|
#include "MozFramebuffer.h"
|
||||||
#include "mozilla/ipc/SharedMemory.h"
|
|
||||||
#include "mozilla/gfx/2D.h"
|
#include "mozilla/gfx/2D.h"
|
||||||
#include "mozilla/gfx/Types.h"
|
#include "mozilla/gfx/Types.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsWaylandDisplay.h"
|
#include "nsWaylandDisplay.h"
|
||||||
|
#include "base/shared_memory.h"
|
||||||
|
|
||||||
namespace mozilla::widget {
|
namespace mozilla::widget {
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ class WaylandShmPool {
|
|||||||
|
|
||||||
wl_shm_pool* mShmPool = nullptr;
|
wl_shm_pool* mShmPool = nullptr;
|
||||||
void* mImageData = nullptr;
|
void* mImageData = nullptr;
|
||||||
RefPtr<ipc::SharedMemory> mShm;
|
UniquePtr<base::SharedMemory> mShm;
|
||||||
int mSize = 0;
|
int mSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user