Backed out 8 changesets (bug 1942129) for causing bustages at SharedMemoryMapping.h. CLOSED TREE

Backed out changeset 8d9053f1c203 (bug 1942129)
Backed out changeset 393e3c507c27 (bug 1942129)
Backed out changeset 8240d353d224 (bug 1942129)
Backed out changeset 8c4cd026b720 (bug 1942129)
Backed out changeset 742634b0d6e9 (bug 1942129)
Backed out changeset d16857f9812f (bug 1942129)
Backed out changeset 7ff7af041ee7 (bug 1942129)
Backed out changeset ef41d9e4c7de (bug 1942129)
This commit is contained in:
Butkovits Atila
2025-03-04 00:43:23 +02:00
parent 65e74408c3
commit 2406ce261c
132 changed files with 3543 additions and 2087 deletions

View File

@@ -220,6 +220,7 @@
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/net/UrlClassifierCommon.h"
#include "mozilla/Tokenizer.h"
#include "mozilla/widget/IMEData.h"

View File

@@ -443,28 +443,25 @@ bool DrawTargetWebgl::Init(const IntSize& size, const SurfaceFormat format,
return false;
}
size_t shmemSize = mozilla::ipc::shared_memory::PageAlignedSize(byteSize);
size_t shmemSize = mozilla::ipc::SharedMemory::PageAlignedSize(byteSize);
if (NS_WARN_IF(shmemSize > UINT32_MAX)) {
MOZ_ASSERT_UNREACHABLE("Buffer too big?");
return false;
}
auto handle = mozilla::ipc::shared_memory::Create(shmemSize);
if (NS_WARN_IF(!handle)) {
return false;
}
auto mapping = handle.Map();
if (NS_WARN_IF(!mapping)) {
auto shmem = MakeRefPtr<mozilla::ipc::SharedMemory>();
if (NS_WARN_IF(!shmem->Create(shmemSize)) ||
NS_WARN_IF(!shmem->Map(shmemSize))) {
return false;
}
mShmemHandle = std::move(handle).ToReadOnly();
mShmem = std::move(mapping);
mShmem = std::move(shmem);
mShmemSize = shmemSize;
mSkia = new DrawTargetSkia;
auto stride = layers::ImageDataSerializer::ComputeRGBStride(
SurfaceFormat::B8G8R8A8, size.width);
if (!mSkia->Init(mShmem.DataAs<uint8_t>(), size, stride,
if (!mSkia->Init(reinterpret_cast<uint8_t*>(mShmem->Memory()), size, stride,
SurfaceFormat::B8G8R8A8, true)) {
return false;
}

View File

@@ -14,8 +14,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/layers/LayersTypes.h"
#include <vector>
@@ -382,13 +381,12 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
RefPtr<DrawTargetSkia> mSkia;
// Skia DT pointing to the same pixel data, but without any applied clips.
RefPtr<DrawTargetSkia> mSkiaNoClip;
// A Shmem read-only handle to the same memory as mShmem, to be consumed by
// TakeShmemHandle().
mozilla::ipc::ReadOnlySharedMemoryHandle mShmemHandle;
// The Shmem backing the Skia DT, if applicable.
mozilla::ipc::SharedMemoryMapping mShmem;
RefPtr<mozilla::ipc::SharedMemory> mShmem;
// The currently cached snapshot of the WebGL context
RefPtr<SourceSurfaceWebgl> mSnapshot;
// The mappable size of mShmem.
uint32_t mShmemSize = 0;
// Whether the framebuffer is still in the initially clear state.
bool mIsClear = true;
// Whether or not the Skia target has valid contents and is being drawn to
@@ -607,10 +605,13 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
return stream.str();
}
mozilla::ipc::ReadOnlySharedMemoryHandle TakeShmemHandle() {
return std::move(mShmemHandle);
mozilla::ipc::SharedMemory::Handle TakeShmemHandle() const {
return mShmem ? mShmem->TakeHandle()
: mozilla::ipc::SharedMemory::NULLHandle();
}
uint32_t GetShmemSize() const { return mShmemSize; }
private:
bool SupportsPattern(const Pattern& aPattern) {
return mSharedContext->SupportsPattern(aPattern);

View File

@@ -13,6 +13,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/IntegerRange.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/Logging.h"
#include "mozilla/TimeStamp.h"
#include "nsExceptionHandler.h"

View File

@@ -41,6 +41,7 @@
#include "nsTArray.h"
#include "nsString.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/ipc/SharedMemory.h"
// Manual reflection of WebIDL typedefs that are different from their
// OpenGL counterparts.

View File

@@ -652,9 +652,9 @@ NS_INTERFACE_MAP_END
mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
FullLookAndFeel&& aLookAndFeelData, dom::SystemFontList&& aFontList,
Maybe<mozilla::ipc::ReadOnlySharedMemoryHandle>&& aSharedUASheetHandle,
Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress,
nsTArray<mozilla::ipc::ReadOnlySharedMemoryHandle>&& aSharedFontListBlocks,
nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
const bool& aIsReadyForBackgroundProcessing) {
if (!sShutdownCanary) {
return IPC_OK();
@@ -1332,9 +1332,8 @@ void ContentChild::InitGraphicsDeviceData(const ContentDeviceData& aData) {
gfxPlatform::InitChild(aData);
}
void ContentChild::InitSharedUASheets(
Maybe<mozilla::ipc::ReadOnlySharedMemoryHandle>&& aHandle,
uintptr_t aAddress) {
void ContentChild::InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
uintptr_t aAddress) {
MOZ_ASSERT_IF(!aHandle, !aAddress);
if (!aAddress) {
@@ -2350,7 +2349,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRegisterStringBundles(
for (auto& descriptor : aDescriptors) {
stringBundleService->RegisterContentBundle(
descriptor.bundleURL(), std::move(descriptor.mapHandle()));
descriptor.bundleURL(), descriptor.mapHandle(), descriptor.mapSize());
}
return IPC_OK();
@@ -2370,7 +2369,7 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateL10nFileSources(
}
mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
mozilla::ipc::ReadOnlySharedMemoryHandle&& aMapHandle,
SharedMemoryHandle&& aMapHandle, const uint32_t& aMapSize,
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
for (auto& ipcBlob : aBlobs) {
@@ -2378,12 +2377,12 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
}
if (mSharedData) {
mSharedData->Update(std::move(aMapHandle), std::move(blobImpls),
mSharedData->Update(std::move(aMapHandle), aMapSize, std::move(blobImpls),
std::move(aChangedKeys));
} else {
mSharedData =
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
std::move(aMapHandle), std::move(blobImpls));
std::move(aMapHandle), aMapSize, std::move(blobImpls));
}
return IPC_OK();
@@ -2444,7 +2443,7 @@ mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList(
mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
const uint32_t& aGeneration, const uint32_t& aIndex,
mozilla::ipc::ReadOnlySharedMemoryHandle&& aHandle) {
SharedMemoryHandle&& aHandle) {
if (gfxPlatform::Initialized()) {
gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
std::move(aHandle));

View File

@@ -17,7 +17,6 @@
#include "mozilla/Hal.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsClassHashtable.h"
@@ -120,9 +119,8 @@ class ContentChild final : public PContentChild,
const mozilla::dom::ipc::StructuredCloneData& aInitialData,
bool aIsReadyForBackgroundProcessing);
void InitSharedUASheets(
Maybe<mozilla::ipc::ReadOnlySharedMemoryHandle>&& aHandle,
uintptr_t aAddress);
void InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
uintptr_t aAddress);
void InitGraphicsDeviceData(const ContentDeviceData& aData);
@@ -311,7 +309,7 @@ class ContentChild final : public PContentChild,
nsTArray<L10nFileSourceDescriptor>&& aDescriptors);
mozilla::ipc::IPCResult RecvUpdateSharedData(
mozilla::ipc::ReadOnlySharedMemoryHandle&& aMapHandle,
SharedMemoryHandle&& aMapHandle, const uint32_t& aMapSize,
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
mozilla::ipc::IPCResult RecvForceGlobalReflow(
@@ -331,7 +329,7 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvRebuildFontList(const bool& aFullRebuild);
mozilla::ipc::IPCResult RecvFontListShmBlockAdded(
const uint32_t& aGeneration, const uint32_t& aIndex,
mozilla::ipc::ReadOnlySharedMemoryHandle&& aHandle);
SharedMemoryHandle&& aHandle);
mozilla::ipc::IPCResult RecvUpdateAppLocales(
nsTArray<nsCString>&& aAppLocales);
@@ -505,10 +503,9 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList,
Maybe<mozilla::ipc::ReadOnlySharedMemoryHandle>&& aSharedUASheetHandle,
Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress,
nsTArray<mozilla::ipc::ReadOnlySharedMemoryHandle>&&
aSharedFontListBlocks,
nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
const bool& aIsReadyForBackgroundProcessing);
mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
@@ -538,7 +535,7 @@ class ContentChild final : public PContentChild,
// for use during gfx initialization.
SystemFontList& SystemFontList() { return mFontList; }
nsTArray<mozilla::ipc::ReadOnlySharedMemoryHandle>& SharedFontListBlocks() {
nsTArray<SharedMemoryHandle>& SharedFontListBlocks() {
return mSharedFontListBlocks;
}
@@ -837,7 +834,7 @@ class ContentChild final : public PContentChild,
// Temporary storage for look and feel data.
FullLookAndFeel mLookAndFeelData;
// Temporary storage for list of shared-fontlist memory blocks.
nsTArray<mozilla::ipc::ReadOnlySharedMemoryHandle> mSharedFontListBlocks;
nsTArray<SharedMemoryHandle> mSharedFontListBlocks;
AppInfo mAppInfo;

View File

@@ -152,7 +152,7 @@
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/ipc/TestShellParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/ImageBridgeParent.h"
@@ -1536,8 +1536,9 @@ void ContentParent::BroadcastStringBundle(
const StringBundleDescriptor& aBundle) {
for (auto* cp : AllProcesses(eLive)) {
AutoTArray<StringBundleDescriptor, 1> array;
array.AppendElement(StringBundleDescriptor(aBundle.bundleURL(),
aBundle.mapHandle().Clone()));
array.AppendElement(StringBundleDescriptor(
aBundle.bundleURL(), SharedMemory::CloneHandle(aBundle.mapHandle()),
aBundle.mapSize()));
Unused << cp->SendRegisterStringBundles(std::move(array));
}
}
@@ -1546,9 +1547,9 @@ void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
uint32_t aIndex) {
auto* pfl = gfxPlatformFontList::PlatformFontList();
for (auto* cp : AllProcesses(eLive)) {
ReadOnlySharedMemoryHandle handle =
SharedMemory::Handle handle =
pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
if (!handle.IsValid()) {
if (handle == SharedMemory::NULLHandle()) {
// If something went wrong here, we just skip it; the child will need to
// request the block as needed, at some performance cost.
continue;
@@ -2810,7 +2811,7 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
// If the shared fontlist is in use, collect its shmem block handles to pass
// to the child.
nsTArray<ReadOnlySharedMemoryHandle> sharedFontListBlocks;
nsTArray<SharedMemoryHandle> sharedFontListBlocks;
gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
&sharedFontListBlocks, OtherPid());
@@ -2849,10 +2850,10 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
screenManager.CopyScreensToRemote(this);
// Send the UA sheet shared memory buffer and the address it is mapped at.
Maybe<ReadOnlySharedMemoryHandle> sharedUASheetHandle;
Maybe<SharedMemoryHandle> sharedUASheetHandle;
uintptr_t sharedUASheetAddress = sheetCache->GetSharedMemoryAddress();
if (ReadOnlySharedMemoryHandle handle = sheetCache->CloneHandle()) {
if (SharedMemoryHandle handle = sheetCache->CloneHandle()) {
sharedUASheetHandle.emplace(std::move(handle));
} else {
sharedUASheetAddress = 0;
@@ -5627,7 +5628,7 @@ mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
const uint32_t& aGeneration, const uint32_t& aIndex,
ReadOnlySharedMemoryHandle* aOut) {
SharedMemory::Handle* aOut) {
auto* fontList = gfxPlatformFontList::PlatformFontList();
MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
@@ -5679,12 +5680,12 @@ mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
}
mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
nsIURI* aURI, ReadOnlySharedMemoryHandle* aOutHandle) {
nsIURI* aURI, SharedMemory::Handle* aOutHandle, uint32_t* aOutSize) {
if (!aURI) {
return IPC_FAIL(this, "aURI must not be null.");
}
nsHyphenationManager::Instance()->ShareHyphDictToProcess(aURI, Pid(),
aOutHandle);
nsHyphenationManager::Instance()->ShareHyphDictToProcess(
aURI, Pid(), aOutHandle, aOutSize);
return IPC_OK();
}

View File

@@ -22,7 +22,7 @@
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/Attributes.h"
#include "mozilla/DataMutex.h"
#include "mozilla/HalTypes.h"
@@ -1125,7 +1125,7 @@ class ContentParent final : public PContentParent,
mozilla::ipc::IPCResult RecvGetFontListShmBlock(
const uint32_t& aGeneration, const uint32_t& aIndex,
mozilla::ipc::ReadOnlySharedMemoryHandle* aOut);
mozilla::ipc::SharedMemory::Handle* aOut);
mozilla::ipc::IPCResult RecvInitializeFamily(const uint32_t& aGeneration,
const uint32_t& aFamilyIndex,
@@ -1149,7 +1149,8 @@ class ContentParent final : public PContentParent,
const uint32_t& aStartIndex);
mozilla::ipc::IPCResult RecvGetHyphDict(
nsIURI* aURIParams, mozilla::ipc::ReadOnlySharedMemoryHandle* aOutHandle);
nsIURI* aURIParams, mozilla::ipc::SharedMemory::Handle* aOutHandle,
uint32_t* aOutSize);
mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsAString& aCodecName,
const uint32_t& aDecodeFPS);

View File

@@ -72,9 +72,10 @@ void ContentProcess::InfallibleInit(int aArgc, char* aArgv[]) {
Maybe<const char*> parentBuildID =
geckoargs::sParentBuildID.Get(aArgc, aArgv);
// command line: -jsInitHandle handle
Maybe<mozilla::ipc::ReadOnlySharedMemoryHandle> jsInitHandle =
// command line: -jsInitHandle handle -jsInitLen length
Maybe<mozilla::ipc::SharedMemoryHandle> jsInitHandle =
geckoargs::sJsInitHandle.Get(aArgc, aArgv);
Maybe<uint64_t> jsInitLen = geckoargs::sJsInitLen.Get(aArgc, aArgv);
nsCOMPtr<nsIFile> appDirArg;
Maybe<const char*> appDir = geckoargs::sAppDir.Get(aArgc, aArgv);
@@ -130,8 +131,8 @@ void ContentProcess::InfallibleInit(int aArgc, char* aArgv[]) {
MOZ_CRASH("InitPrefs failed");
}
if (jsInitHandle &&
!::mozilla::ipc::ImportSharedJSInit(jsInitHandle.extract())) {
if (jsInitHandle && jsInitLen &&
!::mozilla::ipc::ImportSharedJSInit(jsInitHandle.extract(), *jsInitLen)) {
MOZ_CRASH("ImportSharedJSInit failed");
}

View File

@@ -7,36 +7,40 @@
#include "MemMapSnapshot.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
namespace mozilla::ipc {
Result<Ok, nsresult> MemMapSnapshot::Init(size_t aSize) {
MOZ_ASSERT(!mMem);
auto handle = shared_memory::CreateFreezable(aSize);
if (NS_WARN_IF(!handle)) {
auto aMem = MakeRefPtr<SharedMemory>();
if (NS_WARN_IF(!aMem->CreateFreezable(aSize))) {
return Err(NS_ERROR_FAILURE);
}
if (NS_WARN_IF(!aMem->Map(aSize))) {
return Err(NS_ERROR_FAILURE);
}
auto mem = std::move(handle).Map();
if (NS_WARN_IF(!mem)) {
return Err(NS_ERROR_FAILURE);
}
mMem = std::move(mem);
mMem = std::move(aMem);
return Ok();
}
Result<ReadOnlySharedMemoryHandle, nsresult> MemMapSnapshot::Finalize() {
Result<Ok, nsresult> MemMapSnapshot::Finalize(RefPtr<SharedMemory>& aMem) {
MOZ_ASSERT(mMem);
auto [_, readOnlyHandle] = std::move(mMem).Freeze();
if (NS_WARN_IF(!readOnlyHandle)) {
auto size = mMem->Size();
if (NS_WARN_IF(!mMem->Freeze())) {
return Err(NS_ERROR_FAILURE);
}
return std::move(readOnlyHandle);
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 Ok();
}
} // namespace mozilla::ipc

View File

@@ -12,7 +12,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/RangedPtr.h"
#include "mozilla/Result.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "ErrorList.h"
namespace mozilla::ipc {
@@ -23,7 +23,7 @@ namespace mozilla::ipc {
* The Init() method initializes a read-write memory mapped region of the given
* size, which can be initialized with arbitrary data. The Finalize() method
* remaps that region as read-only (and backs it with a read-only file
* descriptor), and returns a handle to it.
* descriptor), and initializes an AutoMemMap with the new contents.
*
* The file descriptor for the resulting AutoMemMap can be shared among
* processes, to safely access a shared, read-only copy of the data snapshot.
@@ -31,17 +31,16 @@ namespace mozilla::ipc {
class MOZ_RAII MemMapSnapshot {
public:
Result<Ok, nsresult> Init(size_t aSize);
Result<ReadOnlySharedMemoryHandle, nsresult> Finalize();
Result<Ok, nsresult> Finalize(RefPtr<SharedMemory>& aMem);
template <typename T>
RangedPtr<T> Get() {
MOZ_ASSERT(mMem);
auto span = mMem.DataAsSpan<T>();
return {span.data(), span.size()};
return {static_cast<T*>(mMem->Memory()), mMem->MaxSize() / sizeof(T)};
}
private:
FreezableSharedMemoryMapping mMem;
RefPtr<SharedMemory> mMem;
};
} // namespace mozilla::ipc

View File

@@ -139,7 +139,7 @@ using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext
using mozilla::dom::PermitUnloadResult from "nsIDocumentViewer.h";
using mozilla::dom::MaybeDiscardedWindowContext from "mozilla/dom/WindowContext.h";
using mozilla::dom::WindowContextTransaction from "mozilla/dom/WindowContext.h";
[MoveOnly] using mozilla::ipc::ReadOnlySharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
[MoveOnly] using mozilla::ipc::SharedMemoryHandle from "mozilla/ipc/SharedMemory.h";
using gfxSparseBitSet from "gfxFontUtils.h";
using FontVisibility from "gfxFontEntry.h";
using mozilla::dom::MediaControlAction from "mozilla/dom/MediaControlKeySource.h";
@@ -400,7 +400,8 @@ struct VisitedQueryResult
struct StringBundleDescriptor
{
nsCString bundleURL;
ReadOnlySharedMemoryHandle mapHandle;
SharedMemoryHandle mapHandle;
uint32_t mapSize;
};
struct IPCURLClassifierFeature
@@ -714,7 +715,7 @@ child:
* should map the new block and add to its index.
*/
async FontListShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
ReadOnlySharedMemoryHandle aHandle);
SharedMemoryHandle aHandle);
async UpdateAppLocales(nsCString[] appLocales);
async UpdateRequestedLocales(nsCString[] requestedLocales);
@@ -731,7 +732,7 @@ child:
async SimpleURIUnknownRemoteSchemes(nsCString[] remoteSchemes);
async UpdateSharedData(ReadOnlySharedMemoryHandle aMapHandle,
async UpdateSharedData(SharedMemoryHandle aMapHandle, uint32_t aSize,
IPCBlob[] blobs,
nsCString[] changedKeys);
@@ -802,9 +803,9 @@ child:
FullLookAndFeel lookAndFeeldata,
/* used on MacOSX/Linux/Android only: */
SystemFontList systemFontList,
ReadOnlySharedMemoryHandle? sharedUASheetHandle,
SharedMemoryHandle? sharedUASheetHandle,
uintptr_t sharedUASheetAddress,
ReadOnlySharedMemoryHandle[] sharedFontListBlocks,
SharedMemoryHandle[] sharedFontListBlocks,
bool aIsStartingUp);
// Notify child that last-pb-context-exited notification was observed
@@ -1376,7 +1377,7 @@ parent:
* until it has mapped the font-list memory.
*/
sync GetFontListShmBlock(uint32_t aGeneration, uint32_t aIndex)
returns (ReadOnlySharedMemoryHandle aHandle);
returns (SharedMemoryHandle aHandle);
/**
* Ask the parent to initialize a given font family, so that face metadata
@@ -1494,7 +1495,7 @@ parent:
* @param aLoaded
* Returns the size in bytes of the resource.
*/
sync GetHyphDict(nullable nsIURI aURI) returns (ReadOnlySharedMemoryHandle aHandle);
sync GetHyphDict(nullable nsIURI aURI) returns (SharedMemoryHandle aHandle, uint32_t aSize);
async CreateWindow(PBrowser aThisTab,
MaybeDiscardedBrowsingContext aParent,

View File

@@ -43,10 +43,11 @@ static inline void AlignTo(size_t* aOffset, size_t aAlign) {
SharedMap::SharedMap() = default;
SharedMap::SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&& aMapHandle,
nsTArray<RefPtr<BlobImpl>>&& aBlobs)
size_t aMapSize, nsTArray<RefPtr<BlobImpl>>&& aBlobs)
: DOMEventTargetHelper(aGlobal),
mBlobImpls(std::move(aBlobs)),
mHandle(std::move(aMapHandle)) {}
mMapHandle(std::move(aMapHandle)),
mMapSize(aMapSize) {}
bool SharedMap::Has(const nsACString& aName) {
Unused << MaybeRebuild();
@@ -96,13 +97,21 @@ void SharedMap::Entry::Read(JSContext* aCx,
holder.Read(aCx, aRetVal, aRv);
}
void SharedMap::Update(SharedMemoryHandle&& aMapHandle,
SharedMap::SharedMemoryHandle SharedMap::CloneHandle() const {
if (mMap->IsValid()) {
return mMap->CloneHandle();
}
return SharedMemory::CloneHandle(mMapHandle);
}
void SharedMap::Update(SharedMemoryHandle&& aMapHandle, size_t aMapSize,
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
nsTArray<nsCString>&& aChangedKeys) {
MOZ_DIAGNOSTIC_ASSERT(!mWritable);
mMapping = nullptr;
mHandle = std::move(aMapHandle);
mMap->TakeHandleAndUnmap();
mMapHandle = std::move(aMapHandle);
mMapSize = aMapSize;
mEntries.Clear();
mEntryArray.reset();
@@ -182,12 +191,10 @@ void SharedMap::Entry::ExtractData(char* aDestPtr, uint32_t aNewOffset,
}
Result<Ok, nsresult> SharedMap::MaybeRebuild() {
if (mMapping || !mHandle) {
if (!SharedMemory::IsHandleValid(mMapHandle)) {
return Ok();
}
MOZ_DIAGNOSTIC_ASSERT(!mWritable);
// This function maps a shared memory region created by Serialize() and reads
// its header block to build a new mEntries hashtable of its contents.
//
@@ -196,20 +203,24 @@ Result<Ok, nsresult> SharedMap::MaybeRebuild() {
// its shared memory region. When needed, that structured clone data is
// retrieved directly as indexes into the SharedMap's shared memory region.
mMapping = mHandle.Map();
if (!mMapping) {
if (!mMap->SetHandle(SharedMemory::CloneHandle(mMapHandle),
SharedMemory::OpenRights::RightsReadOnly)) {
return Err(NS_ERROR_FAILURE);
}
mMapHandle = SharedMemory::NULLHandle();
if (!mMap->Map(mMapSize)) {
return Err(NS_ERROR_FAILURE);
}
mHandle = nullptr;
Range<const uint8_t> inputRange(mMapping.DataAsSpan<uint8_t>());
InputBuffer buffer(inputRange);
// 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
// initializes everything to 0.
Range<uint8_t> range((uint8_t*)mMap->Memory(), mMap->Size());
InputBuffer buffer(range);
uint32_t count;
buffer.codeUint32(count);
MOZ_ASSERT(mEntries.IsEmpty());
MOZ_ASSERT(mEntryArray.isNothing());
for (uint32_t i = 0; i < count; i++) {
auto entry = MakeUnique<Entry>(*this);
entry->Code(buffer);
@@ -235,9 +246,9 @@ void SharedMap::MaybeRebuild() const {
WritableSharedMap::WritableSharedMap() {
mWritable = true;
// Serialize the initial empty contents of the map immediately so that we
// always have a file descriptor to send.
// always have a file descriptor to send to callers of CloneMapFile().
Unused << Serialize();
MOZ_RELEASE_ASSERT(mHandle.IsValid() && mMapping.IsValid());
MOZ_RELEASE_ASSERT(mMap->IsValid());
}
SharedMap* WritableSharedMap::GetReadOnly() {
@@ -245,7 +256,7 @@ SharedMap* WritableSharedMap::GetReadOnly() {
nsTArray<RefPtr<BlobImpl>> blobs(mBlobImpls.Clone());
mReadOnly =
new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
mHandle.Clone(), std::move(blobs));
CloneHandle(), MapSize(), std::move(blobs));
}
return mReadOnly;
}
@@ -328,11 +339,8 @@ Result<Ok, nsresult> WritableSharedMap::Serialize() {
memcpy(ptr.get(), header.Get(), header.cursor());
// We've already updated offsets at this point. We need this to succeed.
auto result = mem.Finalize();
MOZ_RELEASE_ASSERT(result.isOk());
mHandle = result.unwrap();
mMapping = mHandle.Map();
MOZ_RELEASE_ASSERT(mMapping.IsValid());
mMap->TakeHandleAndUnmap();
MOZ_RELEASE_ASSERT(mem.Finalize(mMap).isOk());
return Ok();
}
@@ -347,7 +355,8 @@ void WritableSharedMap::SendTo(ContentParent* aParent) const {
}
}
Unused << aParent->SendUpdateSharedData(mHandle.Clone(), blobs, mChangedKeys);
Unused << aParent->SendUpdateSharedData(CloneHandle(), mMap->Size(), blobs,
mChangedKeys);
}
void WritableSharedMap::BroadcastChanges() {
@@ -367,7 +376,7 @@ void WritableSharedMap::BroadcastChanges() {
if (mReadOnly) {
nsTArray<RefPtr<BlobImpl>> blobImpls(mBlobImpls.Clone());
mReadOnly->Update(mHandle.Clone(), std::move(blobImpls),
mReadOnly->Update(CloneHandle(), mMap->Size(), std::move(blobImpls),
std::move(mChangedKeys));
}

View File

@@ -10,8 +10,7 @@
#include "mozilla/dom/MozSharedMapBinding.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
@@ -54,14 +53,13 @@ namespace ipc {
* WritableSharedMap instances.
*/
class SharedMap : public DOMEventTargetHelper {
protected:
using SharedMemoryMapping = mozilla::ipc::ReadOnlySharedMemoryMapping;
using SharedMemoryHandle = mozilla::ipc::ReadOnlySharedMemoryHandle;
using SharedMemory = mozilla::ipc::SharedMemory;
using SharedMemoryHandle = mozilla::ipc::SharedMemoryHandle;
public:
SharedMap();
SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&&,
SharedMap(nsIGlobalObject* aGlobal, SharedMemoryHandle&&, size_t,
nsTArray<RefPtr<BlobImpl>>&& aBlobs);
// Returns true if the map contains the given (UTF-8) key.
@@ -95,16 +93,26 @@ class SharedMap : public DOMEventTargetHelper {
JS::MutableHandle<JS::Value> aResult) const;
/**
* Returns the size of the memory mapped region that backs this map.
* Returns a copy of the read-only file descriptor which backs the shared
* memory region for this map. The file descriptor may be passed between
* processes, and used to update corresponding instances in child processes.
*/
size_t MapSize() const { return mMapping.Size(); }
SharedMemoryHandle CloneHandle() const;
/**
* Returns the size of the memory mapped region that backs this map. Must be
* passed to the SharedMap() constructor or Update() method along with the
* descriptor returned by CloneMapFile() in order to initialize or update a
* child SharedMap.
*/
size_t MapSize() const { return mMap->Size(); }
/**
* 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
* changed (UTF-8-encoded) keys.
*/
void Update(SharedMemoryHandle&& aMapHandle,
void Update(SharedMemoryHandle&& aMapHandle, size_t aMapSize,
nsTArray<RefPtr<BlobImpl>>&& aBlobs,
nsTArray<nsCString>&& aChangedKeys);
@@ -255,20 +263,24 @@ class SharedMap : public DOMEventTargetHelper {
Result<Ok, nsresult> MaybeRebuild();
void MaybeRebuild() const;
SharedMemoryHandle mMapHandle;
// The size of the memory-mapped region backed by mMap, in bytes.
size_t mMapSize = 0;
mutable nsClassHashtable<nsCStringHashKey, Entry> mEntries;
mutable Maybe<nsTArray<Entry*>> mEntryArray;
// Manages the memory mapping of the current snapshot. This is initialized
// lazily after each SharedMap construction or update.
SharedMemoryHandle mHandle;
SharedMemoryMapping mMapping;
// lazily after each SharedMap construction or updated, based on the values in
// mMapFile and mMapSize.
RefPtr<SharedMemory> mMap = MakeRefPtr<SharedMemory>();
bool mWritable = false;
// Returns a pointer to the beginning of the memory mapped snapshot. Entry
// offsets are relative to this pointer, and Entry objects access their
// structured clone data by indexing this pointer.
const char* Data() { return mMapping.DataAs<char>(); }
char* Data() { return static_cast<char*>(mMap->Memory()); }
};
class WritableSharedMap final : public SharedMap {

View File

@@ -27,36 +27,42 @@ static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
return mod ? aAlign - mod : 0;
}
SharedStringMap::SharedStringMap(const ReadOnlySharedMemoryHandle& aMapHandle) {
mHandle = aMapHandle.Clone();
MOZ_RELEASE_ASSERT(mHandle.IsValid());
auto mapping = aMapHandle.Map();
MOZ_RELEASE_ASSERT(mapping.IsValid());
SharedStringMap::SharedStringMap(const SharedMemoryHandle& aMapHandle,
size_t aMapSize) {
auto map = MakeRefPtr<SharedMemory>();
{
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 nsStrings and nsCStrings pointing to the mapped data,
// 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
// mapping alive until process shutdown, in order to be safe.
mMappedMemory = std::move(mapping).Release();
mMappedMemory = map->TakeMapping();
mHandle = map->TakeHandle();
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
}
SharedStringMap::SharedStringMap(SharedStringMapBuilder&& aBuilder) {
ReadOnlySharedMemoryMappingWithHandle mappingWithHandle;
auto result = aBuilder.Finalize();
MOZ_RELEASE_ASSERT(result.isOk());
mHandle = result.unwrap();
auto mapping = mHandle.Map();
MOZ_RELEASE_ASSERT(mapping.IsValid());
RefPtr<SharedMemory> map;
auto result = aBuilder.Finalize(map);
MOZ_RELEASE_ASSERT(result.isOk() && map);
mMappedMemory = std::move(mapping).Release();
mMappedMemory = map->TakeMapping();
mHandle = map->TakeHandle();
MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic);
}
mozilla::ipc::ReadOnlySharedMemoryHandle SharedStringMap::CloneHandle() const {
return mHandle.Clone();
mozilla::ipc::SharedMemoryHandle SharedStringMap::CloneHandle() const {
return SharedMemory::CloneHandle(mHandle);
}
bool SharedStringMap::Has(const nsCString& aKey) {
@@ -91,8 +97,8 @@ void SharedStringMapBuilder::Add(const nsCString& aKey,
Entry{mKeyTable.Add(aKey), mValueTable.Add(aValue)});
}
Result<ReadOnlySharedMemoryHandle, nsresult>
SharedStringMapBuilder::Finalize() {
Result<Ok, nsresult> SharedStringMapBuilder::Finalize(
RefPtr<SharedMemory>& aMap) {
using Header = SharedStringMap::Header;
MOZ_ASSERT(mEntries.Count() == mKeyTable.Count());
@@ -141,7 +147,7 @@ SharedStringMapBuilder::Finalize() {
mValueTable.Clear();
mEntries.Clear();
return mem.Finalize();
return mem.Finalize(aMap);
}
} // namespace dom::ipc

View File

@@ -9,8 +9,7 @@
#include "mozilla/Result.h"
#include "mozilla/dom/ipc/StringTable.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "nsTHashMap.h"
namespace mozilla::dom::ipc {
@@ -89,7 +88,7 @@ class SharedStringMap {
// Note: These constructors are infallible on the premise that this class
// is used primarily in cases where it is critical to platform
// functionality.
explicit SharedStringMap(const mozilla::ipc::ReadOnlySharedMemoryHandle&);
explicit SharedStringMap(const mozilla::ipc::SharedMemoryHandle&, size_t);
explicit SharedStringMap(SharedStringMapBuilder&&);
/**
@@ -152,7 +151,7 @@ class SharedStringMap {
* used to construct new instances of SharedStringMap with the same data as
* this instance.
*/
mozilla::ipc::ReadOnlySharedMemoryHandle CloneHandle() const;
mozilla::ipc::SharedMemoryHandle CloneHandle() const;
size_t MapSize() const { return mMappedMemory.size(); }
@@ -173,23 +172,21 @@ class SharedStringMap {
StringTable<nsCString> KeyTable() const {
const auto& header = GetHeader();
return {
{const_cast<uint8_t*>(&mMappedMemory.data()[header.mKeyStringsOffset]),
header.mKeyStringsSize}};
return {{&mMappedMemory.data()[header.mKeyStringsOffset],
header.mKeyStringsSize}};
}
StringTable<nsString> ValueTable() const {
const auto& header = GetHeader();
return {{const_cast<uint8_t*>(
&mMappedMemory.data()[header.mValueStringsOffset]),
return {{&mMappedMemory.data()[header.mValueStringsOffset],
header.mValueStringsSize}};
}
mozilla::ipc::ReadOnlySharedMemoryHandle mHandle;
mozilla::ipc::SharedMemoryHandle mHandle;
// This is a leaked shared memory mapping (see the constructor definition for
// an explanation). It replaces AutoMemMap::setPersistent behavior as part of
// bug 1454816.
mozilla::ipc::shared_memory::LeakedReadOnlyMapping mMappedMemory;
Span<uint8_t> mMappedMemory;
};
/**
@@ -208,9 +205,10 @@ class MOZ_RAII SharedStringMapBuilder {
/**
* Finalizes the binary representation of the map, writes it to a shared
* memory region, and then returns a read-only handle to it.
* memory region, and then initializes the given SharedMemory with a reference
* to the read-only copy of it.
*/
Result<mozilla::ipc::ReadOnlySharedMemoryHandle, nsresult> Finalize();
Result<Ok, nsresult> Finalize(RefPtr<mozilla::ipc::SharedMemory>& aMap);
private:
using Entry = SharedStringMap::Entry;

View File

@@ -22,7 +22,7 @@
#include "mozilla/ipc/GeckoChildProcessHost.h"
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
# include "mozilla/SandboxInfo.h"
# include "mozilla/ipc/SharedMemoryHandle.h"
# include "mozilla/ipc/SharedMemory.h"
#endif
#include "mozilla/Services.h"
#include "mozilla/SSE.h"
@@ -303,7 +303,7 @@ class NotifyGMPProcessLoadedTask : public Runnable {
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
if (SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia) &&
ipc::shared_memory::UsingPosixShm()) {
ipc::SharedMemory::UsingPosixShm()) {
canProfile = false;
}
#endif

View File

@@ -18,9 +18,11 @@ void GMPProcessChild::InitStatics(int aArgc, char* aArgv[]) {
Maybe<bool> nativeEvent = geckoargs::sPluginNativeEvent.Get(aArgc, aArgv);
sUseNativeEventProcessing = nativeEvent.isSome() && *nativeEvent;
auto prefsHandlePresent = geckoargs::sPrefsHandle.IsPresent(aArgc, aArgv);
auto prefMapHandlePresent = geckoargs::sPrefMapHandle.IsPresent(aArgc, aArgv);
sUseXpcom = prefsHandlePresent && prefMapHandlePresent;
Maybe<uint64_t> prefsLen =
geckoargs::sPrefsLen.Get(aArgc, aArgv, CheckArgFlag::None);
Maybe<uint64_t> prefMapSize =
geckoargs::sPrefMapSize.Get(aArgc, aArgv, CheckArgFlag::None);
sUseXpcom = prefsLen.isSome() && prefMapSize.isSome();
}
GMPProcessChild::~GMPProcessChild() = default;

View File

@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPSharedMemManager.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
namespace mozilla::gmp {
@@ -49,7 +49,7 @@ bool GMPSharedMemManager::MgrTakeShmem(GMPSharedMemClass aClass, size_t aSize,
MOZ_ASSERT(MgrIsOnOwningThread());
auto& pool = mPool[size_t(aClass)];
size_t alignedSize = ipc::shared_memory::PageAlignedSize(aSize);
size_t alignedSize = ipc::SharedMemory::PageAlignedSize(aSize);
PurgeSmallerShmem(pool, alignedSize);
if (pool.IsEmpty()) {
return MgrAllocShmem(alignedSize, aMem);

View File

@@ -42,10 +42,11 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Buffer)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
Buffer::Buffer(Device* const aParent, RawId aId, BufferAddress aSize,
uint32_t aUsage, ipc::SharedMemoryMapping&& aShmem)
uint32_t aUsage, ipc::WritableSharedMemoryMapping&& aShmem)
: ChildOf(aParent), mId(aId), mSize(aSize), mUsage(aUsage) {
mozilla::HoldJSObjects(this);
mShmem = std::make_shared<ipc::SharedMemoryMapping>(std::move(aShmem));
mShmem =
std::make_shared<ipc::WritableSharedMemoryMapping>(std::move(aShmem));
MOZ_ASSERT(mParent);
}
@@ -62,14 +63,14 @@ already_AddRefed<Buffer> Buffer::Create(Device* aDevice, RawId aDeviceId,
if (!aDevice->IsBridgeAlive()) {
// Create and return an invalid Buffer.
RefPtr<Buffer> buffer =
new Buffer(aDevice, bufferId, aDesc.mSize, 0, nullptr);
RefPtr<Buffer> buffer = new Buffer(aDevice, bufferId, aDesc.mSize, 0,
ipc::WritableSharedMemoryMapping());
buffer->mValid = false;
return buffer.forget();
}
ipc::MutableSharedMemoryHandle handle;
ipc::SharedMemoryMapping mapping;
auto handle = ipc::UnsafeSharedMemoryHandle();
auto mapping = ipc::WritableSharedMemoryMapping();
bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE |
dom::GPUBufferUsage_Binding::MAP_READ);
@@ -84,18 +85,17 @@ already_AddRefed<Buffer> Buffer::Create(Device* aDevice, RawId aDeviceId,
size_t size = checked.value();
if (size > 0 && size < maxSize) {
handle = ipc::shared_memory::Create(size);
mapping = handle.Map();
if (handle && mapping) {
auto maybeShmem = ipc::UnsafeSharedMemoryHandle::CreateAndMap(size);
if (maybeShmem.isSome()) {
allocSucceeded = true;
handle = std::move(maybeShmem.ref().first);
mapping = std::move(maybeShmem.ref().second);
MOZ_RELEASE_ASSERT(mapping.Size() >= size);
// zero out memory
memset(mapping.Address(), 0, size);
} else {
handle = nullptr;
mapping = nullptr;
memset(mapping.Bytes().data(), 0, size);
}
}
@@ -259,7 +259,8 @@ already_AddRefed<dom::Promise> Buffer::MapAsync(
static void ExternalBufferFreeCallback(void* aContents, void* aUserData) {
Unused << aContents;
auto shm = static_cast<std::shared_ptr<ipc::SharedMemoryMapping>*>(aUserData);
auto shm = static_cast<std::shared_ptr<ipc::WritableSharedMemoryMapping>*>(
aUserData);
delete shm;
}
@@ -352,8 +353,8 @@ void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset,
// unfortunately necessary: `JS::BufferContentsDeleter` requires that its
// `userData` be a `void*`, and while `shared_ptr` can't be inter-converted
// with `void*` (it's actually two pointers), `shared_ptr*` obviously can.
std::shared_ptr<ipc::SharedMemoryMapping>* data =
new std::shared_ptr<ipc::SharedMemoryMapping>(mShmem);
std::shared_ptr<ipc::WritableSharedMemoryMapping>* data =
new std::shared_ptr<ipc::WritableSharedMemoryMapping>(mShmem);
// 4. Let `view` be (potentially fallible operation follows) create an
// `ArrayBuffer` of size `rangeSize`, but with its pointer mutably
@@ -365,8 +366,7 @@ void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset,
// range for `size_t` before any conversion is performed.
const auto checkedSize = CheckedInt<size_t>(rangeSize.value()).value();
const auto checkedOffset = CheckedInt<size_t>(offset.value()).value();
const auto span =
(*data)->DataAsSpan<uint8_t>().Subspan(checkedOffset, checkedSize);
const auto span = (*data)->Bytes().Subspan(checkedOffset, checkedSize);
UniquePtr<void, JS::BufferContentsDeleter> contents{
span.data(), {&ExternalBufferFreeCallback, data}};
JS::Rooted<JSObject*> view(
@@ -431,7 +431,7 @@ void Buffer::Unmap(JSContext* aCx, ErrorResult& aRv) {
// We get here if the buffer was mapped at creation without map flags.
// It won't be possible to map the buffer again so we can get rid of
// our shmem on this side.
mShmem = std::make_shared<ipc::SharedMemoryMapping>();
mShmem = std::make_shared<ipc::WritableSharedMemoryMapping>();
}
if (!GetDevice().IsLost()) {

View File

@@ -8,10 +8,10 @@
#include "js/RootingAPI.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/webgpu/WebGPUTypes.h"
#include "nsTArray.h"
#include "ObjectModel.h"
#include "mozilla/ipc/RawShmem.h"
#include <memory>
namespace mozilla {
@@ -112,7 +112,7 @@ class Buffer final : public ObjectBase, public ChildOf<Device> {
private:
Buffer(Device* const aParent, RawId aId, BufferAddress aSize, uint32_t aUsage,
ipc::SharedMemoryMapping&& aShmem);
ipc::WritableSharedMemoryMapping&& aShmem);
virtual ~Buffer();
Device& GetDevice() { return *mParent; }
void Cleanup();
@@ -143,10 +143,10 @@ class Buffer final : public ObjectBase, public ChildOf<Device> {
// and destroyed when we first unmap the buffer, by clearing this
// `shared_ptr`.
//
// Otherwise, this points to `SharedMemoryMapping()` (the default
// constructor), a zero-length mapping that doesn't point to any shared
// memory.
std::shared_ptr<ipc::SharedMemoryMapping> mShmem;
// Otherwise, this points to `WritableSharedMemoryMapping()` (the
// default constructor), a zero-length mapping that doesn't point to
// any shared memory.
std::shared_ptr<ipc::WritableSharedMemoryMapping> mShmem;
};
} // namespace webgpu

View File

@@ -20,8 +20,6 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WebGLTexelConversions.h"
#include "mozilla/dom/WebGLTypes.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "nsLayoutUtils.h"
#include "Utility.h"
@@ -120,17 +118,16 @@ void Queue::WriteBuffer(const Buffer& aBuffer, uint64_t aBufferOffset,
return;
}
mozilla::ipc::MutableSharedMemoryHandle handle;
if (size != 0) {
handle = mozilla::ipc::shared_memory::Create(size);
auto mapping = handle.Map();
if (!handle || !mapping) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
memcpy(mapping.DataAs<uint8_t>(), aData.Elements() + offset, size);
auto alloc = mozilla::ipc::UnsafeSharedMemoryHandle::CreateAndMap(size);
if (alloc.isNothing()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
auto handle = std::move(alloc.ref().first);
auto mapping = std::move(alloc.ref().second);
memcpy(mapping.Bytes().data(), aData.Elements() + offset, size);
ipc::ByteBuf bb;
ffi::wgpu_queue_write_buffer(aBuffer.mId, aBufferOffset, ToFFI(&bb));
mBridge->SendQueueWriteAction(mId, mParent->mId, std::move(bb),
@@ -164,19 +161,18 @@ void Queue::WriteTexture(const dom::GPUTexelCopyTextureInfo& aDestination,
}
const auto size = checkedSize.value();
mozilla::ipc::MutableSharedMemoryHandle handle;
if (size != 0) {
handle = mozilla::ipc::shared_memory::Create(size);
auto mapping = handle.Map();
if (!handle || !mapping) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
memcpy(mapping.DataAs<uint8_t>(), aData.Elements() + aDataLayout.mOffset,
size);
auto alloc = mozilla::ipc::UnsafeSharedMemoryHandle::CreateAndMap(size);
if (alloc.isNothing()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
auto handle = std::move(alloc.ref().first);
auto mapping = std::move(alloc.ref().second);
memcpy(mapping.Bytes().data(), aData.Elements() + aDataLayout.mOffset,
size);
ipc::ByteBuf bb;
ffi::wgpu_queue_write_texture(copyView, dataLayout, extent, ToFFI(&bb));
mBridge->SendQueueWriteAction(mId, mParent->mId, std::move(bb),
@@ -399,15 +395,18 @@ void Queue::CopyExternalImageToTexture(
return;
}
auto handle = mozilla::ipc::shared_memory::Create(dstByteLength.value());
auto mapping = handle.Map();
if (!handle || !mapping) {
auto alloc = mozilla::ipc::UnsafeSharedMemoryHandle::CreateAndMap(
dstByteLength.value());
if (alloc.isNothing()) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
auto handle = std::move(alloc.ref().first);
auto mapping = std::move(alloc.ref().second);
const int32_t pixelSize = gfx::BytesPerPixel(surfaceFormat);
auto* dstBegin = mapping.DataAs<uint8_t>();
auto* dstBegin = mapping.Bytes().data();
const auto* srcBegin =
map.GetData() + srcOriginX * pixelSize + srcOriginY * map.GetStride();
const auto srcOriginPos = gl::OriginPos::TopLeft;

View File

@@ -17,7 +17,7 @@ using mozilla::dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h
using mozilla::dom::GPUBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
using mozilla::webgpu::PopErrorScopeResult from "mozilla/webgpu/WebGPUTypes.h";
using mozilla::webgpu::WebGPUCompilationMessage from "mozilla/webgpu/WebGPUTypes.h";
[MoveOnly] using mozilla::ipc::MutableSharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
[MoveOnly] using class mozilla::ipc::UnsafeSharedMemoryHandle from "mozilla/ipc/RawShmem.h";
using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
include "mozilla/ipc/ByteBufUtils.h";
@@ -48,7 +48,7 @@ parent:
async ComputePass(RawId selfId, RawId aDeviceId, ByteBuf buf);
async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId);
async DeviceCreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, MutableSharedMemoryHandle shm);
async DeviceCreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, UnsafeSharedMemoryHandle shm);
async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId aAdapterId) returns (ByteBuf byteBuf);
async AdapterRequestDevice(
@@ -77,8 +77,7 @@ parent:
async RenderBundleDrop(RawId selfId);
async QueueSubmit(RawId selfId, RawId aDeviceId, RawId[] commandBuffers, RawId[] textureIds);
async QueueOnSubmittedWorkDone(RawId selfId) returns (void_t ok);
// In the case of a zero-sized write action, `shmem` will be an invalid handle.
async QueueWriteAction(RawId selfId, RawId aDeviceId, ByteBuf buf, MutableSharedMemoryHandle shmem);
async QueueWriteAction(RawId selfId, RawId aDeviceId, ByteBuf buf, UnsafeSharedMemoryHandle shmem);
async BindGroupLayoutDrop(RawId selfId);
async PipelineLayoutDrop(RawId selfId);

View File

@@ -25,6 +25,7 @@
#include "PipelineLayout.h"
#include "Sampler.h"
#include "CompilationInfo.h"
#include "mozilla/ipc/RawShmem.h"
#include "Utility.h"
#include <utility>

View File

@@ -12,6 +12,9 @@
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla {
namespace ipc {
class UnsafeSharedMemoryHandle;
} // namespace ipc
namespace dom {
struct GPURequestAdapterOptions;
} // namespace dom

View File

@@ -549,10 +549,11 @@ WebGPUParent::BufferMapData* WebGPUParent::GetBufferMapData(RawId aBufferId) {
ipc::IPCResult WebGPUParent::RecvDeviceCreateBuffer(
RawId aDeviceId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc,
ipc::MutableSharedMemoryHandle&& aShmem) {
ipc::UnsafeSharedMemoryHandle&& aShmem) {
webgpu::StringHelper label(aDesc.mLabel);
auto shmem = aShmem.Map();
auto shmem =
ipc::WritableSharedMemoryMapping::Open(std::move(aShmem)).value();
bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE |
dom::GPUBufferUsage_Binding::MAP_READ);
@@ -663,7 +664,7 @@ void WebGPUParent::MapCallback(uint8_t* aUserData,
MOZ_RELEASE_ASSERT(mapData->mShmem.Size() >= offset + size);
if (src.ptr != nullptr && src.length >= size) {
auto dst = mapData->mShmem.DataAsSpan<uint8_t>().Subspan(offset, size);
auto dst = mapData->mShmem.Bytes().Subspan(offset, size);
memcpy(dst.data(), src.ptr, size);
}
}
@@ -746,7 +747,7 @@ ipc::IPCResult WebGPUParent::RecvBufferUnmap(RawId aDeviceId, RawId aBufferId,
MOZ_RELEASE_ASSERT(offset <= shmSize);
MOZ_RELEASE_ASSERT(size <= shmSize - offset);
auto src = mapData->mShmem.DataAsSpan<uint8_t>().Subspan(offset, size);
auto src = mapData->mShmem.Bytes().Subspan(offset, size);
memcpy(mapped.ptr, src.data(), size);
}
@@ -911,15 +912,14 @@ ipc::IPCResult WebGPUParent::RecvQueueOnSubmittedWorkDone(
ipc::IPCResult WebGPUParent::RecvQueueWriteAction(
RawId aQueueId, RawId aDeviceId, const ipc::ByteBuf& aByteBuf,
ipc::MutableSharedMemoryHandle&& aShmem) {
// `aShmem` may be an invalid handle, however this will simply result in an
// invalid mapping with 0 size, which is used safely below.
auto mapping = aShmem.Map();
ipc::UnsafeSharedMemoryHandle&& aShmem) {
auto mapping =
ipc::WritableSharedMemoryMapping::Open(std::move(aShmem)).value();
ErrorBuffer error;
ffi::wgpu_server_queue_write_action(
mContext.get(), aQueueId, ToFFI(&aByteBuf), mapping.DataAs<uint8_t>(),
mapping.Size(), error.ToFFI());
ffi::wgpu_server_queue_write_action(mContext.get(), aQueueId,
ToFFI(&aByteBuf), mapping.Bytes().data(),
mapping.Size(), error.ToFFI());
ForwardError(aDeviceId, error);
return IPC_OK();
}

View File

@@ -9,10 +9,10 @@
#include <unordered_map>
#include "mozilla/WeakPtr.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/webgpu/ffi/wgpu.h"
#include "mozilla/webgpu/PWebGPUParent.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/ipc/RawShmem.h"
#include "WebGPUTypes.h"
#include "base/timer.h"
@@ -56,9 +56,9 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
ipc::IPCResult RecvAdapterDrop(RawId aAdapterId);
ipc::IPCResult RecvDeviceDestroy(RawId aDeviceId);
ipc::IPCResult RecvDeviceDrop(RawId aDeviceId);
ipc::IPCResult RecvDeviceCreateBuffer(
RawId aDeviceId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc,
ipc::MutableSharedMemoryHandle&& aShmem);
ipc::IPCResult RecvDeviceCreateBuffer(RawId aDeviceId, RawId aBufferId,
dom::GPUBufferDescriptor&& aDesc,
ipc::UnsafeSharedMemoryHandle&& aShmem);
ipc::IPCResult RecvBufferMap(RawId aDeviceId, RawId aBufferId, uint32_t aMode,
uint64_t aOffset, uint64_t size,
BufferMapResolver&& aResolver);
@@ -83,7 +83,7 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
RawId aQueueId, std::function<void(mozilla::void_t)>&& aResolver);
ipc::IPCResult RecvQueueWriteAction(RawId aQueueId, RawId aDeviceId,
const ipc::ByteBuf& aByteBuf,
ipc::MutableSharedMemoryHandle&& aShmem);
ipc::UnsafeSharedMemoryHandle&& aShmem);
ipc::IPCResult RecvBindGroupLayoutDrop(RawId aBindGroupLayoutId);
ipc::IPCResult RecvPipelineLayoutDrop(RawId aPipelineLayoutId);
ipc::IPCResult RecvBindGroupDrop(RawId aBindGroupId);
@@ -141,7 +141,7 @@ class WebGPUParent final : public PWebGPUParent, public SupportsWeakPtr {
void ActorDestroy(ActorDestroyReason aWhy) override;
struct BufferMapData {
ipc::SharedMemoryMapping mShmem;
ipc::WritableSharedMemoryMapping mShmem;
// True if buffer's usage has MAP_READ or MAP_WRITE set.
bool mHasMapFlags;
uint64_t mMappedOffset;

View File

@@ -239,7 +239,7 @@ struct MemWriter {
// An istream like class for reading from memory
struct MemReader {
constexpr MemReader(const char* aData, size_t aLen)
constexpr MemReader(char* aData, size_t aLen)
: mData(aData), mEnd(aData + aLen) {}
void read(char* s, std::streamsize n) {
if (n <= (mEnd - mData)) {
@@ -255,8 +255,8 @@ struct MemReader {
bool good() { return !eof(); }
void SetIsBad() { mData = mEnd + 1; }
const char* mData;
const char* mEnd;
char* mData;
char* mEnd;
};
class ContiguousBuffer {

View File

@@ -10,6 +10,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/layers/TextureClient.h"
namespace mozilla {

View File

@@ -21,27 +21,28 @@ namespace mozilla {
namespace layers {
struct ShmemAndHandle {
ipc::SharedMemoryMapping shmem;
ipc::MutableSharedMemoryHandle handle;
RefPtr<ipc::SharedMemory> shmem;
Handle handle;
};
static Maybe<ShmemAndHandle> CreateAndMapShmem(size_t aSize) {
auto handle = ipc::shared_memory::Create(aSize);
if (!handle) {
return Nothing();
}
auto mapping = handle.Map();
if (!mapping) {
auto shmem = MakeRefPtr<ipc::SharedMemory>();
if (!shmem->Create(aSize) || !shmem->Map(aSize)) {
return Nothing();
}
return Some(ShmemAndHandle{std::move(mapping), std::move(handle)});
auto shmemHandle = shmem->TakeHandle();
if (!shmemHandle) {
return Nothing();
}
return Some(ShmemAndHandle{shmem.forget(), std::move(shmemHandle)});
}
CanvasDrawEventRecorder::CanvasDrawEventRecorder(
dom::ThreadSafeWorkerRef* aWorkerRef)
: mWorkerRef(aWorkerRef), mIsOnWorker(!!aWorkerRef) {
mDefaultBufferSize = ipc::shared_memory::PageAlignedSize(
mDefaultBufferSize = ipc::SharedMemory::PageAlignedSize(
StaticPrefs::gfx_canvas_remote_default_buffer_size());
mMaxDefaultBuffers = StaticPrefs::gfx_canvas_remote_max_default_buffers();
mMaxSpinCount = StaticPrefs::gfx_canvas_remote_max_spin_count();
@@ -65,7 +66,7 @@ bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
return false;
}
mHeader = header->shmem.DataAs<Header>();
mHeader = static_cast<Header*>(header->shmem->Memory());
mHeader->eventCount = 0;
mHeader->writerWaitCount = 0;
mHeader->writerState = State::Processing;
@@ -75,20 +76,20 @@ bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
// We always keep at least two buffers. This means that when we
// have to add a new buffer, there is at least a full buffer that requires
// translating while the handle is sent over.
AutoTArray<ipc::ReadOnlySharedMemoryHandle, 2> bufferHandles;
AutoTArray<Handle, 2> bufferHandles;
auto buffer = CreateAndMapShmem(mDefaultBufferSize);
if (NS_WARN_IF(buffer.isNothing())) {
return false;
}
mCurrentBuffer = CanvasBuffer(std::move(buffer->shmem));
bufferHandles.AppendElement(std::move(buffer->handle).ToReadOnly());
bufferHandles.AppendElement(std::move(buffer->handle));
buffer = CreateAndMapShmem(mDefaultBufferSize);
if (NS_WARN_IF(buffer.isNothing())) {
return false;
}
mRecycledBuffers.emplace(std::move(buffer->shmem), 0);
bufferHandles.AppendElement(std::move(buffer->handle).ToReadOnly());
mRecycledBuffers.emplace(buffer->shmem.forget(), 0);
bufferHandles.AppendElement(std::move(buffer->handle));
mWriterSemaphore.reset(CrossProcessSemaphore::Create("CanvasRecorder", 0));
auto writerSem = mWriterSemaphore->CloneHandle();
@@ -106,13 +107,13 @@ bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
if (!mHelpers->InitTranslator(aTextureType, aWebglTextureType, aBackendType,
std::move(header->handle),
std::move(bufferHandles), std::move(readerSem),
std::move(writerSem))) {
std::move(bufferHandles), mDefaultBufferSize,
std::move(readerSem), std::move(writerSem))) {
return false;
}
mTextureType = aTextureType;
mHeaderShmem = std::move(header->shmem);
mHeaderShmem = header->shmem;
return true;
}
@@ -245,7 +246,7 @@ gfx::ContiguousBuffer& CanvasDrawEventRecorder::GetContiguousBuffer(
}
size_t bufferSize = std::max(mDefaultBufferSize,
ipc::shared_memory::PageAlignedSize(aSize + 1));
ipc::SharedMemory::PageAlignedSize(aSize + 1));
auto newBuffer = CreateAndMapShmem(bufferSize);
if (NS_WARN_IF(newBuffer.isNothing())) {
mHeader->writerState = State::Failed;
@@ -253,7 +254,7 @@ gfx::ContiguousBuffer& CanvasDrawEventRecorder::GetContiguousBuffer(
return mCurrentBuffer;
}
if (!mHelpers->AddBuffer(std::move(newBuffer->handle).ToReadOnly())) {
if (!mHelpers->AddBuffer(std::move(newBuffer->handle), bufferSize)) {
mHeader->writerState = State::Failed;
mCurrentBuffer = CanvasBuffer();
return mCurrentBuffer;

View File

@@ -12,7 +12,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
@@ -27,6 +27,7 @@ class ThreadSafeWorkerRef;
namespace layers {
typedef mozilla::ipc::SharedMemory::Handle Handle;
typedef mozilla::CrossProcessSemaphoreHandle CrossProcessSemaphoreHandle;
class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
@@ -71,15 +72,16 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
public:
virtual ~Helpers() = default;
virtual bool InitTranslator(
TextureType aTextureType, TextureType aWebglTextureType,
gfx::BackendType aBackendType,
ipc::MutableSharedMemoryHandle&& aReadHandle,
nsTArray<ipc::ReadOnlySharedMemoryHandle>&& aBufferHandles,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem) = 0;
virtual bool InitTranslator(TextureType aTextureType,
TextureType aWebglTextureType,
gfx::BackendType aBackendType,
Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem) = 0;
virtual bool AddBuffer(ipc::ReadOnlySharedMemoryHandle&& aBufferHandle) = 0;
virtual bool AddBuffer(Handle&& aBufferHandle, uint64_t aBufferSize) = 0;
/**
* @returns true if the reader of the CanvasEventRingBuffer has permanently
@@ -161,28 +163,29 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
UniquePtr<Helpers> mHelpers;
TextureType mTextureType = TextureType::Unknown;
ipc::SharedMemoryMapping mHeaderShmem;
RefPtr<ipc::SharedMemory> mHeaderShmem;
Header* mHeader = nullptr;
struct CanvasBuffer : public gfx::ContiguousBuffer {
ipc::SharedMemoryMapping shmem;
RefPtr<ipc::SharedMemory> shmem;
CanvasBuffer() : ContiguousBuffer(nullptr) {}
explicit CanvasBuffer(ipc::SharedMemoryMapping&& aShmem)
: ContiguousBuffer(aShmem.DataAs<char>(), aShmem.Size()),
explicit CanvasBuffer(RefPtr<ipc::SharedMemory>&& aShmem)
: ContiguousBuffer(static_cast<char*>(aShmem->Memory()),
aShmem->Size()),
shmem(std::move(aShmem)) {}
size_t Capacity() { return shmem ? shmem.Size() : 0; }
size_t Capacity() { return shmem ? shmem->Size() : 0; }
};
struct RecycledBuffer {
ipc::SharedMemoryMapping shmem;
RefPtr<ipc::SharedMemory> shmem;
int64_t eventCount = 0;
explicit RecycledBuffer(ipc::SharedMemoryMapping&& aShmem,
explicit RecycledBuffer(RefPtr<ipc::SharedMemory>&& aShmem,
int64_t aEventCount)
: shmem(std::move(aShmem)), eventCount(aEventCount) {}
size_t Capacity() { return shmem.Size(); }
size_t Capacity() { return shmem->Size(); }
};
CanvasBuffer mCurrentBuffer;

View File

@@ -26,6 +26,7 @@ using gfx::ReadElement;
using gfx::ReferencePtr;
using gfx::SurfaceFormat;
using gfx::WriteElement;
using ipc::SharedMemory;
const EventType CANVAS_BEGIN_TRANSACTION = EventType::LAST;
const EventType CANVAS_END_TRANSACTION = EventType(EventType::LAST + 1);

View File

@@ -9,7 +9,6 @@
#include "mozilla/Likely.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/Types.h" // for decltype
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/layers/SharedSurfacesChild.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "nsDebug.h" // for NS_ABORT_OOM
@@ -31,9 +30,10 @@ using namespace mozilla::layers;
namespace mozilla {
namespace gfx {
void SourceSurfaceSharedDataWrapper::Init(
const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
ipc::ReadOnlySharedMemoryHandle aHandle, base::ProcessId aCreatorPid) {
void SourceSurfaceSharedDataWrapper::Init(const IntSize& aSize, int32_t aStride,
SurfaceFormat aFormat,
SharedMemory::Handle aHandle,
base::ProcessId aCreatorPid) {
MOZ_ASSERT(!mBuf);
mSize = aSize;
mStride = aStride;
@@ -41,8 +41,8 @@ void SourceSurfaceSharedDataWrapper::Init(
mCreatorPid = aCreatorPid;
size_t len = GetAlignedDataLength();
mBufHandle = std::move(aHandle);
if (!mBufHandle) {
mBuf = MakeAndAddRef<SharedMemory>();
if (!mBuf->SetHandle(std::move(aHandle), ipc::SharedMemory::RightsReadOnly)) {
MOZ_CRASH("Invalid shared memory handle!");
}
@@ -63,7 +63,7 @@ void SourceSurfaceSharedDataWrapper::Init(
// We don't support unmapping for this surface, and we failed to map it.
NS_ABORT_OOM(len);
} else {
mBufHandle = nullptr;
mBuf->CloseHandle();
}
}
@@ -80,20 +80,15 @@ void SourceSurfaceSharedDataWrapper::Init(SourceSurfaceSharedData* aSurface) {
bool SourceSurfaceSharedDataWrapper::EnsureMapped(size_t aLength) {
MOZ_ASSERT(!GetData());
auto mapping = mBufHandle.Map();
while (!mapping) {
while (!mBuf->Map(aLength)) {
nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>> expired;
if (!SharedSurfacesParent::AgeOneGeneration(expired)) {
return false;
}
MOZ_ASSERT(!expired.Contains(this));
SharedSurfacesParent::ExpireMap(expired);
mapping = mBufHandle.Map();
}
mBuf = std::make_shared<ipc::MutableOrReadOnlySharedMemoryMapping>(
std::move(mapping));
return true;
}
@@ -148,8 +143,7 @@ void SourceSurfaceSharedDataWrapper::Unmap() {
void SourceSurfaceSharedDataWrapper::ExpireMap() {
MutexAutoLock lock(*mHandleLock);
if (mMapCount == 0) {
// This unmaps the stored memory mapping.
*mBuf = nullptr;
mBuf->Unmap();
}
}
@@ -161,10 +155,9 @@ bool SourceSurfaceSharedData::Init(const IntSize& aSize, int32_t aStride,
mFormat = aFormat;
size_t len = GetAlignedDataLength();
mBufHandle = ipc::shared_memory::Create(len);
mBuf = std::make_shared<ipc::MutableOrReadOnlySharedMemoryMapping>(
mBufHandle.Map());
if (NS_WARN_IF(!mBufHandle) || NS_WARN_IF(!mBuf || !*mBuf)) {
mBuf = new SharedMemory();
if (NS_WARN_IF(!mBuf->Create(len)) || NS_WARN_IF(!mBuf->Map(len))) {
mBuf = nullptr;
return false;
}
@@ -194,23 +187,17 @@ void SourceSurfaceSharedData::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
uint8_t* SourceSurfaceSharedData::GetDataInternal() const {
mMutex.AssertCurrentThreadOwns();
// This class's mappings are always mutable, so we can safely cast away the
// const in the values returned here (see the comment above the `mBuf`
// declaration).
// If we have an old buffer lingering, it is because we get reallocated to
// get a new handle to share, but there were still active mappings.
if (MOZ_UNLIKELY(mOldBuf)) {
MOZ_ASSERT(mMapCount > 0);
MOZ_ASSERT(mFinalized);
return const_cast<uint8_t*>(mOldBuf->DataAs<uint8_t>());
return static_cast<uint8_t*>(mOldBuf->Memory());
}
// Const cast to match `GetData()`.
return const_cast<uint8_t*>(mBuf->DataAs<uint8_t>());
return static_cast<uint8_t*>(mBuf->Memory());
}
nsresult SourceSurfaceSharedData::CloneHandle(
ipc::ReadOnlySharedMemoryHandle& aHandle) {
nsresult SourceSurfaceSharedData::CloneHandle(SharedMemory::Handle& aHandle) {
MutexAutoLock lock(mMutex);
MOZ_ASSERT(mHandleCount > 0);
@@ -218,7 +205,7 @@ nsresult SourceSurfaceSharedData::CloneHandle(
return NS_ERROR_NOT_AVAILABLE;
}
aHandle = mBufHandle.Clone().ToReadOnly();
aHandle = mBuf->CloneHandle();
if (MOZ_UNLIKELY(!aHandle)) {
return NS_ERROR_FAILURE;
}
@@ -236,7 +223,7 @@ void SourceSurfaceSharedData::CloseHandleInternal() {
}
if (mShared) {
mBufHandle = nullptr;
mBuf->CloseHandle();
mClosed = true;
}
}
@@ -255,25 +242,21 @@ bool SourceSurfaceSharedData::ReallocHandle() {
}
size_t len = GetAlignedDataLength();
auto handle = ipc::shared_memory::Create(len);
auto mapping = handle.Map();
if (NS_WARN_IF(!handle) || NS_WARN_IF(!mapping)) {
RefPtr<SharedMemory> buf = new SharedMemory();
if (NS_WARN_IF(!buf->Create(len)) || NS_WARN_IF(!buf->Map(len))) {
return false;
}
size_t copyLen = GetDataLength();
memcpy(mapping.Address(), mBuf->Address(), copyLen);
memcpy(buf->Memory(), mBuf->Memory(), copyLen);
#ifdef SHARED_SURFACE_PROTECT_FINALIZED
ipc::shared_memory::LocalProtect(mapping.DataAs<char>(), len,
ipc::shared_memory::AccessRead);
buf->Protect(static_cast<char*>(buf->Memory()), len, RightsRead);
#endif
if (mMapCount > 0 && !mOldBuf) {
mOldBuf = std::move(mBuf);
}
mBufHandle = std::move(handle);
mBuf = std::make_shared<ipc::MutableOrReadOnlySharedMemoryMapping>(
std::move(mapping));
mBuf = std::move(buf);
mClosed = false;
mShared = false;
return true;
@@ -285,10 +268,7 @@ void SourceSurfaceSharedData::Finalize() {
#ifdef SHARED_SURFACE_PROTECT_FINALIZED
size_t len = GetAlignedDataLength();
// This class's mappings are always mutable, so we can safely cast away the
// const (see the comment above the `mBuf` declaration).
ipc::shared_memory::LocalProtect(const_cast<char*>(mBuf->DataAs<char>()), len,
ipc::shared_memory::AccessRead);
mBuf->Protect(static_cast<char*>(mBuf->Memory()), len, RightsRead);
#endif
mFinalized = true;

View File

@@ -10,8 +10,7 @@
#include "base/process.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Mutex.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "nsExpirationTracker.h"
namespace mozilla {
@@ -35,6 +34,8 @@ class SourceSurfaceSharedData;
* mapped in the given shared memory handle as read only memory.
*/
class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
typedef mozilla::ipc::SharedMemory SharedMemory;
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper,
override)
@@ -42,8 +43,7 @@ class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
SourceSurfaceSharedDataWrapper() = default;
void Init(const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
mozilla::ipc::ReadOnlySharedMemoryHandle aHandle,
base::ProcessId aCreatorPid);
SharedMemory::Handle aHandle, base::ProcessId aCreatorPid);
void Init(SourceSurfaceSharedData* aSurface);
@@ -57,11 +57,7 @@ class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
IntSize GetSize() const override { return mSize; }
SurfaceFormat GetFormat() const override { return mFormat; }
uint8_t* GetData() override {
// Cast away const-ness of shared memory to match the
// `DataSourceSurface::GetData` interface. The data will not be written to.
return mBuf ? const_cast<uint8_t*>(mBuf->DataAs<uint8_t>()) : nullptr;
}
uint8_t* GetData() override { return static_cast<uint8_t*>(mBuf->Memory()); }
bool OnHeap() const override { return false; }
@@ -101,7 +97,7 @@ class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
}
size_t GetAlignedDataLength() const {
return mozilla::ipc::shared_memory::PageAlignedSize(GetDataLength());
return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
}
bool EnsureMapped(size_t aLength);
@@ -112,9 +108,7 @@ class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
int32_t mStride = 0;
uint32_t mConsumers = 1;
IntSize mSize;
// This is only used to support EnsureMapped if we fail initially.
mozilla::ipc::ReadOnlySharedMemoryHandle mBufHandle;
std::shared_ptr<mozilla::ipc::MutableOrReadOnlySharedMemoryMapping> mBuf;
RefPtr<SharedMemory> mBuf;
SurfaceFormat mFormat = SurfaceFormat::UNKNOWN;
base::ProcessId mCreatorPid = 0;
bool mCreatorRef = true;
@@ -125,6 +119,8 @@ class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
* source surface.
*/
class SourceSurfaceSharedData : public DataSourceSurface {
typedef mozilla::ipc::SharedMemory SharedMemory;
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
@@ -201,7 +197,7 @@ class SourceSurfaceSharedData : public DataSourceSurface {
* NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
* NS_ERROR_FAILURE -- failed to create a handle to share.
*/
nsresult CloneHandle(mozilla::ipc::ReadOnlySharedMemoryHandle& aHandle);
nsresult CloneHandle(SharedMemory::Handle& aHandle);
/**
* Indicates the buffer is not expected to be shared with any more processes.
@@ -318,7 +314,7 @@ class SourceSurfaceSharedData : public DataSourceSurface {
}
size_t GetAlignedDataLength() const {
return mozilla::ipc::shared_memory::PageAlignedSize(GetDataLength());
return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
}
/**
@@ -332,11 +328,8 @@ class SourceSurfaceSharedData : public DataSourceSurface {
int32_t mHandleCount;
Maybe<IntRect> mDirtyRect;
IntSize mSize;
mozilla::ipc::MutableSharedMemoryHandle mBufHandle;
// This class always has mutable mappings, however we need to share them with
// the wrapper which may be read-only, so we use MutableOrReadOnly.
std::shared_ptr<mozilla::ipc::MutableOrReadOnlySharedMemoryMapping> mBuf;
std::shared_ptr<mozilla::ipc::MutableOrReadOnlySharedMemoryMapping> mOldBuf;
RefPtr<SharedMemory> mBuf;
RefPtr<SharedMemory> mOldBuf;
SurfaceFormat mFormat;
bool mClosed : 1;
bool mFinalized : 1;

View File

@@ -86,8 +86,9 @@
#include "nsThreadUtils.h" // for NS_IsMainThread
#include "nsViewportInfo.h" // for ViewportMinScale(), ViewportMaxScale()
#include "prsystem.h" // for PR_GetPhysicalMemorySize
#include "ScrollSnap.h" // for ScrollSnapUtils
#include "ScrollAnimationPhysics.h" // for ComputeAcceleratedWheelDelta
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory
#include "ScrollSnap.h" // for ScrollSnapUtils
#include "ScrollAnimationPhysics.h" // for ComputeAcceleratedWheelDelta
#include "SmoothMsdScrollAnimation.h"
#include "SmoothScrollAnimation.h"
#include "WheelScrollAnimation.h"

View File

@@ -26,6 +26,7 @@
#include "mozilla/gfx/Logging.h" // for gfxDebug
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/CanvasRenderer.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/ISurfaceAllocator.h"

View File

@@ -18,7 +18,6 @@
#include "mozilla/gfx/Point.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
@@ -40,29 +39,27 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers {
~RecorderHelpers() override = default;
bool InitTranslator(
TextureType aTextureType, TextureType aWebglTextureType,
gfx::BackendType aBackendType,
ipc::MutableSharedMemoryHandle&& aReadHandle,
nsTArray<ipc::ReadOnlySharedMemoryHandle>&& aBufferHandles,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem) override {
bool InitTranslator(TextureType aTextureType, TextureType aWebglTextureType,
gfx::BackendType aBackendType, Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles, uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem) override {
NS_ASSERT_OWNINGTHREAD(RecorderHelpers);
if (NS_WARN_IF(!mCanvasChild)) {
return false;
}
return mCanvasChild->SendInitTranslator(
aTextureType, aWebglTextureType, aBackendType, std::move(aReadHandle),
std::move(aBufferHandles), std::move(aReaderSem),
std::move(aBufferHandles), aBufferSize, std::move(aReaderSem),
std::move(aWriterSem));
}
bool AddBuffer(ipc::ReadOnlySharedMemoryHandle&& aBufferHandle) override {
bool AddBuffer(Handle&& aBufferHandle, uint64_t aBufferSize) override {
NS_ASSERT_OWNINGTHREAD(RecorderHelpers);
if (!mCanvasChild) {
return false;
}
return mCanvasChild->SendAddBuffer(std::move(aBufferHandle));
return mCanvasChild->SendAddBuffer(std::move(aBufferHandle), aBufferSize);
}
bool ReaderClosed() override {
@@ -195,9 +192,7 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
class CanvasDataShmemHolder {
public:
CanvasDataShmemHolder(
const std::shared_ptr<ipc::ReadOnlySharedMemoryMapping>& aShmem,
CanvasChild* aCanvasChild)
CanvasDataShmemHolder(ipc::SharedMemory* aShmem, CanvasChild* aCanvasChild)
: mMutex("CanvasChild::DataShmemHolder::mMutex"),
mShmem(aShmem),
mCanvasChild(aCanvasChild) {}
@@ -264,7 +259,7 @@ class CanvasDataShmemHolder {
return;
}
mCanvasChild->ReturnDataSurfaceShmem(std::move(mShmem));
mCanvasChild->ReturnDataSurfaceShmem(mShmem.forget());
mCanvasChild = nullptr;
mWorkerRef = nullptr;
}
@@ -281,7 +276,7 @@ class CanvasDataShmemHolder {
private:
Mutex mMutex;
std::shared_ptr<ipc::ReadOnlySharedMemoryMapping> mShmem;
RefPtr<ipc::SharedMemory> mShmem;
RefPtr<CanvasChild> mCanvasChild MOZ_GUARDED_BY(mMutex);
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex);
};
@@ -494,26 +489,26 @@ bool CanvasChild::EnsureDataSurfaceShmem(gfx::IntSize aSize,
if (!sizeRequired) {
return false;
}
sizeRequired = ipc::shared_memory::PageAlignedSize(sizeRequired);
sizeRequired = ipc::SharedMemory::PageAlignedSize(sizeRequired);
if (!mDataSurfaceShmemAvailable || mDataSurfaceShmem->Size() < sizeRequired) {
RecordEvent(RecordedPauseTranslation());
auto shmemHandle = ipc::shared_memory::Create(sizeRequired);
auto dataSurfaceShmem = MakeRefPtr<ipc::SharedMemory>();
if (!dataSurfaceShmem->Create(sizeRequired) ||
!dataSurfaceShmem->Map(sizeRequired)) {
return false;
}
auto shmemHandle = dataSurfaceShmem->TakeHandle();
if (!shmemHandle) {
return false;
}
auto roMapping = shmemHandle.AsReadOnly().Map();
if (!roMapping) {
if (!SendSetDataSurfaceBuffer(std::move(shmemHandle), sizeRequired)) {
return false;
}
if (!SendSetDataSurfaceBuffer(std::move(shmemHandle))) {
return false;
}
mDataSurfaceShmem = std::make_shared<ipc::ReadOnlySharedMemoryMapping>(
std::move(roMapping));
mDataSurfaceShmem = dataSurfaceShmem.forget();
mDataSurfaceShmemAvailable = true;
}
@@ -565,7 +560,8 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
// use that directly without having to allocate a new shmem for retrieval.
auto it = mTextureInfo.find(aTextureOwnerId);
if (it != mTextureInfo.end() && it->second.mSnapshotShmem) {
const auto* shmemPtr = it->second.mSnapshotShmem->DataAs<uint8_t>();
const auto shmemPtr =
reinterpret_cast<uint8_t*>(it->second.mSnapshotShmem->Memory());
MOZ_ASSERT(shmemPtr);
mRecorder->RecordEvent(RecordedPrepareShmem(aTextureOwnerId));
auto checkpoint = CreateCheckpoint();
@@ -578,12 +574,10 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
delete closure;
return nullptr;
}
// We can cast away the const of `shmemPtr` to match the call because the
// DataSourceSurface will not be written to.
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateWrappingDataSourceSurface(
const_cast<uint8_t*>(shmemPtr), stride, ssSize, ssFormat,
ReleaseDataShmemHolder, closure);
shmemPtr, stride, ssSize, ssFormat, ReleaseDataShmemHolder,
closure);
aMayInvalidate = true;
return dataSurface.forget();
}
@@ -609,14 +603,11 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
mDataSurfaceShmemAvailable = false;
const auto* data = mDataSurfaceShmem->DataAs<uint8_t>();
auto* data = static_cast<uint8_t*>(mDataSurfaceShmem->Memory());
// We can cast away the const of `data` to match the call because the
// DataSourceSurface will not be written to.
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateWrappingDataSourceSurface(
const_cast<uint8_t*>(data), stride, ssSize, ssFormat,
ReleaseDataShmemHolder, closure);
data, stride, ssSize, ssFormat, ReleaseDataShmemHolder, closure);
aMayInvalidate = false;
return dataSurface.forget();
}
@@ -640,9 +631,10 @@ already_AddRefed<gfx::SourceSurface> CanvasChild::WrapSurface(
}
void CanvasChild::ReturnDataSurfaceShmem(
std::shared_ptr<ipc::ReadOnlySharedMemoryMapping>&& aDataSurfaceShmem) {
already_AddRefed<ipc::SharedMemory> aDataSurfaceShmem) {
RefPtr<ipc::SharedMemory> data = aDataSurfaceShmem;
// We can only reuse the latest data surface shmem.
if (aDataSurfaceShmem == mDataSurfaceShmem) {
if (data == mDataSurfaceShmem) {
MOZ_ASSERT(!mDataSurfaceShmemAvailable);
mDataSurfaceShmemAvailable = true;
}
@@ -688,17 +680,17 @@ bool CanvasChild::RequiresRefresh(
}
ipc::IPCResult CanvasChild::RecvSnapshotShmem(
const RemoteTextureOwnerId aTextureOwnerId,
ipc::ReadOnlySharedMemoryHandle&& aShmemHandle,
SnapshotShmemResolver&& aResolve) {
const RemoteTextureOwnerId aTextureOwnerId, Handle&& aShmemHandle,
uint32_t aShmemSize, SnapshotShmemResolver&& aResolve) {
auto it = mTextureInfo.find(aTextureOwnerId);
if (it != mTextureInfo.end()) {
auto shmem = aShmemHandle.Map();
if (NS_WARN_IF(!shmem)) {
auto shmem = MakeRefPtr<ipc::SharedMemory>();
if (NS_WARN_IF(!shmem->SetHandle(std::move(aShmemHandle),
ipc::SharedMemory::RightsReadOnly)) ||
NS_WARN_IF(!shmem->Map(aShmemSize))) {
shmem = nullptr;
} else {
it->second.mSnapshotShmem =
std::make_shared<ipc::ReadOnlySharedMemoryMapping>(std::move(shmem));
it->second.mSnapshotShmem = std::move(shmem);
}
aResolve(true);
} else {

View File

@@ -9,7 +9,6 @@
#include "mozilla/gfx/RecordedEvent.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/layers/PCanvasChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/WeakPtr.h"
@@ -57,10 +56,9 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
ipc::IPCResult RecvNotifyRequiresRefresh(
const RemoteTextureOwnerId aTextureOwnerId);
ipc::IPCResult RecvSnapshotShmem(
const RemoteTextureOwnerId aTextureOwnerId,
ipc::ReadOnlySharedMemoryHandle&& aShmemHandle,
SnapshotShmemResolver&& aResolve);
ipc::IPCResult RecvSnapshotShmem(const RemoteTextureOwnerId aTextureOwnerId,
Handle&& aShmemHandle, uint32_t aShmemSize,
SnapshotShmemResolver&& aResolve);
ipc::IPCResult RecvNotifyTextureDestruction(
const RemoteTextureOwnerId aTextureOwnerId);
@@ -164,7 +162,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
bool RequiresRefresh(const RemoteTextureOwnerId aTextureOwnerId) const;
void ReturnDataSurfaceShmem(
std::shared_ptr<ipc::ReadOnlySharedMemoryMapping>&& aDataSurfaceShmem);
already_AddRefed<ipc::SharedMemory> aDataSurfaceShmem);
protected:
void ActorDestroy(ActorDestroyReason aWhy) final;
@@ -187,12 +185,12 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
RefPtr<CanvasDrawEventRecorder> mRecorder;
std::shared_ptr<ipc::ReadOnlySharedMemoryMapping> mDataSurfaceShmem;
RefPtr<ipc::SharedMemory> mDataSurfaceShmem;
bool mDataSurfaceShmemAvailable = false;
int64_t mLastWriteLockCheckpoint = 0;
uint32_t mTransactionsSinceGetDataSurface = kCacheDataSurfaceThreshold;
struct TextureInfo {
std::shared_ptr<mozilla::ipc::ReadOnlySharedMemoryMapping> mSnapshotShmem;
RefPtr<mozilla::ipc::SharedMemory> mSnapshotShmem;
bool mRequiresRefresh = false;
};
std::unordered_map<RemoteTextureOwnerId, TextureInfo,

View File

@@ -18,7 +18,6 @@
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/layers/BufferTexture.h"
#include "mozilla/layers/CanvasTranslator.h"
#include "mozilla/layers/ImageDataSerializer.h"
@@ -103,6 +102,21 @@ bool CanvasTranslator::IsInTaskQueue() const {
return gfx::CanvasRenderThread::IsInCanvasRenderThread();
}
static bool CreateAndMapShmem(RefPtr<ipc::SharedMemory>& aShmem,
Handle&& aHandle,
ipc::SharedMemory::OpenRights aOpenRights,
size_t aSize) {
auto shmem = MakeRefPtr<ipc::SharedMemory>();
if (!shmem->SetHandle(std::move(aHandle), aOpenRights) ||
!shmem->Map(aSize)) {
return false;
}
shmem->CloseHandle();
aShmem = shmem.forget();
return true;
}
StaticRefPtr<gfx::SharedContextWebgl> CanvasTranslator::sSharedContext;
bool CanvasTranslator::EnsureSharedContextWebgl() {
@@ -140,8 +154,8 @@ void CanvasTranslator::Shutdown() {
mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator(
TextureType aTextureType, TextureType aWebglTextureType,
gfx::BackendType aBackendType, ipc::MutableSharedMemoryHandle&& aReadHandle,
nsTArray<ipc::ReadOnlySharedMemoryHandle>&& aBufferHandles,
gfx::BackendType aBackendType, Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles, uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem) {
if (mHeaderShmem) {
@@ -153,13 +167,14 @@ mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator(
mBackendType = aBackendType;
mOtherPid = OtherPid();
mHeaderShmem = aReadHandle.Map();
if (!mHeaderShmem) {
mHeaderShmem = MakeAndAddRef<ipc::SharedMemory>();
if (!CreateAndMapShmem(mHeaderShmem, std::move(aReadHandle),
ipc::SharedMemory::RightsReadWrite, sizeof(Header))) {
Deactivate();
return IPC_FAIL(this, "Failed to map canvas header shared memory.");
}
mHeader = mHeaderShmem.DataAs<Header>();
mHeader = static_cast<Header*>(mHeaderShmem->Memory());
mWriterSemaphore.reset(CrossProcessSemaphore::Create(std::move(aWriterSem)));
mWriterSemaphore->CloseHandle();
@@ -178,10 +193,10 @@ mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator(
}
// Use the first buffer as our current buffer.
mDefaultBufferSize = aBufferHandles[0].Size();
mDefaultBufferSize = aBufferSize;
auto handleIter = aBufferHandles.begin();
mCurrentShmem.shmem = std::move(*handleIter).Map();
if (!mCurrentShmem.shmem) {
if (!CreateAndMapShmem(mCurrentShmem.shmem, std::move(*handleIter),
ipc::SharedMemory::RightsReadOnly, aBufferSize)) {
Deactivate();
return IPC_FAIL(this, "Failed to map canvas buffer shared memory.");
}
@@ -190,8 +205,8 @@ mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator(
// Add all other buffers to our recycled CanvasShmems.
for (handleIter++; handleIter < aBufferHandles.end(); handleIter++) {
CanvasShmem newShmem;
newShmem.shmem = std::move(*handleIter).Map();
if (!newShmem.shmem) {
if (!CreateAndMapShmem(newShmem.shmem, std::move(*handleIter),
ipc::SharedMemory::RightsReadOnly, aBufferSize)) {
Deactivate();
return IPC_FAIL(this, "Failed to map canvas buffer shared memory.");
}
@@ -232,7 +247,7 @@ ipc::IPCResult CanvasTranslator::RecvRestartTranslation() {
}
ipc::IPCResult CanvasTranslator::RecvAddBuffer(
ipc::ReadOnlySharedMemoryHandle&& aBufferHandle) {
ipc::SharedMemory::Handle&& aBufferHandle, uint64_t aBufferSize) {
if (mDeactivated) {
// The other side might have sent a resume message before we deactivated.
return IPC_OK();
@@ -240,20 +255,20 @@ ipc::IPCResult CanvasTranslator::RecvAddBuffer(
if (UsePendingCanvasTranslatorEvents()) {
MutexAutoLock lock(mCanvasTranslatorEventsLock);
mPendingCanvasTranslatorEvents.push_back(
CanvasTranslatorEvent::AddBuffer(std::move(aBufferHandle)));
mPendingCanvasTranslatorEvents.push_back(CanvasTranslatorEvent::AddBuffer(
std::move(aBufferHandle), aBufferSize));
PostCanvasTranslatorEvents(lock);
} else {
DispatchToTaskQueue(NewRunnableMethod<ipc::ReadOnlySharedMemoryHandle&&>(
DispatchToTaskQueue(NewRunnableMethod<ipc::SharedMemory::Handle&&, size_t>(
"CanvasTranslator::AddBuffer", this, &CanvasTranslator::AddBuffer,
std::move(aBufferHandle)));
std::move(aBufferHandle), aBufferSize));
}
return IPC_OK();
}
bool CanvasTranslator::AddBuffer(
ipc::ReadOnlySharedMemoryHandle&& aBufferHandle) {
bool CanvasTranslator::AddBuffer(ipc::SharedMemory::Handle&& aBufferHandle,
size_t aBufferSize) {
MOZ_ASSERT(IsInTaskQueue());
if (mHeader->readerState == State::Failed) {
// We failed before we got to the pause event.
@@ -282,8 +297,8 @@ bool CanvasTranslator::AddBuffer(
}
CanvasShmem newShmem;
newShmem.shmem = aBufferHandle.Map();
if (!newShmem.shmem) {
if (!CreateAndMapShmem(newShmem.shmem, std::move(aBufferHandle),
ipc::SharedMemory::RightsReadOnly, aBufferSize)) {
return false;
}
@@ -294,7 +309,7 @@ bool CanvasTranslator::AddBuffer(
}
ipc::IPCResult CanvasTranslator::RecvSetDataSurfaceBuffer(
ipc::MutableSharedMemoryHandle&& aBufferHandle) {
ipc::SharedMemory::Handle&& aBufferHandle, uint64_t aBufferSize) {
if (mDeactivated) {
// The other side might have sent a resume message before we deactivated.
return IPC_OK();
@@ -303,19 +318,21 @@ ipc::IPCResult CanvasTranslator::RecvSetDataSurfaceBuffer(
if (UsePendingCanvasTranslatorEvents()) {
MutexAutoLock lock(mCanvasTranslatorEventsLock);
mPendingCanvasTranslatorEvents.push_back(
CanvasTranslatorEvent::SetDataSurfaceBuffer(std::move(aBufferHandle)));
CanvasTranslatorEvent::SetDataSurfaceBuffer(std::move(aBufferHandle),
aBufferSize));
PostCanvasTranslatorEvents(lock);
} else {
DispatchToTaskQueue(NewRunnableMethod<ipc::MutableSharedMemoryHandle&&>(
DispatchToTaskQueue(NewRunnableMethod<ipc::SharedMemory::Handle&&, size_t>(
"CanvasTranslator::SetDataSurfaceBuffer", this,
&CanvasTranslator::SetDataSurfaceBuffer, std::move(aBufferHandle)));
&CanvasTranslator::SetDataSurfaceBuffer, std::move(aBufferHandle),
aBufferSize));
}
return IPC_OK();
}
bool CanvasTranslator::SetDataSurfaceBuffer(
ipc::MutableSharedMemoryHandle&& aBufferHandle) {
ipc::SharedMemory::Handle&& aBufferHandle, size_t aBufferSize) {
MOZ_ASSERT(IsInTaskQueue());
if (mHeader->readerState == State::Failed) {
// We failed before we got to the pause event.
@@ -332,8 +349,8 @@ bool CanvasTranslator::SetDataSurfaceBuffer(
return false;
}
mDataSurfaceShmem = aBufferHandle.Map();
if (!mDataSurfaceShmem) {
if (!CreateAndMapShmem(mDataSurfaceShmem, std::move(aBufferHandle),
ipc::SharedMemory::RightsReadWrite, aBufferSize)) {
return false;
}
@@ -368,11 +385,11 @@ void CanvasTranslator::GetDataSurface(uint64_t aSurfaceRef) {
ImageDataSerializer::ComputeRGBStride(format, dstSize.width);
auto requiredSize =
ImageDataSerializer::ComputeRGBBufferSize(dstSize, format);
if (requiredSize <= 0 || size_t(requiredSize) > mDataSurfaceShmem.Size()) {
if (requiredSize <= 0 || size_t(requiredSize) > mDataSurfaceShmem->Size()) {
return;
}
uint8_t* dst = mDataSurfaceShmem.DataAs<uint8_t>();
uint8_t* dst = static_cast<uint8_t*>(mDataSurfaceShmem->Memory());
const uint8_t* src = map->GetData();
const uint8_t* endSrc = src + (srcSize.height * srcStride);
while (src < endSrc) {
@@ -778,11 +795,12 @@ void CanvasTranslator::HandleCanvasTranslatorEvents() {
dispatchTranslate = TranslateRecording();
break;
case CanvasTranslatorEvent::Tag::AddBuffer:
dispatchTranslate = AddBuffer(event->TakeBufferHandle());
dispatchTranslate =
AddBuffer(event->TakeBufferHandle(), event->BufferSize());
break;
case CanvasTranslatorEvent::Tag::SetDataSurfaceBuffer:
dispatchTranslate =
SetDataSurfaceBuffer(event->TakeDataSurfaceBufferHandle());
dispatchTranslate = SetDataSurfaceBuffer(event->TakeBufferHandle(),
event->BufferSize());
break;
case CanvasTranslatorEvent::Tag::ClearCachedResources:
ClearCachedResources();
@@ -1053,7 +1071,8 @@ void CanvasTranslator::CacheSnapshotShmem(
nsCOMPtr<nsIThread> thread =
gfx::CanvasRenderThread::GetCanvasRenderThread();
RefPtr<CanvasTranslator> translator = this;
SendSnapshotShmem(aTextureOwnerId, std::move(shmemHandle))
SendSnapshotShmem(aTextureOwnerId, std::move(shmemHandle),
webgl->GetShmemSize())
->Then(
thread, __func__,
[=](bool) { translator->RemoveTexture(aTextureOwnerId); },

View File

@@ -15,16 +15,13 @@
#include "mozilla/gfx/InlineTranslator.h"
#include "mozilla/gfx/RecordedEvent.h"
#include "CanvasChild.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/PCanvasParent.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/Monitor.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Variant.h"
namespace mozilla {
@@ -84,13 +81,14 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer
* @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer
*/
ipc::IPCResult RecvInitTranslator(
TextureType aTextureType, TextureType aWebglTextureType,
gfx::BackendType aBackendType,
ipc::MutableSharedMemoryHandle&& aReadHandle,
nsTArray<ipc::ReadOnlySharedMemoryHandle>&& aBufferHandles,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem);
ipc::IPCResult RecvInitTranslator(TextureType aTextureType,
TextureType aWebglTextureType,
gfx::BackendType aBackendType,
Handle&& aReadHandle,
nsTArray<Handle>&& aBufferHandles,
uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem);
/**
* Restart the translation from a Stopped state.
@@ -101,13 +99,13 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* Adds a new buffer to be translated. The current buffer will be recycled if
* it is of the default size. The translation will then be restarted.
*/
ipc::IPCResult RecvAddBuffer(ipc::ReadOnlySharedMemoryHandle&& aBufferHandle);
ipc::IPCResult RecvAddBuffer(Handle&& aBufferHandle, uint64_t aBufferSize);
/**
* Sets the shared memory to be used for readback.
*/
ipc::IPCResult RecvSetDataSurfaceBuffer(
ipc::MutableSharedMemoryHandle&& aBufferHandle);
ipc::IPCResult RecvSetDataSurfaceBuffer(Handle&& aBufferHandle,
uint64_t aBufferSize);
ipc::IPCResult RecvClearCachedResources();
@@ -318,25 +316,23 @@ class CanvasTranslator final : public gfx::InlineTranslator,
const Tag mTag;
private:
Variant<ipc::ReadOnlySharedMemoryHandle, ipc::MutableSharedMemoryHandle>
mBufferHandle;
ipc::SharedMemory::Handle mBufferHandle;
const size_t mBufferSize;
public:
explicit CanvasTranslatorEvent(const Tag aTag)
: mTag(aTag), mBufferHandle(ipc::ReadOnlySharedMemoryHandle()) {
: mTag(aTag), mBufferSize(0) {
MOZ_ASSERT(mTag == Tag::TranslateRecording ||
mTag == Tag::ClearCachedResources ||
mTag == Tag::DropFreeBuffersWhenDormant);
}
CanvasTranslatorEvent(const Tag aTag,
ipc::ReadOnlySharedMemoryHandle&& aBufferHandle)
: mTag(aTag), mBufferHandle(std::move(aBufferHandle)) {
MOZ_ASSERT(mTag == Tag::AddBuffer);
}
CanvasTranslatorEvent(const Tag aTag,
ipc::MutableSharedMemoryHandle&& aBufferHandle)
: mTag(aTag), mBufferHandle(std::move(aBufferHandle)) {
MOZ_ASSERT(mTag == Tag::SetDataSurfaceBuffer);
ipc::SharedMemory::Handle&& aBufferHandle,
size_t aBufferSize)
: mTag(aTag),
mBufferHandle(std::move(aBufferHandle)),
mBufferSize(aBufferSize) {
MOZ_ASSERT(mTag == Tag::AddBuffer || mTag == Tag::SetDataSurfaceBuffer);
}
static UniquePtr<CanvasTranslatorEvent> TranslateRecording() {
@@ -344,15 +340,15 @@ class CanvasTranslator final : public gfx::InlineTranslator,
}
static UniquePtr<CanvasTranslatorEvent> AddBuffer(
ipc::ReadOnlySharedMemoryHandle&& aBufferHandle) {
return MakeUnique<CanvasTranslatorEvent>(Tag::AddBuffer,
std::move(aBufferHandle));
ipc::SharedMemory::Handle&& aBufferHandle, size_t aBufferSize) {
return MakeUnique<CanvasTranslatorEvent>(
Tag::AddBuffer, std::move(aBufferHandle), aBufferSize);
}
static UniquePtr<CanvasTranslatorEvent> SetDataSurfaceBuffer(
ipc::MutableSharedMemoryHandle&& aBufferHandle) {
return MakeUnique<CanvasTranslatorEvent>(Tag::SetDataSurfaceBuffer,
std::move(aBufferHandle));
ipc::SharedMemory::Handle&& aBufferHandle, size_t aBufferSize) {
return MakeUnique<CanvasTranslatorEvent>(
Tag::SetDataSurfaceBuffer, std::move(aBufferHandle), aBufferSize);
}
static UniquePtr<CanvasTranslatorEvent> ClearCachedResources() {
@@ -363,20 +359,20 @@ class CanvasTranslator final : public gfx::InlineTranslator,
return MakeUnique<CanvasTranslatorEvent>(Tag::DropFreeBuffersWhenDormant);
}
ipc::ReadOnlySharedMemoryHandle TakeBufferHandle() {
if (mTag == Tag::AddBuffer) {
return std::move(mBufferHandle).as<ipc::ReadOnlySharedMemoryHandle>();
ipc::SharedMemory::Handle TakeBufferHandle() {
if (mTag == Tag::AddBuffer || mTag == Tag::SetDataSurfaceBuffer) {
return std::move(mBufferHandle);
}
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
return mozilla::ipc::SharedMemory::NULLHandle();
}
ipc::MutableSharedMemoryHandle TakeDataSurfaceBufferHandle() {
if (mTag == Tag::SetDataSurfaceBuffer) {
return std::move(mBufferHandle).as<ipc::MutableSharedMemoryHandle>();
size_t BufferSize() {
if (mTag == Tag::AddBuffer || mTag == Tag::SetDataSurfaceBuffer) {
return mBufferSize;
}
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
return 0;
}
};
@@ -384,13 +380,13 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* @returns true if next HandleCanvasTranslatorEvents() needs to call
* TranslateRecording().
*/
bool AddBuffer(ipc::ReadOnlySharedMemoryHandle&& aBufferHandle);
bool AddBuffer(Handle&& aBufferHandle, size_t aBufferSize);
/*
* @returns true if next HandleCanvasTranslatorEvents() needs to call
* TranslateRecording().
*/
bool SetDataSurfaceBuffer(ipc::MutableSharedMemoryHandle&& aBufferHandle);
bool SetDataSurfaceBuffer(Handle&& aBufferHandle, size_t aBufferSize);
bool ReadNextEvent(EventType& aEventType);
@@ -474,7 +470,7 @@ class CanvasTranslator final : public gfx::InlineTranslator,
using State = CanvasDrawEventRecorder::State;
using Header = CanvasDrawEventRecorder::Header;
ipc::SharedMemoryMapping mHeaderShmem;
RefPtr<ipc::SharedMemory> mHeaderShmem;
Header* mHeader = nullptr;
// Limit event processing to stop at the designated checkpoint, rather than
// proceed beyond it. This also forces processing to continue, even when it
@@ -483,20 +479,20 @@ class CanvasTranslator final : public gfx::InlineTranslator,
int64_t mFlushCheckpoint = 0;
struct CanvasShmem {
ipc::ReadOnlySharedMemoryMapping shmem;
bool IsValid() const { return shmem.IsValid(); }
auto Size() { return shmem ? shmem.Size() : 0; }
RefPtr<ipc::SharedMemory> shmem;
bool IsValid() const { return !!shmem; }
auto Size() { return shmem ? shmem->Size() : 0; }
gfx::MemReader CreateMemReader() {
if (!shmem) {
return {nullptr, 0};
}
return {shmem.DataAs<char>(), Size()};
return {static_cast<char*>(shmem->Memory()), Size()};
}
};
std::queue<CanvasShmem> mCanvasShmems;
CanvasShmem mCurrentShmem;
gfx::MemReader mCurrentMemReader{0, 0};
ipc::SharedMemoryMapping mDataSurfaceShmem;
RefPtr<ipc::SharedMemory> mDataSurfaceShmem;
UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
TextureType mTextureType = TextureType::Unknown;

View File

@@ -17,6 +17,7 @@
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/layers/CompositorController.h"
#include "mozilla/layers/CompositorVsyncSchedulerOwner.h"
#include "mozilla/layers/FocusTarget.h"

View File

@@ -11,7 +11,8 @@
#include <stdint.h> // for uint32_t
#include "gfxTypes.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/RefPtr.h"
#include "nsIMemoryReporter.h" // for nsIMemoryReporter
#include "mozilla/Atomics.h" // for Atomic

View File

@@ -13,7 +13,8 @@
#include "mozilla/Attributes.h" // for override
#include "mozilla/Atomics.h"
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/PImageBridgeChild.h"

View File

@@ -14,6 +14,7 @@
#include "mozilla/Attributes.h" // for override
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/PImageBridgeParent.h"
#include "nsISupportsImpl.h"

View File

@@ -24,6 +24,7 @@ using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
using mozilla::gfx::FenceInfo from "mozilla/gfx/FileHandleWrapper.h";
[RefCounted] using mozilla::gfx::FileHandleWrapper from "mozilla/gfx/FileHandleWrapper.h";
[MoveOnly] using mozilla::ipc::SharedMemory::Handle from "mozilla/ipc/SharedMemory.h";
using gfxImageFormat from "gfxTypes.h";
using mozilla::layers::MaybeVideoBridgeSource from "mozilla/layers/VideoBridgeUtils.h";
using mozilla::layers::RemoteTextureId from "mozilla/layers/LayersTypes.h";
@@ -34,7 +35,6 @@ using mozilla::layers::GpuProcessQueryId from "mozilla/layers/LayersTypes.h";
using mozilla::wr::ExternalImageSource from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::layers::SurfaceDescriptorRemoteDecoderId from "mozilla/layers/LayersTypes.h";
[MoveOnly] using mozilla::ipc::ReadOnlySharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
namespace mozilla {
namespace layers {
@@ -186,12 +186,12 @@ namespace layers {
MemoryOrShmem data;
};
struct SurfaceDescriptorShared
[Comparable] struct SurfaceDescriptorShared
{
IntSize size;
int32_t stride;
SurfaceFormat format;
ReadOnlySharedMemoryHandle handle;
Handle handle;
};
[Comparable] struct SurfaceDescriptorExternalImage

View File

@@ -11,9 +11,8 @@ include "mozilla/layers/CanvasTranslator.h";
[MoveOnly] using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h";
using mozilla::layers::RemoteTextureOwnerId from "mozilla/layers/LayersTypes.h";
using mozilla::layers::TextureType from "mozilla/layers/LayersTypes.h";
[MoveOnly] using mozilla::ipc::SharedMemory::Handle from "mozilla/ipc/SharedMemory.h";
using mozilla::gfx::BackendType from "mozilla/gfx/Types.h";
[MoveOnly] using mozilla::ipc::ReadOnlySharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
[MoveOnly] using mozilla::ipc::MutableSharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
namespace mozilla {
namespace layers {
@@ -35,8 +34,8 @@ parent:
* are handles for the semaphores to handle waiting on either side.
*/
async InitTranslator(TextureType aTextureType, TextureType aWebglTextureType,
BackendType aBackendType, MutableSharedMemoryHandle aHeaderHandle,
ReadOnlySharedMemoryHandle[] aBufferHandles,
BackendType aBackendType, Handle aHeaderHandle,
Handle[] aBufferHandles, uint64_t aBufferSize,
CrossProcessSemaphoreHandle aReaderSem,
CrossProcessSemaphoreHandle aWriterSem);
@@ -49,12 +48,12 @@ parent:
* Adds a new buffer to be translated. The current buffer will be recycled if
* it is of the default size. The translation will then be restarted.
*/
async AddBuffer(ReadOnlySharedMemoryHandle aBufferHandle);
async AddBuffer(Handle aBufferHandle, uint64_t aBufferSize);
/**
* Sets the shared memory to be used for readback.
*/
async SetDataSurfaceBuffer(MutableSharedMemoryHandle aBufferHandle);
async SetDataSurfaceBuffer(Handle aBufferHandle, uint64_t aBufferSize);
/**
* Notify CanvasTranslator it is about to be minimized.
@@ -98,7 +97,7 @@ child:
/**
* Cache the shmem of the framebuffer for snapshotting.
*/
async SnapshotShmem(RemoteTextureOwnerId aTextureOwnerId, ReadOnlySharedMemoryHandle aShmemHandle) returns (bool aSuccess);
async SnapshotShmem(RemoteTextureOwnerId aTextureOwnerId, Handle aShmemHandle, uint32_t aShmemSize) returns (bool aSuccess);
async NotifyTextureDestruction(RemoteTextureOwnerId aTextureOwnerId);
};

View File

@@ -14,6 +14,7 @@ include "mozilla/layers/WebRenderMessageUtils.h";
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
using mozilla::CSSToLayoutDeviceScale from "Units.h";
using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
[MoveOnly] using mozilla::ipc::SharedMemory::Handle from "mozilla/ipc/SharedMemory.h";
using mozilla::layers::CompositorOptions from "mozilla/layers/LayersMessageUtils.h";
using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::MemoryReport from "mozilla/webrender/WebRenderTypes.h";

View File

@@ -5,12 +5,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedPlanarYCbCrImage.h"
#include <stddef.h> // for size_t
#include <stdio.h> // for printf
#include "gfx2DGlue.h" // for Moz2D transition helpers
#include "ISurfaceAllocator.h" // for ISurfaceAllocator, etc
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/gfx/Types.h" // for SurfaceFormat::SurfaceFormat::YUV
#include <stddef.h> // for size_t
#include <stdio.h> // for printf
#include "gfx2DGlue.h" // for Moz2D transition helpers
#include "ISurfaceAllocator.h" // for ISurfaceAllocator, etc
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/gfx/Types.h" // for SurfaceFormat::SurfaceFormat::YUV
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/ImageClient.h" // for ImageClient
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
#include "mozilla/layers/TextureClient.h"

View File

@@ -220,7 +220,7 @@ nsresult SharedSurfacesChild::ShareInternal(SourceSurfaceSharedData* aSurface,
// Attempt to share a handle with the GPU process. The handle may or may not
// be available -- it will only be available if it is either not yet finalized
// and/or if it has been finalized but never used for drawing in process.
ipc::ReadOnlySharedMemoryHandle handle;
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
nsresult rv = aSurface->CloneHandle(handle);
if (rv == NS_ERROR_NOT_AVAILABLE) {
// It is at least as expensive to copy the image to the GPU process if we

View File

@@ -12,6 +12,7 @@
#include "mozilla/StaticMutex.h" // for StaticMutex
#include "mozilla/StaticPtr.h" // for StaticAutoPtr
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/gfx/2D.h" // for SurfaceFormat
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptorShared

View File

@@ -8,6 +8,7 @@
#include <string.h>
#include <algorithm>
#include "mozilla/Maybe.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/layers/PTextureChild.h"
#include "mozilla/layers/WebRenderBridgeChild.h"

View File

@@ -14,13 +14,15 @@
#include "nsXULAppAPI.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
// This is split out from SharedFontList.h because that header is included
// quite widely (via gfxPlatformFontList.h, gfxTextRun.h, etc). This header,
// which defines the actual shared-memory FontList class, is included only by
// the .cpp files that implement or directly interface with the font list, to
// avoid polluting other headers.
// quite widely (via gfxPlatformFontList.h, gfxTextRun.h, etc), and other code
// such as the generated DOM bindings code gets upset at (indirect) inclusion
// of <windows.h> via SharedMemory.h. So this header, which defines the actual
// shared-memory FontList class, is included only by the .cpp files that
// implement or directly interface with the font list, to avoid polluting other
// headers.
namespace mozilla {
namespace fontlist {
@@ -241,14 +243,14 @@ class FontList {
* list has changed/grown since the child was first initialized).
*/
void ShareShmBlockToProcess(uint32_t aIndex, base::ProcessId aPid,
ipc::ReadOnlySharedMemoryHandle* aOut) {
ipc::SharedMemory::Handle* aOut) {
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
if (aIndex >= mReadOnlyShmems.Length()) {
// Block index out of range
*aOut = nullptr;
*aOut = ipc::SharedMemory::NULLHandle();
return;
}
*aOut = mReadOnlyShmems[aIndex].Clone();
*aOut = mReadOnlyShmems[aIndex]->CloneHandle();
if (!*aOut) {
MOZ_CRASH("failed to share block");
}
@@ -259,14 +261,14 @@ class FontList {
* shared to the given process. This is used at child process startup
* to pass the complete list at once.
*/
void ShareBlocksToProcess(nsTArray<ipc::ReadOnlySharedMemoryHandle>* aBlocks,
void ShareBlocksToProcess(nsTArray<ipc::SharedMemory::Handle>* aBlocks,
base::ProcessId aPid);
ipc::ReadOnlySharedMemoryHandle ShareBlockToProcess(uint32_t aIndex,
base::ProcessId aPid);
ipc::SharedMemory::Handle ShareBlockToProcess(uint32_t aIndex,
base::ProcessId aPid);
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
ipc::ReadOnlySharedMemoryHandle aHandle);
ipc::SharedMemory::Handle aHandle);
/**
* Support for memory reporter.
*/
@@ -296,22 +298,13 @@ class FontList {
private:
struct ShmBlock {
// Takes ownership of aShmem. In a child process, aShmem will be mapped as
// read-only.
explicit ShmBlock(ipc::ReadOnlySharedMemoryMapping&& aShmem)
: mShmem(std::move(aShmem)) {
MOZ_ASSERT(!XRE_IsParentProcess());
}
explicit ShmBlock(ipc::SharedMemoryMapping&& aShmem)
: mShmem(std::move(aShmem)) {
MOZ_ASSERT(XRE_IsParentProcess());
}
// Takes ownership of aShmem. Note that in a child process, aShmem will be
// mapped as read-only.
explicit ShmBlock(RefPtr<ipc::SharedMemory>&& aShmem)
: mShmem(std::move(aShmem)) {}
// Get pointer to the mapped memory.
void* Memory() const { return mShmem.Address(); }
void Clear() { mShmem = nullptr; }
void* Memory() const { return mShmem->Memory(); }
// Only the parent process does allocation, so only it will update this
// field. Content processes read the value when checking Pointer validity.
@@ -333,8 +326,7 @@ class FontList {
return static_cast<BlockHeader*>(Memory())->mBlockSize;
}
private:
ipc::MutableOrReadOnlySharedMemoryMapping mShmem;
RefPtr<ipc::SharedMemory> mShmem;
};
Header& GetHeader() const;
@@ -377,10 +369,10 @@ class FontList {
nsTArray<mozilla::UniquePtr<ShmBlock>> mBlocks;
/**
* Auxiliary array, used only in the parent process; holds read-only handles
* for the shmem blocks; these are what will be shared to child processes.
* 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.
*/
nsTArray<ipc::ReadOnlySharedMemoryHandle> mReadOnlyShmems;
nsTArray<RefPtr<ipc::SharedMemory>> mReadOnlyShmems;
#ifdef XP_WIN
// Bool array to track whether we have read face names from the name table.

View File

@@ -6,6 +6,7 @@
#include "gfxPlatformFontList.h"
#include "gfxFontUtils.h"
#include "gfxFont.h"
#include "mozilla/ipc/SharedMemory.h"
#include "nsReadableUtils.h"
#include "prerror.h"
#include "mozilla/dom/ContentChild.h"
@@ -740,21 +741,25 @@ FontList::FontList(uint32_t aGeneration) {
// SetXPCOMProcessAttributes.
auto& blocks = dom::ContentChild::GetSingleton()->SharedFontListBlocks();
for (auto& handle : blocks) {
if (!handle) {
auto newShm = MakeRefPtr<ipc::SharedMemory>();
if (!newShm->IsHandleValid(handle)) {
// Bail out and let UpdateShmBlocks try to do its thing below.
break;
}
if (handle.Size() < SHM_BLOCK_SIZE) {
if (!newShm->SetHandle(std::move(handle),
ipc::SharedMemory::OpenRights::RightsReadOnly)) {
MOZ_CRASH("failed to set shm handle");
}
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
}
auto newShm = handle.Map();
if (!newShm || !newShm.Address()) {
MOZ_CRASH("failed to map shared memory");
}
uint32_t size = newShm.DataAs<BlockHeader>()->mBlockSize;
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
if (newShm.Size() < size) {
MOZ_CRASH("failed to map shared memory");
if (size != SHM_BLOCK_SIZE) {
newShm->Unmap();
if (!newShm->Map(size) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
}
}
mBlocks.AppendElement(new ShmBlock(std::move(newShm)));
}
@@ -799,17 +804,17 @@ FontList::Header& FontList::GetHeader() const MOZ_NO_THREAD_SAFETY_ANALYSIS {
bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
MOZ_ASSERT(XRE_IsParentProcess());
uint32_t size = std::max(aSizeNeeded, SHM_BLOCK_SIZE);
auto handle = ipc::shared_memory::CreateFreezable(size);
if (!handle) {
auto newShm = MakeRefPtr<ipc::SharedMemory>();
if (!newShm->CreateFreezable(size)) {
MOZ_CRASH("failed to create shared memory");
return false;
}
auto [newShm, readOnly] = std::move(handle).Map().Freeze();
if (!newShm || !newShm.Address()) {
if (!newShm->Map(size) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
return false;
}
if (!readOnly) {
auto readOnly = MakeRefPtr<ipc::SharedMemory>();
if (!newShm->ReadOnlyCopy(readOnly.get())) {
MOZ_CRASH("failed to create read-only copy");
return false;
}
@@ -843,13 +848,19 @@ bool FontList::AppendShmBlock(uint32_t aSizeNeeded) {
}
void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
ipc::ReadOnlySharedMemoryHandle aHandle) {
ipc::SharedMemory::Handle aHandle) {
MOZ_ASSERT(!XRE_IsParentProcess());
MOZ_ASSERT(mBlocks.Length() > 0);
if (!aHandle) {
auto newShm = MakeRefPtr<ipc::SharedMemory>();
if (!newShm->IsHandleValid(aHandle)) {
return;
}
if (!newShm->SetHandle(std::move(aHandle),
ipc::SharedMemory::RightsReadOnly)) {
MOZ_CRASH("failed to set shm handle");
}
if (aIndex != mBlocks.Length()) {
return;
}
@@ -857,15 +868,17 @@ void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
return;
}
auto newShm = aHandle.Map();
if (!newShm || !newShm.Address() || newShm.Size() < SHM_BLOCK_SIZE) {
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
}
uint32_t size = newShm.DataAs<BlockHeader>()->mBlockSize;
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
if (newShm.Size() < size) {
MOZ_CRASH("failed to map shared memory");
if (size != SHM_BLOCK_SIZE) {
newShm->Unmap();
if (!newShm->Map(size) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
}
}
mBlocks.AppendElement(new ShmBlock(std::move(newShm)));
@@ -873,7 +886,7 @@ void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
void FontList::DetachShmBlocks() {
for (auto& i : mBlocks) {
i->Clear();
i->mShmem = nullptr;
}
mBlocks.Clear();
mReadOnlyShmems.Clear();
@@ -884,22 +897,29 @@ FontList::ShmBlock* FontList::GetBlockFromParent(uint32_t aIndex) {
// 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
uint32_t generation = aIndex == 0 ? 0 : GetGeneration();
ipc::ReadOnlySharedMemoryHandle handle;
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
if (!dom::ContentChild::GetSingleton()->SendGetFontListShmBlock(
generation, aIndex, &handle)) {
return nullptr;
}
if (!handle) {
auto newShm = MakeRefPtr<ipc::SharedMemory>();
if (!newShm->IsHandleValid(handle)) {
return nullptr;
}
auto newShm = handle.Map();
if (!newShm || !newShm.Address() || newShm.Size() < SHM_BLOCK_SIZE) {
if (!newShm->SetHandle(std::move(handle),
ipc::SharedMemory::RightsReadOnly)) {
MOZ_CRASH("failed to set shm handle");
}
if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
}
uint32_t size = newShm.DataAs<BlockHeader>()->mBlockSize;
uint32_t size = static_cast<BlockHeader*>(newShm->Memory())->mBlockSize;
MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
if (newShm.Size() < size) {
MOZ_CRASH("failed to map shared memory");
if (size != SHM_BLOCK_SIZE) {
newShm->Unmap();
if (!newShm->Map(size) || !newShm->Memory()) {
MOZ_CRASH("failed to map shared memory");
}
}
return new ShmBlock(std::move(newShm));
}
@@ -927,10 +947,10 @@ bool FontList::UpdateShmBlocks(bool aMustLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
}
void FontList::ShareBlocksToProcess(
nsTArray<ipc::ReadOnlySharedMemoryHandle>* aBlocks, base::ProcessId aPid) {
nsTArray<ipc::SharedMemory::Handle>* aBlocks, base::ProcessId aPid) {
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
for (auto& shmem : mReadOnlyShmems) {
auto handle = shmem.Clone();
auto handle = shmem->CloneHandle();
if (!handle) {
// If something went wrong here, we just bail out; the child will need to
// request the blocks as needed, at some performance cost. (Although in
@@ -943,13 +963,13 @@ void FontList::ShareBlocksToProcess(
}
}
ipc::ReadOnlySharedMemoryHandle FontList::ShareBlockToProcess(
uint32_t aIndex, base::ProcessId aPid) {
ipc::SharedMemory::Handle FontList::ShareBlockToProcess(uint32_t aIndex,
base::ProcessId aPid) {
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
MOZ_RELEASE_ASSERT(aIndex < mReadOnlyShmems.Length());
return mReadOnlyShmems[aIndex].Clone();
return mReadOnlyShmems[aIndex]->CloneHandle();
}
Pointer FontList::Alloc(uint32_t aSize) {
@@ -1390,7 +1410,7 @@ size_t FontList::SizeOfExcludingThis(
mozilla::MallocSizeOf aMallocSizeOf) const {
size_t result = mBlocks.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (const auto& b : mBlocks) {
result += aMallocSizeOf(b.get());
result += aMallocSizeOf(b.get()) + aMallocSizeOf(b->mShmem.get());
}
return result;
}

View File

@@ -9,6 +9,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/SharedMemory.h"
#include "gfxASurface.h"
#include "gfxImageSurface.h"
@@ -32,6 +33,7 @@ extern const cairo_user_data_key_t SHM_KEY;
template <typename Base, typename Sub>
class gfxBaseSharedMemorySurface : public Base {
typedef mozilla::ipc::SharedMemory SharedMemory;
typedef mozilla::ipc::Shmem Shmem;
protected:

View File

@@ -3111,7 +3111,7 @@ void gfxPlatformFontList::CancelInitOtherFamilyNamesTask() {
void gfxPlatformFontList::ShareFontListShmBlockToProcess(
uint32_t aGeneration, uint32_t aIndex, base::ProcessId aPid,
mozilla::ipc::ReadOnlySharedMemoryHandle* aOut) {
mozilla::ipc::SharedMemory::Handle* aOut) {
auto list = SharedFontList();
if (!list) {
return;
@@ -3119,12 +3119,12 @@ void gfxPlatformFontList::ShareFontListShmBlockToProcess(
if (!aGeneration || list->GetGeneration() == aGeneration) {
list->ShareShmBlockToProcess(aIndex, aPid, aOut);
} else {
*aOut = nullptr;
*aOut = mozilla::ipc::SharedMemory::NULLHandle();
}
}
void gfxPlatformFontList::ShareFontListToProcess(
nsTArray<mozilla::ipc::ReadOnlySharedMemoryHandle>* aBlocks,
nsTArray<mozilla::ipc::SharedMemory::Handle>* aBlocks,
base::ProcessId aPid) {
auto list = SharedFontList();
if (list) {
@@ -3132,16 +3132,15 @@ void gfxPlatformFontList::ShareFontListToProcess(
}
}
mozilla::ipc::ReadOnlySharedMemoryHandle
gfxPlatformFontList::ShareShmBlockToProcess(uint32_t aIndex,
base::ProcessId aPid) {
mozilla::ipc::SharedMemory::Handle gfxPlatformFontList::ShareShmBlockToProcess(
uint32_t aIndex, base::ProcessId aPid) {
MOZ_RELEASE_ASSERT(SharedFontList());
return SharedFontList()->ShareBlockToProcess(aIndex, aPid);
}
void gfxPlatformFontList::ShmBlockAdded(
uint32_t aGeneration, uint32_t aIndex,
mozilla::ipc::ReadOnlySharedMemoryHandle aHandle) {
mozilla::ipc::SharedMemory::Handle aHandle) {
if (SharedFontList()) {
AutoLock lock(mLock);
SharedFontList()->ShmBlockAdded(aGeneration, aIndex, std::move(aHandle));

View File

@@ -27,7 +27,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/RangedArray.h"
#include "mozilla/RecursiveMutex.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemory.h"
#include "nsLanguageAtomService.h"
namespace mozilla {
@@ -353,20 +353,20 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
// Create a handle for a single shmem block (identified by index) ready to
// be shared to the given processId.
void ShareFontListShmBlockToProcess(
uint32_t aGeneration, uint32_t aIndex, base::ProcessId aPid,
mozilla::ipc::ReadOnlySharedMemoryHandle* aOut);
void ShareFontListShmBlockToProcess(uint32_t aGeneration, uint32_t aIndex,
base::ProcessId aPid,
mozilla::ipc::SharedMemory::Handle* aOut);
// Populate the array aBlocks with the complete list of shmem handles ready
// to be shared to the given processId.
void ShareFontListToProcess(
nsTArray<mozilla::ipc::ReadOnlySharedMemoryHandle>* aBlocks,
nsTArray<mozilla::ipc::SharedMemory::Handle>* aBlocks,
base::ProcessId aPid);
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
mozilla::ipc::ReadOnlySharedMemoryHandle aHandle);
mozilla::ipc::SharedMemory::Handle aHandle);
mozilla::ipc::ReadOnlySharedMemoryHandle ShareShmBlockToProcess(
mozilla::ipc::SharedMemory::Handle ShareShmBlockToProcess(
uint32_t aIndex, base::ProcessId aPid);
void SetCharacterMap(uint32_t aGeneration, uint32_t aFamilyIndex, bool aAlias,

View File

@@ -13,6 +13,7 @@
#include "mozilla/dom/WebXRBinding.h"
#include "mozilla/dom/XRFrame.h"
#include "mozilla/gfx/PVRManagerChild.h"
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
#include "mozilla/layers/LayersTypes.h" // for LayersBackend

View File

@@ -2549,13 +2549,7 @@ pub unsafe extern "C" fn wgpu_server_queue_write_action(
mut error_buf: ErrorBuffer,
) {
let action: QueueWriteAction = bincode::deserialize(byte_buf.as_slice()).unwrap();
// It is undefined behavior to pass a null pointer to `slice::from_raw_parts`, so in the case
// of a null pointer (which occurs if `data_length` is 0), we use a dangling pointer.
let data = ptr::NonNull::new(data as *mut u8).unwrap_or_else(|| {
assert!(data_length == 0);
ptr::NonNull::dangling()
});
let data = slice::from_raw_parts(data.as_ptr(), data_length);
let data = slice::from_raw_parts(data, data_length);
let result = match action {
QueueWriteAction::Buffer { dst, offset } => {
global.queue_write_buffer(self_id, dst, offset, data)

View File

@@ -7,7 +7,6 @@
#include "ImageMemoryReporter.h"
#include "Image.h"
#include "base/process_util.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/StaticPrefs_image.h"
#include "nsIMemoryReporter.h"
@@ -114,7 +113,7 @@ void ImageMemoryReporter::ReportSharedSurface(
path.AppendInt(aEntry.mCreatorRef);
path.AppendLiteral(")/decoded-");
size_t surfaceSize = mozilla::ipc::shared_memory::PageAlignedSize(
size_t surfaceSize = mozilla::ipc::SharedMemory::PageAlignedSize(
aEntry.mSize.height * aEntry.mStride);
// If this memory has already been reported elsewhere (e.g. as part of our

View File

@@ -331,10 +331,11 @@ void nsHyphenationManager::LoadAliases() {
void nsHyphenationManager::ShareHyphDictToProcess(
nsIURI* aURI, base::ProcessId aPid,
mozilla::ipc::ReadOnlySharedMemoryHandle* aOutHandle) {
mozilla::ipc::SharedMemory::Handle* aOutHandle, uint32_t* aOutSize) {
MOZ_ASSERT(XRE_IsParentProcess());
// aURI will be referring to an omnijar resource (otherwise just bail).
*aOutHandle = nullptr;
*aOutHandle = mozilla::ipc::SharedMemory::NULLHandle();
*aOutSize = 0;
// Extract the locale code from the URI, and get the corresponding
// hyphenator (loading it into shared memory if necessary).
@@ -357,7 +358,7 @@ void nsHyphenationManager::ShareHyphDictToProcess(
return;
}
*aOutHandle = hyph->CloneHandle();
hyph->CloneHandle(aOutHandle, aOutSize);
}
size_t nsHyphenationManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {

View File

@@ -8,7 +8,7 @@
#include "base/process.h"
#include "mozilla/Omnijar.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemory.h"
#include "nsHashKeys.h"
#include "nsAtomHashKeys.h"
#include "nsInterfaceHashtable.h"
@@ -27,9 +27,9 @@ class nsHyphenationManager : public nsIObserver {
already_AddRefed<nsHyphenator> GetHyphenator(nsAtom* aLocale);
void ShareHyphDictToProcess(
nsIURI* aURI, base::ProcessId aPid,
mozilla::ipc::ReadOnlySharedMemoryHandle* aOutHandle);
void ShareHyphDictToProcess(nsIURI* aURI, base::ProcessId aPid,
mozilla::ipc::SharedMemory::Handle* aOutHandle,
uint32_t* aOutSize);
static nsHyphenationManager* Instance();

View File

@@ -7,8 +7,6 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Omnijar.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIFile.h"
@@ -34,7 +32,7 @@ void DefaultDelete<const CompiledData>::operator()(
mapped_hyph_free_compiled_data(const_cast<CompiledData*>(aData));
}
static const uint8_t* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) {
static const void* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) {
// Try to get the jarfile's nsZipArchive, find the relevant item, and return
// a pointer to its data provided it is stored uncompressed.
nsCOMPtr<nsIURI> jarFile;
@@ -68,53 +66,63 @@ static const uint8_t* GetItemPtrFromJarURI(nsIJARURI* aJAR, uint32_t* aLength) {
return nullptr;
}
static ipc::ReadOnlySharedMemoryMapping GetHyphDictFromParent(nsIURI* aURI) {
static RefPtr<ipc::SharedMemory> GetHyphDictFromParent(nsIURI* aURI,
uint32_t* aLength) {
MOZ_ASSERT(!XRE_IsParentProcess());
ipc::ReadOnlySharedMemoryHandle handle;
ipc::SharedMemory::Handle handle = ipc::SharedMemory::NULLHandle();
uint32_t size;
MOZ_ASSERT(aURI);
if (!dom::ContentChild::GetSingleton()->SendGetHyphDict(aURI, &handle)) {
if (!dom::ContentChild::GetSingleton()->SendGetHyphDict(aURI, &handle,
&size)) {
return nullptr;
}
if (!handle.IsValid()) {
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
if (!shm->IsHandleValid(handle)) {
return nullptr;
}
auto map = handle.Map();
if (!map) {
if (!shm->SetHandle(std::move(handle), ipc::SharedMemory::RightsReadOnly)) {
return nullptr;
}
if (!map.Address()) {
if (!shm->Map(size)) {
return nullptr;
}
return map;
char* addr = static_cast<char*>(shm->Memory());
if (!addr) {
return nullptr;
}
*aLength = size;
return shm;
}
static ipc::ReadOnlySharedMemoryHandle CopyToShmem(const CompiledData* aData) {
static RefPtr<ipc::SharedMemory> CopyToShmem(const CompiledData* aData) {
MOZ_ASSERT(XRE_IsParentProcess());
// 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
// without hyphenation.
uint32_t size = mapped_hyph_compiled_data_size(aData);
auto handle = ipc::shared_memory::CreateFreezable(size);
if (!handle) {
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
if (!shm->CreateFreezable(size)) {
return nullptr;
}
auto map = std::move(handle).Map();
if (!map) {
if (!shm->Map(size)) {
return nullptr;
}
char* buffer = map.DataAs<char>();
char* buffer = static_cast<char*>(shm->Memory());
if (!buffer) {
return nullptr;
}
memcpy(buffer, mapped_hyph_compiled_data_ptr(aData), size);
auto [_, readOnlyHandle] = std::move(map).Freeze();
return std::move(readOnlyHandle);
if (!shm->Freeze()) {
return nullptr;
}
return shm;
}
static ipc::ReadOnlySharedMemoryHandle LoadFromURI(nsIURI* aURI,
bool aPrecompiled) {
static RefPtr<ipc::SharedMemory> LoadFromURI(nsIURI* aURI, uint32_t* aLength,
bool aPrecompiled) {
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsIChannel> channel;
if (NS_FAILED(NS_NewChannel(
@@ -137,15 +145,14 @@ static ipc::ReadOnlySharedMemoryHandle LoadFromURI(nsIURI* aURI,
}
if (aPrecompiled) {
auto handle = ipc::shared_memory::CreateFreezable(available);
if (!handle) {
RefPtr<ipc::SharedMemory> shm = MakeRefPtr<ipc::SharedMemory>();
if (!shm->CreateFreezable(available)) {
return nullptr;
}
auto map = std::move(handle).Map();
if (!map) {
if (!shm->Map(available)) {
return nullptr;
}
char* buffer = map.DataAs<char>();
char* buffer = static_cast<char*>(shm->Memory());
if (!buffer) {
return nullptr;
}
@@ -161,13 +168,12 @@ static ipc::ReadOnlySharedMemoryHandle LoadFromURI(nsIURI* aURI,
return nullptr;
}
auto [_, readOnlyHandle] = std::move(map).Freeze();
if (!readOnlyHandle) {
if (!shm->Freeze()) {
return nullptr;
}
return std::move(readOnlyHandle);
*aLength = bytesRead;
return shm;
}
// Read from the URI into a temporary buffer, compile it, then copy the
@@ -182,6 +188,7 @@ static ipc::ReadOnlySharedMemoryHandle LoadFromURI(nsIURI* aURI,
UniquePtr<const CompiledData> data(mapped_hyph_compile_buffer(
reinterpret_cast<const uint8_t*>(buffer.get()), bytesRead, false));
if (data) {
*aLength = mapped_hyph_compiled_data_size(data.get());
return CopyToShmem(data.get());
}
@@ -189,7 +196,8 @@ static ipc::ReadOnlySharedMemoryHandle LoadFromURI(nsIURI* aURI,
}
nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
: mDict(Span<const uint8_t>()),
: mDict(static_cast<const void*>(nullptr)),
mDictSize(0),
mHyphenateCapitalized(aHyphenateCapitalized) {
// Files with extension ".hyf" are expected to be precompiled mapped_hyph
// tables; we also support uncompiled ".dic" files, but they are more
@@ -202,11 +210,13 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
// them a compiled version of the resource, so that we only pay the cost of
// compilation once per language per session.
if (!precompiled && !XRE_IsParentProcess()) {
auto shm = GetHyphDictFromParent(aURI);
uint32_t length;
RefPtr<ipc::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
if (shm) {
// We don't need to validate mDict because the parent process
// will have done so.
mDict.emplace<ipc::ReadOnlySharedMemoryMapping>(std::move(shm));
mDictSize = length;
mDict = AsVariant(std::move(shm));
}
return;
}
@@ -216,13 +226,15 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
// This gives us a raw pointer into the omnijar's data (if uncompressed);
// we do not own it and must not attempt to free it!
uint32_t length;
const uint8_t* ptr = GetItemPtrFromJarURI(jar, &length);
const void* ptr = GetItemPtrFromJarURI(jar, &length);
if (ptr) {
if (precompiled) {
// The data should be directly usable by mapped_hyph; validate that it
// looks correct, and save the pointer.
if (mapped_hyph_is_valid_hyphenator(ptr, length)) {
mDict.emplace<Span<const uint8_t>>(ptr, length);
if (mapped_hyph_is_valid_hyphenator(static_cast<const uint8_t*>(ptr),
length)) {
mDictSize = length;
mDict = AsVariant(ptr);
return;
}
} else {
@@ -230,12 +242,13 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
// We then move it to shared memory so we can expose it to content
// processes.
MOZ_ASSERT(XRE_IsParentProcess());
UniquePtr<const CompiledData> data(
mapped_hyph_compile_buffer(ptr, length, false));
UniquePtr<const CompiledData> data(mapped_hyph_compile_buffer(
static_cast<const uint8_t*>(ptr), length, false));
if (data) {
auto shm = CopyToShmem(data.get());
RefPtr<ipc::SharedMemory> shm = CopyToShmem(data.get());
if (shm) {
mDict.emplace<ipc::ReadOnlySharedMemoryHandle>(std::move(shm));
mDictSize = mapped_hyph_compiled_data_size(data.get());
mDict = AsVariant(std::move(shm));
return;
}
}
@@ -246,17 +259,19 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
// 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).
if (XRE_IsParentProcess()) {
auto shm = LoadFromURI(aURI, precompiled);
RefPtr<ipc::SharedMemory> shm = LoadFromURI(aURI, &length, precompiled);
if (shm) {
mDict.emplace<ipc::ReadOnlySharedMemoryHandle>(std::move(shm));
mDictSize = length;
mDict = AsVariant(std::move(shm));
return;
}
} else {
auto shm = GetHyphDictFromParent(aURI);
RefPtr<ipc::SharedMemory> shm = GetHyphDictFromParent(aURI, &length);
if (shm) {
// We don't need to validate mDict because the parent process
// will have done so.
mDict.emplace<ipc::ReadOnlySharedMemoryMapping>(std::move(shm));
mDictSize = length;
mDict = AsVariant(std::move(shm));
return;
}
}
@@ -297,9 +312,10 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
UniquePtr<const CompiledData> data(
mapped_hyph_compile_file(path.get(), false));
if (data) {
auto shm = CopyToShmem(data.get());
RefPtr<ipc::SharedMemory> shm = CopyToShmem(data.get());
if (shm) {
mDict.emplace<ipc::ReadOnlySharedMemoryHandle>(std::move(shm));
mDictSize = mapped_hyph_compiled_data_size(data.get());
mDict = AsVariant(std::move(shm));
return;
}
}
@@ -317,9 +333,8 @@ nsHyphenator::nsHyphenator(nsIURI* aURI, bool aHyphenateCapitalized)
bool nsHyphenator::IsValid() {
return mDict.match(
[](Span<const uint8_t>& span) { return span.data() != nullptr; },
[](ipc::ReadOnlySharedMemoryHandle& shm) { return shm.IsValid(); },
[](ipc::ReadOnlySharedMemoryMapping& shm) { return shm.IsValid(); },
[](const void*& ptr) { return ptr != nullptr; },
[](RefPtr<ipc::SharedMemory>& shm) { return shm != nullptr; },
[](UniquePtr<const HyphDic>& hyph) { return hyph != nullptr; });
}
@@ -426,22 +441,17 @@ void nsHyphenator::HyphenateWord(const nsAString& aString, uint32_t aStart,
AutoTArray<uint8_t, 200> hyphenValues;
hyphenValues.SetLength(utf8.Length());
int32_t result = mDict.match(
[&](Span<const uint8_t>& span) {
[&](const void*& ptr) {
return mapped_hyph_find_hyphen_values_raw(
span.data(), span.size(), utf8.BeginReading(), utf8.Length(),
hyphenValues.Elements(), hyphenValues.Length());
},
[&](ipc::ReadOnlySharedMemoryHandle& shm) {
// Only the parent process can have a handle stored. We should never
// get to this point with just a handle.
MOZ_ASSERT_UNREACHABLE("Unexpected HyphenateWord with only a handle");
return 0;
},
[&](ipc::ReadOnlySharedMemoryMapping& shm) {
return mapped_hyph_find_hyphen_values_raw(
shm.DataAs<uint8_t>(), shm.Size(), utf8.BeginReading(),
static_cast<const uint8_t*>(ptr), mDictSize, utf8.BeginReading(),
utf8.Length(), hyphenValues.Elements(), hyphenValues.Length());
},
[&](RefPtr<ipc::SharedMemory>& shm) {
return mapped_hyph_find_hyphen_values_raw(
static_cast<const uint8_t*>(shm->Memory()), mDictSize,
utf8.BeginReading(), utf8.Length(), hyphenValues.Elements(),
hyphenValues.Length());
},
[&](UniquePtr<const HyphDic>& hyph) {
return mapped_hyph_find_hyphen_values_dic(
hyph.get(), utf8.BeginReading(), utf8.Length(),
@@ -476,11 +486,14 @@ void nsHyphenator::HyphenateWord(const nsAString& aString, uint32_t aStart,
}
}
ipc::ReadOnlySharedMemoryHandle nsHyphenator::CloneHandle() {
MOZ_ASSERT(XRE_IsParentProcess());
if (mDict.is<ipc::ReadOnlySharedMemoryHandle>()) {
return mDict.as<ipc::ReadOnlySharedMemoryHandle>().Clone();
void nsHyphenator::CloneHandle(ipc::SharedMemory::Handle* aOutHandle,
uint32_t* aOutSize) {
// 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
// for this to be a fatal error.
if (!mDict.is<RefPtr<ipc::SharedMemory>>()) {
return;
}
return nullptr;
*aOutHandle = mDict.as<RefPtr<ipc::SharedMemory>>()->CloneHandle();
*aOutSize = mDictSize;
}

View File

@@ -6,10 +6,8 @@
#ifndef nsHyphenator_h__
#define nsHyphenator_h__
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Variant.h"
#include "nsCOMPtr.h"
@@ -44,7 +42,8 @@ class nsHyphenator {
nsresult Hyphenate(const nsAString& aText, nsTArray<bool>& aHyphens);
mozilla::ipc::ReadOnlySharedMemoryHandle CloneHandle();
void CloneHandle(mozilla::ipc::SharedMemory::Handle* aOutHandle,
uint32_t* aOutSize);
private:
~nsHyphenator() = default;
@@ -52,13 +51,12 @@ class nsHyphenator {
void HyphenateWord(const nsAString& aString, uint32_t aStart, uint32_t aLimit,
nsTArray<bool>& aHyphens);
mozilla::Variant<
mozilla::Span<const uint8_t>, // raw pointer to uncompressed omnijar data
mozilla::ipc::ReadOnlySharedMemoryHandle, // shmem handle, in the parent
mozilla::ipc::ReadOnlySharedMemoryMapping, // mapped shmem, in the child
mozilla::UniquePtr<const HyphDic> // loaded by mapped_hyph
>
mozilla::Variant<const void*, // raw pointer to uncompressed omnijar data
RefPtr<mozilla::ipc::SharedMemory>, // shmem block
mozilla::UniquePtr<const HyphDic> // loaded by mapped_hyph
>
mDict;
uint32_t mDictSize; // size of mDict data (not used if type is HyphDic)
bool mHyphenateCapitalized;
};

View File

@@ -8,7 +8,7 @@
%{C++
#include "mozilla/MemoryReporting.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemory.h"
namespace mozilla {
namespace dom {
@@ -27,7 +27,7 @@ class ContentParent;
%}
[ptr] native ContentParent(mozilla::dom::ContentParent);
native ReadOnlySharedMemoryHandle(mozilla::ipc::ReadOnlySharedMemoryHandle&&);
[ref] native SharedMemoryHandle(mozilla::ipc::SharedMemoryHandle);
native MallocSizeOf(mozilla::MallocSizeOf);
[scriptable, builtinclass, uuid(D85A17C2-AA7C-11d2-9B8C-00805F8A16D9)]
@@ -104,5 +104,6 @@ interface nsIStringBundleService : nsISupports
[notxpcom, nostdcall] void sendContentBundles(in ContentParent aContentParent);
[notxpcom, nostdcall] void registerContentBundle(in ACString aBundleURL,
in ReadOnlySharedMemoryHandle aMapHandle);
[const] in SharedMemoryHandle aMapHandle,
in size_t aMapSize);
};

View File

@@ -27,7 +27,6 @@
#include "nsSimpleEnumerator.h"
#include "nsStringStream.h"
#include "mozilla/dom/txXSLTMsgsURL.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ResultExtensions.h"
@@ -202,7 +201,8 @@ class SharedStringBundle final : public nsStringBundleBase {
* called in child processes, for bundles initially created in the parent
* process.
*/
void SetMapFile(mozilla::ipc::ReadOnlySharedMemoryHandle&& aHandle);
void SetMapFile(const mozilla::ipc::SharedMemoryHandle& aHandle,
size_t aSize);
NS_DECL_ISUPPORTS_INHERITED
NS_DECLARE_STATIC_IID_ACCESSOR(SHAREDSTRINGBUNDLE_IID)
@@ -211,21 +211,21 @@ class SharedStringBundle final : public nsStringBundleBase {
/**
* Returns a copy of the file descriptor pointing to the shared memory
* key-value store for this string bundle. This should only be called in the
* key-values tore for this string bundle. This should only be called in the
* parent process, and may be used to send shared string bundles to child
* processes.
*/
mozilla::ipc::ReadOnlySharedMemoryHandle CloneHandle() const {
mozilla::ipc::SharedMemoryHandle CloneHandle() const {
MOZ_ASSERT(XRE_IsParentProcess());
if (mMapHandle.isSome()) {
return mMapHandle.ref().Clone();
return mozilla::ipc::SharedMemory::CloneHandle(mMapHandle.ref());
}
return mStringMap->CloneHandle();
}
size_t MapSize() const {
if (mMapHandle.isSome()) {
return mMapHandle->Size();
return mMapSize;
}
if (mStringMap) {
return mStringMap->MapSize();
@@ -241,6 +241,7 @@ class SharedStringBundle final : public nsStringBundleBase {
StringBundleDescriptor descriptor;
descriptor.bundleURL() = BundleURL();
descriptor.mapHandle() = CloneHandle();
descriptor.mapSize() = MapSize();
return descriptor;
}
@@ -265,7 +266,8 @@ class SharedStringBundle final : public nsStringBundleBase {
private:
RefPtr<SharedStringMap> mStringMap;
Maybe<mozilla::ipc::ReadOnlySharedMemoryHandle> mMapHandle;
Maybe<mozilla::ipc::SharedMemoryHandle> mMapHandle;
size_t mMapSize;
};
NS_DEFINE_STATIC_IID_ACCESSOR(SharedStringBundle, SHAREDSTRINGBUNDLE_IID)
@@ -513,7 +515,8 @@ nsresult SharedStringBundle::LoadProperties() {
if (mStringMap) return NS_OK;
if (mMapHandle.isSome()) {
mStringMap = new SharedStringMap(mMapHandle.extract());
mStringMap = new SharedStringMap(mMapHandle.ref(), mMapSize);
mMapHandle.reset();
return NS_OK;
}
@@ -567,10 +570,11 @@ nsresult SharedStringBundle::LoadProperties() {
}
void SharedStringBundle::SetMapFile(
mozilla::ipc::ReadOnlySharedMemoryHandle&& aHandle) {
const mozilla::ipc::SharedMemoryHandle& aHandle, size_t aSize) {
MOZ_ASSERT(XRE_IsContentProcess());
mStringMap = nullptr;
mMapHandle.emplace(std::move(aHandle));
mMapHandle.emplace(mozilla::ipc::SharedMemory::CloneHandle(aHandle));
mMapSize = aSize;
}
NS_IMETHODIMP
@@ -818,7 +822,7 @@ void nsStringBundleService::SendContentBundles(ContentParent* aContentParent) {
void nsStringBundleService::RegisterContentBundle(
const nsACString& aBundleURL,
mozilla::ipc::ReadOnlySharedMemoryHandle&& aMapHandle) {
const mozilla::ipc::SharedMemoryHandle& aMapHandle, size_t aMapSize) {
RefPtr<StringBundleProxy> proxy;
bundleCacheEntry_t* cacheEntry = mBundleMap.Get(aBundleURL);
@@ -836,7 +840,7 @@ void nsStringBundleService::RegisterContentBundle(
auto bundle = MakeBundleRefPtr<SharedStringBundle>(
PromiseFlatCString(aBundleURL).get());
bundle->SetMapFile(std::move(aMapHandle));
bundle->SetMapFile(aMapHandle, aMapSize);
if (proxy) {
proxy->Retarget(bundle);

View File

@@ -73,7 +73,7 @@ MessageBufferReader::MessageBufferReader(MessageReader* reader,
return;
}
if (shmem_ok) {
mozilla::ipc::shared_memory::MutableHandle handle;
mozilla::ipc::shared_memory::Handle handle;
if (!IPC::ReadParam(reader, &handle)) {
reader->FatalError("failed to read shared memory handle");
return;

View File

@@ -18,7 +18,6 @@
#include "base/pickle.h"
#include "chrome/common/ipc_message.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#if defined(XP_WIN)
# include <windows.h>
@@ -33,6 +32,7 @@ namespace mozilla::ipc {
class IProtocol;
template <typename P>
struct IPDLParamTraits;
class SharedMemory;
namespace shared_memory {
class Cursor;
}

View File

@@ -7,15 +7,16 @@
#include "mozilla/ipc/BigBuffer.h"
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/ipc/SharedMemory.h"
#include "nsDebug.h"
namespace mozilla::ipc {
BigBuffer::BigBuffer(Adopt, SharedMemoryMappingWithHandle&& aSharedMemory,
size_t aSize)
: mSize(aSize), mData(AsVariant(std::move(aSharedMemory))) {
MOZ_RELEASE_ASSERT(mData.as<1>(), "shared memory must be valid");
MOZ_RELEASE_ASSERT(mSize <= mData.as<1>().Size(),
BigBuffer::BigBuffer(Adopt, SharedMemory* aSharedMemory, size_t aSize)
: mSize(aSize), mData(AsVariant(RefPtr{aSharedMemory})) {
MOZ_RELEASE_ASSERT(aSharedMemory && aSharedMemory->Memory(),
"shared memory must be non-null and mapped");
MOZ_RELEASE_ASSERT(mSize <= aSharedMemory->Size(),
"shared memory region isn't large enough");
}
@@ -23,11 +24,13 @@ BigBuffer::BigBuffer(Adopt, uint8_t* aData, size_t aSize)
: mSize(aSize), mData(AsVariant(UniqueFreePtr<uint8_t[]>{aData})) {}
uint8_t* BigBuffer::Data() {
return mData.is<0>() ? mData.as<0>().get() : mData.as<1>().DataAs<uint8_t>();
return mData.is<0>() ? mData.as<0>().get()
: reinterpret_cast<uint8_t*>(mData.as<1>()->Memory());
}
const uint8_t* BigBuffer::Data() const {
return mData.is<0>() ? mData.as<0>().get()
: mData.as<1>().DataAs<const uint8_t>();
return mData.is<0>()
? mData.as<0>().get()
: reinterpret_cast<const uint8_t*>(mData.as<1>()->Memory());
}
auto BigBuffer::TryAllocBuffer(size_t aSize) -> Maybe<Storage> {
@@ -38,12 +41,12 @@ auto BigBuffer::TryAllocBuffer(size_t aSize) -> Maybe<Storage> {
return Some(AsVariant(std::move(mem)));
}
size_t capacity = shared_memory::PageAlignedSize(aSize);
auto mapping = shared_memory::Create(capacity).MapWithHandle();
if (!mapping) {
RefPtr<SharedMemory> shmem = new SharedMemory();
size_t capacity = SharedMemory::PageAlignedSize(aSize);
if (!shmem->Create(capacity) || !shmem->Map(capacity)) {
return {};
}
return Some(AsVariant(std::move(mapping)));
return Some(AsVariant(shmem));
}
} // namespace mozilla::ipc
@@ -59,11 +62,8 @@ void IPC::ParamTraits<mozilla::ipc::BigBuffer>::Write(MessageWriter* aWriter,
WriteParam(aWriter, isShmem);
if (isShmem) {
auto handle = data.as<1>().Handle().Clone();
if (!handle) {
if (!data.as<1>()->WriteHandle(aWriter)) {
aWriter->FatalError("Failed to write data shmem");
} else {
WriteParam(aWriter, std::move(handle));
}
} else {
aWriter->WriteBytes(data.as<0>().get(), size);
@@ -81,18 +81,13 @@ bool IPC::ParamTraits<mozilla::ipc::BigBuffer>::Read(MessageReader* aReader,
}
if (isShmem) {
MutableSharedMemoryHandle handle;
size_t expected_size = shared_memory::PageAlignedSize(size);
if (!ReadParam(aReader, &handle) || !handle) {
RefPtr<SharedMemory> shmem = new SharedMemory();
size_t capacity = SharedMemory::PageAlignedSize(size);
if (!shmem->ReadHandle(aReader) || !shmem->Map(capacity)) {
aReader->FatalError("Failed to read data shmem");
return false;
}
auto mapping = std::move(handle).MapWithHandle();
if (!mapping || mapping.Size() != expected_size) {
aReader->FatalError("Failed to map data shmem");
return false;
}
*aResult = BigBuffer(BigBuffer::Adopt{}, std::move(mapping), size);
*aResult = BigBuffer(BigBuffer::Adopt{}, shmem, size);
return true;
}

View File

@@ -9,10 +9,9 @@
#include <stdlib.h>
#include <inttypes.h>
#include "mozilla/Maybe.h"
#include "mozilla/Span.h"
#include "mozilla/Variant.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
namespace mozilla::ipc {
@@ -63,8 +62,8 @@ class BigBuffer {
// Create a new BigBuffer from an existing shared memory region, taking
// ownership of that shared memory region. The shared memory region must be
// valid and large enough to fit aSize bytes.
BigBuffer(Adopt, SharedMemoryMappingWithHandle&& aSharedMemory, size_t aSize);
// non-null, mapped, and large enough to fit aSize bytes.
BigBuffer(Adopt, SharedMemory* aSharedMemory, size_t aSize);
// Create a new BigBuffer from an existing memory buffer, taking ownership of
// that memory region. The region will be freed using `free()` when it is no
@@ -88,16 +87,14 @@ class BigBuffer {
// If the BigBuffer is backed by shared memory, returns a pointer to the
// backing SharedMemory region.
// This is only meant to be used in tests.
const SharedMemoryMappingWithHandle* GetSharedMemory() const {
return mData.is<1>() ? &mData.as<1>() : nullptr;
SharedMemory* GetSharedMemory() const {
return mData.is<1>() ? mData.as<1>().get() : nullptr;
}
private:
friend struct IPC::ParamTraits<mozilla::ipc::BigBuffer>;
using Storage =
Variant<UniqueFreePtr<uint8_t[]>, SharedMemoryMappingWithHandle>;
using Storage = Variant<UniqueFreePtr<uint8_t[]>, RefPtr<SharedMemory>>;
// Empty storage which holds no data.
static Storage NoData() { return AsVariant(UniqueFreePtr<uint8_t[]>{}); }

View File

@@ -15,7 +15,7 @@
#endif
#if !defined(XP_WIN) && !defined(XP_NETBSD) && !defined(XP_OPENBSD)
# include <pthread.h>
# include "mozilla/ipc/SharedMemoryMapping.h"
# include "mozilla/ipc/SharedMemory.h"
# include "mozilla/Atomics.h"
#endif
@@ -39,7 +39,7 @@ namespace mozilla {
#if defined(XP_WIN)
typedef mozilla::UniqueFileHandle CrossProcessMutexHandle;
#elif !defined(XP_NETBSD) && !defined(XP_OPENBSD)
typedef mozilla::ipc::MutableSharedMemoryHandle CrossProcessMutexHandle;
typedef mozilla::ipc::SharedMemory::Handle CrossProcessMutexHandle;
#else
// Stub for other platforms. We can't use uintptr_t here since different
// processes could disagree on its size.
@@ -104,7 +104,7 @@ class CrossProcessMutex {
#if defined(XP_WIN)
HANDLE mMutex;
#elif !defined(XP_NETBSD) && !defined(XP_OPENBSD)
mozilla::ipc::SharedMemoryMappingWithHandle mSharedBuffer;
RefPtr<mozilla::ipc::SharedMemory> mSharedBuffer;
pthread_mutex_t* mMutex;
mozilla::Atomic<int32_t>* mCount;
#endif

View File

@@ -6,7 +6,6 @@
#include "CrossProcessMutex.h"
#include "mozilla/Unused.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "nsDebug.h"
#include "nsISupportsImpl.h"
@@ -44,12 +43,16 @@ CrossProcessMutex::CrossProcessMutex(const char*)
// they specifically are not on Linux.
MOZ_RELEASE_ASSERT(false);
#endif
mSharedBuffer = ipc::shared_memory::Create(sizeof(MutexData)).MapWithHandle();
if (!mSharedBuffer) {
mSharedBuffer = new ipc::SharedMemory;
if (!mSharedBuffer->Create(sizeof(MutexData))) {
MOZ_CRASH();
}
MutexData* data = mSharedBuffer.DataAs<MutexData>();
if (!mSharedBuffer->Map(sizeof(MutexData))) {
MOZ_CRASH();
}
MutexData* data = static_cast<MutexData*>(mSharedBuffer->Memory());
if (!data) {
MOZ_CRASH();
@@ -66,12 +69,22 @@ CrossProcessMutex::CrossProcessMutex(const char*)
CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle aHandle)
: mMutex(nullptr), mCount(nullptr) {
mSharedBuffer = std::move(aHandle).MapWithHandle();
if (!mSharedBuffer) {
mSharedBuffer = new ipc::SharedMemory;
if (!mSharedBuffer->IsHandleValid(aHandle)) {
MOZ_CRASH();
}
MutexData* data = mSharedBuffer.DataAs<MutexData>();
if (!mSharedBuffer->SetHandle(std::move(aHandle),
ipc::SharedMemory::RightsReadWrite)) {
MOZ_CRASH();
}
if (!mSharedBuffer->Map(sizeof(MutexData))) {
MOZ_CRASH();
}
MutexData* data = static_cast<MutexData*>(mSharedBuffer->Memory());
if (!data) {
MOZ_CRASH();
@@ -112,14 +125,16 @@ void CrossProcessMutex::Unlock() {
}
CrossProcessMutexHandle CrossProcessMutex::CloneHandle() {
CrossProcessMutexHandle result = ipc::SharedMemory::NULLHandle();
if (mSharedBuffer) {
auto handle = mSharedBuffer.Handle().Clone();
if (!handle) {
result = mSharedBuffer->CloneHandle();
if (!result) {
MOZ_CRASH();
}
return handle;
}
return nullptr;
return result;
}
} // namespace mozilla

View File

@@ -16,7 +16,7 @@
#else
# include <pthread.h>
# include <semaphore.h>
# include "mozilla/ipc/SharedMemoryMapping.h"
# include "mozilla/ipc/SharedMemory.h"
# include "mozilla/Atomics.h"
#endif
@@ -41,7 +41,13 @@ typedef mozilla::UniqueFileHandle CrossProcessSemaphoreHandle;
#elif defined(XP_DARWIN)
typedef mozilla::UniqueMachSendRight CrossProcessSemaphoreHandle;
#else
typedef mozilla::ipc::MutableSharedMemoryHandle CrossProcessSemaphoreHandle;
typedef mozilla::ipc::SharedMemory::Handle CrossProcessSemaphoreHandle;
template <>
inline bool IsHandleValid<CrossProcessSemaphoreHandle>(
const CrossProcessSemaphoreHandle& handle) {
return !(handle == mozilla::ipc::SharedMemory::NULLHandle());
}
#endif
class CrossProcessSemaphore {
@@ -102,8 +108,7 @@ class CrossProcessSemaphore {
CrossProcessSemaphoreHandle mSemaphore;
#else
mozilla::ipc::MutableSharedMemoryHandle mHandle;
mozilla::ipc::SharedMemoryMapping mSharedBuffer;
RefPtr<mozilla::ipc::SharedMemory> mSharedBuffer;
sem_t* mSemaphore;
mozilla::Atomic<int32_t>* mRefCount;
#endif

View File

@@ -28,17 +28,16 @@ namespace mozilla {
/* static */
CrossProcessSemaphore* CrossProcessSemaphore::Create(const char*,
uint32_t aInitialValue) {
auto handle = ipc::shared_memory::Create(sizeof(SemaphoreData));
if (!handle) {
RefPtr<ipc::SharedMemory> sharedBuffer = new ipc::SharedMemory;
if (!sharedBuffer->Create(sizeof(SemaphoreData))) {
return nullptr;
}
auto mapping = handle.Map();
if (!mapping) {
if (!sharedBuffer->Map(sizeof(SemaphoreData))) {
return nullptr;
}
SemaphoreData* data = mapping.DataAs<SemaphoreData>();
SemaphoreData* data = static_cast<SemaphoreData*>(sharedBuffer->Memory());
if (!data) {
return nullptr;
@@ -49,8 +48,7 @@ CrossProcessSemaphore* CrossProcessSemaphore::Create(const char*,
}
CrossProcessSemaphore* sem = new CrossProcessSemaphore;
sem->mHandle = std::move(handle);
sem->mSharedBuffer = std::move(mapping);
sem->mSharedBuffer = sharedBuffer;
sem->mSemaphore = &data->mSemaphore;
sem->mRefCount = &data->mRefCount;
*sem->mRefCount = 1;
@@ -63,14 +61,24 @@ CrossProcessSemaphore* CrossProcessSemaphore::Create(const char*,
/* static */
CrossProcessSemaphore* CrossProcessSemaphore::Create(
CrossProcessSemaphoreHandle aHandle) {
auto mapping = aHandle.Map();
if (!mapping) {
RefPtr<ipc::SharedMemory> sharedBuffer = new ipc::SharedMemory;
if (!sharedBuffer->IsHandleValid(aHandle)) {
return nullptr;
}
aHandle = nullptr;
if (!sharedBuffer->SetHandle(std::move(aHandle),
ipc::SharedMemory::RightsReadWrite)) {
return nullptr;
}
SemaphoreData* data = mapping.DataAs<SemaphoreData>();
if (!sharedBuffer->Map(sizeof(SemaphoreData))) {
return nullptr;
}
sharedBuffer->CloseHandle();
SemaphoreData* data = static_cast<SemaphoreData*>(sharedBuffer->Memory());
if (!data) {
return nullptr;
@@ -87,7 +95,7 @@ CrossProcessSemaphore* CrossProcessSemaphore::Create(
}
CrossProcessSemaphore* sem = new CrossProcessSemaphore;
sem->mSharedBuffer = std::move(mapping);
sem->mSharedBuffer = sharedBuffer;
sem->mSemaphore = &data->mSemaphore;
sem->mRefCount = &data->mRefCount;
return sem;
@@ -139,16 +147,18 @@ void CrossProcessSemaphore::Signal() {
}
CrossProcessSemaphoreHandle CrossProcessSemaphore::CloneHandle() {
CrossProcessSemaphoreHandle result = ipc::SharedMemory::NULLHandle();
if (mSharedBuffer) {
auto handle = mHandle.Clone();
if (!handle) {
result = mSharedBuffer->CloneHandle();
if (!result) {
MOZ_CRASH();
}
return handle;
}
return nullptr;
return result;
}
void CrossProcessSemaphore::CloseHandle() { mHandle = nullptr; }
void CrossProcessSemaphore::CloseHandle() { mSharedBuffer->CloseHandle(); }
} // namespace mozilla

View File

@@ -71,10 +71,9 @@ static void DoNotifyOnUnlock(DataPipeAutoLock& aLock,
class DataPipeLink : public NodeController::PortObserver {
public:
DataPipeLink(bool aReceiverSide, std::shared_ptr<Mutex> aMutex,
ScopedPort aPort, MutableSharedMemoryHandle&& aShmemHandle,
const std::shared_ptr<SharedMemoryMapping> aShmem,
uint32_t aCapacity, nsresult aPeerStatus, uint32_t aOffset,
uint32_t aAvailable)
ScopedPort aPort, SharedMemory::Handle aShmemHandle,
SharedMemory* aShmem, uint32_t aCapacity, nsresult aPeerStatus,
uint32_t aOffset, uint32_t aAvailable)
: mMutex(std::move(aMutex)),
mPort(std::move(aPort)),
mShmemHandle(std::move(aShmemHandle)),
@@ -166,8 +165,8 @@ class DataPipeLink : public NodeController::PortObserver {
std::shared_ptr<Mutex> mMutex;
ScopedPort mPort MOZ_GUARDED_BY(*mMutex);
MutableSharedMemoryHandle mShmemHandle MOZ_GUARDED_BY(*mMutex);
const std::shared_ptr<SharedMemoryMapping> mShmem;
SharedMemory::Handle mShmemHandle MOZ_GUARDED_BY(*mMutex);
const RefPtr<SharedMemory> mShmem;
const uint32_t mCapacity;
const bool mReceiverSide;
@@ -246,10 +245,10 @@ DataPipeBase::DataPipeBase(bool aReceiverSide, nsresult aError)
mStatus(NS_SUCCEEDED(aError) ? NS_BASE_STREAM_CLOSED : aError) {}
DataPipeBase::DataPipeBase(bool aReceiverSide, ScopedPort aPort,
MutableSharedMemoryHandle&& aShmemHandle,
const std::shared_ptr<SharedMemoryMapping>& aShmem,
uint32_t aCapacity, nsresult aPeerStatus,
uint32_t aOffset, uint32_t aAvailable)
SharedMemory::Handle aShmemHandle,
SharedMemory* aShmem, uint32_t aCapacity,
nsresult aPeerStatus, uint32_t aOffset,
uint32_t aAvailable)
: mMutex(std::make_shared<Mutex>(aReceiverSide ? "DataPipeReceiver"
: "DataPipeSender")),
mStatus(NS_OK),
@@ -319,7 +318,7 @@ nsresult DataPipeBase::ProcessSegmentsInternal(
// Extract an iterator over the next contiguous region of the shared memory
// buffer which will be used .
char* start = link->mShmem->DataAs<char>() + link->mOffset;
char* start = static_cast<char*>(link->mShmem->Memory()) + link->mOffset;
char* iter = start;
char* end = start + std::min({aCount - *aProcessedCount, link->mAvailable,
link->mCapacity - link->mOffset});
@@ -481,17 +480,21 @@ bool DataPipeRead(IPC::MessageReader* aReader, RefPtr<T>* aResult) {
aReader->FatalError("failed to read DataPipe port");
return false;
}
MutableSharedMemoryHandle shmemHandle;
SharedMemory::Handle shmemHandle;
if (!ReadParam(aReader, &shmemHandle)) {
aReader->FatalError("failed to read DataPipe shmem");
return false;
}
if (!shmemHandle) {
aReader->FatalError("failed to create DataPipe shmem handle");
// Due to the awkward shared memory API provided by SharedMemory, we need to
// transfer ownership into the `shmem` here, then steal it back later in the
// function. Bug 1797039 tracks potential changes to the RawShmem API which
// could improve this situation.
RefPtr shmem = new SharedMemory();
if (!shmem->SetHandle(std::move(shmemHandle),
SharedMemory::RightsReadWrite)) {
aReader->FatalError("failed to create DataPipe shmem from handle");
return false;
}
uint32_t capacity = 0;
nsresult peerStatus = NS_OK;
uint32_t offset = 0;
@@ -505,14 +508,12 @@ bool DataPipeRead(IPC::MessageReader* aReader, RefPtr<T>* aResult) {
aReader->FatalError("received DataPipe state values are inconsistent");
return false;
}
auto mapping = std::make_shared<SharedMemoryMapping>(shmemHandle.Map());
if (!*mapping ||
mapping->Size() != shared_memory::PageAlignedSize(capacity)) {
if (!shmem->Map(SharedMemory::PageAlignedSize(capacity))) {
aReader->FatalError("failed to map DataPipe shared memory region");
return false;
}
*aResult = new T(std::move(port), std::move(shmemHandle), mapping, capacity,
*aResult = new T(std::move(port), shmem->TakeHandle(), shmem, capacity,
peerStatus, offset, available);
if (MOZ_LOG_TEST(gDataPipeLog, LogLevel::Debug)) {
DataPipeAutoLock lock(*(*aResult)->mMutex);
@@ -587,7 +588,7 @@ NS_IMETHODIMP DataPipeSender::AsyncWait(nsIOutputStreamCallback* aCallback,
nsIEventTarget* aTarget) {
AsyncWaitInternal(
aCallback ? NS_NewCancelableRunnableFunction(
"DataPipeSender::AsyncWait",
"DataPipeReceiver::AsyncWait",
[self = RefPtr{this}, callback = RefPtr{aCallback}] {
MOZ_LOG(gDataPipeLog, LogLevel::Debug,
("Calling OnOutputStreamReady(%p, %p)",
@@ -716,31 +717,27 @@ nsresult NewDataPipe(uint32_t aCapacity, DataPipeSender** aSender,
auto [senderPort, receiverPort] = controller->CreatePortPair();
// Create and allocate the shared memory region.
size_t alignedCapacity = shared_memory::PageAlignedSize(aCapacity);
auto handle = shared_memory::Create(alignedCapacity);
if (!handle) {
return NS_ERROR_OUT_OF_MEMORY;
}
auto mapping = std::make_shared<SharedMemoryMapping>(handle.Map());
if (!*mapping) {
auto shmem = MakeRefPtr<SharedMemory>();
size_t alignedCapacity = SharedMemory::PageAlignedSize(aCapacity);
if (!shmem->Create(alignedCapacity) || !shmem->Map(alignedCapacity)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// We'll first clone then take the handle from the region so that the sender &
// receiver each have a handle. This avoids the need to duplicate the handle
// when serializing, when errors are non-recoverable.
auto senderShmemHandle = handle.Clone();
auto receiverShmemHandle = std::move(handle);
SharedMemory::Handle senderShmemHandle = shmem->CloneHandle();
SharedMemory::Handle receiverShmemHandle = shmem->TakeHandle();
if (!senderShmemHandle || !receiverShmemHandle) {
return NS_ERROR_OUT_OF_MEMORY;
}
RefPtr sender =
new DataPipeSender(std::move(senderPort), std::move(senderShmemHandle),
mapping, aCapacity, NS_OK, 0, aCapacity);
shmem, aCapacity, NS_OK, 0, aCapacity);
RefPtr receiver = new DataPipeReceiver(std::move(receiverPort),
std::move(receiverShmemHandle),
mapping, aCapacity, NS_OK, 0, 0);
std::move(receiverShmemHandle), shmem,
aCapacity, NS_OK, 0, 0);
sender.forget(aSender);
receiver.forget(aReceiver);
return NS_OK;

View File

@@ -7,14 +7,12 @@
#ifndef mozilla_ipc_DataPipe_h
#define mozilla_ipc_DataPipe_h
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/ipc/NodeController.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsISupports.h"
#include <memory>
namespace mozilla {
namespace ipc {
@@ -32,8 +30,7 @@ class DataPipeBase {
protected:
explicit DataPipeBase(bool aReceiverSide, nsresult aError);
DataPipeBase(bool aReceiverSide, ScopedPort aPort,
MutableSharedMemoryHandle&& aShmemHandle,
const std::shared_ptr<SharedMemoryMapping>& aShmem,
SharedMemory::Handle aShmemHandle, SharedMemory* aShmem,
uint32_t aCapacity, nsresult aPeerStatus, uint32_t aOffset,
uint32_t aAvailable);
@@ -102,10 +99,9 @@ class DataPipeSender final : public nsIAsyncOutputStream,
explicit DataPipeSender(nsresult aError)
: data_pipe_detail::DataPipeBase(/* aReceiverSide */ false, aError) {}
DataPipeSender(ScopedPort aPort, MutableSharedMemoryHandle&& aShmemHandle,
const std::shared_ptr<SharedMemoryMapping>& aShmem,
uint32_t aCapacity, nsresult aPeerStatus, uint32_t aOffset,
uint32_t aAvailable)
DataPipeSender(ScopedPort aPort, SharedMemory::Handle aShmemHandle,
SharedMemory* aShmem, uint32_t aCapacity, nsresult aPeerStatus,
uint32_t aOffset, uint32_t aAvailable)
: data_pipe_detail::DataPipeBase(
/* aReceiverSide */ false, std::move(aPort),
std::move(aShmemHandle), aShmem, aCapacity, aPeerStatus, aOffset,
@@ -139,10 +135,9 @@ class DataPipeReceiver final : public nsIAsyncInputStream,
explicit DataPipeReceiver(nsresult aError)
: data_pipe_detail::DataPipeBase(/* aReceiverSide */ true, aError) {}
DataPipeReceiver(ScopedPort aPort, MutableSharedMemoryHandle&& aShmemHandle,
const std::shared_ptr<SharedMemoryMapping>& aShmem,
uint32_t aCapacity, nsresult aPeerStatus, uint32_t aOffset,
uint32_t aAvailable)
DataPipeReceiver(ScopedPort aPort, SharedMemory::Handle aShmemHandle,
SharedMemory* aShmem, uint32_t aCapacity,
nsresult aPeerStatus, uint32_t aOffset, uint32_t aAvailable)
: data_pipe_detail::DataPipeBase(
/* aReceiverSide */ true, std::move(aPort), std::move(aShmemHandle),
aShmem, aCapacity, aPeerStatus, aOffset, aAvailable) {}

View File

@@ -15,6 +15,7 @@
#include "chrome/common/process_watcher.h"
#ifdef XP_DARWIN
# include <mach/mach_traps.h>
# include "SharedMemory.h"
# include "base/rand_util.h"
# include "chrome/common/mach_ipc_mac.h"
# include "mozilla/StaticPrefs_media.h"

View File

@@ -29,16 +29,18 @@ void IdleSchedulerChild::Init(IdlePeriodState* aIdlePeriodState) {
mIdlePeriodState = aIdlePeriodState;
RefPtr<IdleSchedulerChild> scheduler = this;
auto resolve = [&](std::tuple<mozilla::Maybe<MutableSharedMemoryHandle>,
uint32_t>&& aResult) {
if (auto& handle = std::get<0>(aResult)) {
mActiveCounter = handle->Map();
mChildId = std::get<1>(aResult);
if (mChildId && mIdlePeriodState && mIdlePeriodState->IsActive()) {
SetActive();
}
}
};
auto resolve =
[&](std::tuple<mozilla::Maybe<SharedMemoryHandle>, uint32_t>&& aResult) {
if (std::get<0>(aResult)) {
mActiveCounter->SetHandle(std::move(*std::get<0>(aResult)),
SharedMemory::RightsReadWrite);
mActiveCounter->Map(sizeof(int32_t));
mChildId = std::get<1>(aResult);
if (mChildId && mIdlePeriodState && mIdlePeriodState->IsActive()) {
SetActive();
}
}
};
auto reject = [&](ResponseRejectReason) {};
SendInitForIdleUse(std::move(resolve), std::move(reject));
@@ -52,21 +54,23 @@ IPCResult IdleSchedulerChild::RecvIdleTime(uint64_t aId, TimeDuration aBudget) {
}
void IdleSchedulerChild::SetActive() {
if (mChildId && CanSend() && mActiveCounter) {
auto counters = mActiveCounter.DataAsSpan<Atomic<int32_t>>();
++counters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
++counters[mChildId];
if (mChildId && CanSend() && mActiveCounter->Memory()) {
++(static_cast<Atomic<int32_t>*>(
mActiveCounter->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
++(static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())[mChildId]);
}
}
bool IdleSchedulerChild::SetPaused() {
if (mChildId && CanSend() && mActiveCounter) {
auto counters = mActiveCounter.DataAsSpan<Atomic<int32_t>>();
--counters[mChildId];
if (mChildId && CanSend() && mActiveCounter->Memory()) {
--(static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())[mChildId]);
// The following expression reduces the global activity count and checks if
// it drops below the cpu counter limit.
return counters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]-- ==
counters[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
return (static_cast<Atomic<int32_t>*>(mActiveCounter->Memory())
[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER])-- ==
static_cast<Atomic<int32_t>*>(
mActiveCounter
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER];
}
return false;

View File

@@ -11,7 +11,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ipc/PIdleSchedulerChild.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
class nsIIdlePeriod;
@@ -58,7 +58,7 @@ class IdleSchedulerChild final : public PIdleSchedulerChild {
friend class BackgroundChildImpl;
// See IdleScheduleParent::sActiveChildCounter
SharedMemoryMapping mActiveCounter;
RefPtr<SharedMemory> mActiveCounter = MakeRefPtr<SharedMemory>();
IdlePeriodState* mIdlePeriodState = nullptr;

View File

@@ -9,10 +9,7 @@
#include "mozilla/Unused.h"
#include "mozilla/ipc/IdleSchedulerParent.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/NeverDestroyed.h"
#include "mozilla/Telemetry.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "nsSystemInfo.h"
#include "nsThreadUtils.h"
#include "nsITimer.h"
@@ -20,18 +17,8 @@
namespace mozilla::ipc {
// Shared memory for counting how many child processes are running
// tasks. This memory is shared across all the child processes.
// The [0] is used for counting all the processes and
// [childId] is for counting per process activity.
// This way the global activity can be checked in a fast way by just looking
// at [0] value.
// [1] is used for cpu count for child processes.
static SharedMemoryMappingWithHandle& sActiveChildCounter() {
static NeverDestroyed<SharedMemoryMappingWithHandle> mapping;
return *mapping;
}
MOZ_RUNINIT RefPtr<SharedMemory> IdleSchedulerParent::sActiveChildCounter =
nullptr;
std::bitset<NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT>
IdleSchedulerParent::sInUseChildCounters;
MOZ_RUNINIT LinkedList<IdleSchedulerParent>
@@ -121,9 +108,9 @@ void IdleSchedulerParent::CalculateNumIdleTasks() {
sMaxConcurrentGCs = std::clamp(sNumCPUs / sPrefConcurrentGCsCPUDivisor, 1u,
sPrefConcurrentGCsMax);
if (sActiveChildCounter()) {
sActiveChildCounter()
.DataAsSpan<Atomic<int32_t>>()[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
if (sActiveChildCounter && sActiveChildCounter->Memory()) {
static_cast<Atomic<int32_t>*>(
sActiveChildCounter->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
}
IdleSchedulerParent::Schedule(nullptr);
@@ -134,12 +121,14 @@ IdleSchedulerParent::~IdleSchedulerParent() {
// that is the case.
if (mChildId) {
sInUseChildCounters[mChildId] = false;
if (sActiveChildCounter()) {
auto counters = sActiveChildCounter().DataAsSpan<Atomic<int32_t>>();
if (counters[mChildId]) {
--counters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
counters[mChildId] = 0;
}
if (sActiveChildCounter && sActiveChildCounter->Memory() &&
static_cast<Atomic<int32_t>*>(
sActiveChildCounter->Memory())[mChildId]) {
--static_cast<Atomic<int32_t>*>(
sActiveChildCounter
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
static_cast<Atomic<int32_t>*>(sActiveChildCounter->Memory())[mChildId] =
0;
}
}
@@ -166,7 +155,7 @@ IdleSchedulerParent::~IdleSchedulerParent() {
sChildProcessesAlive--;
if (sChildProcessesAlive == 0) {
MOZ_ASSERT(sIdleAndGCRequests.isEmpty());
sActiveChildCounter() = nullptr;
sActiveChildCounter = nullptr;
if (sStarvationPreventer) {
sStarvationPreventer->Cancel();
@@ -188,22 +177,27 @@ IPCResult IdleSchedulerParent::RecvInitForIdleUse(
// Create a shared memory object which is shared across all the relevant
// processes.
if (!sActiveChildCounter()) {
if (!sActiveChildCounter) {
sActiveChildCounter = MakeRefPtr<SharedMemory>();
size_t shmemSize = NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT * sizeof(int32_t);
sActiveChildCounter() = shared_memory::Create(shmemSize).MapWithHandle();
if (sActiveChildCounter()) {
memset(sActiveChildCounter().Address(), 0, shmemSize);
if (sActiveChildCounter->Create(shmemSize) &&
sActiveChildCounter->Map(shmemSize)) {
memset(sActiveChildCounter->Memory(), 0, shmemSize);
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER] = true;
sInUseChildCounters[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] = true;
sActiveChildCounter().DataAsSpan<Atomic<int32_t>>()
[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
static_cast<Atomic<int32_t>*>(
sActiveChildCounter
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_CPU_COUNTER] =
static_cast<int32_t>(sMaxConcurrentIdleTasksInChildProcesses);
} else {
sActiveChildCounter() = nullptr;
sActiveChildCounter = nullptr;
}
}
MutableSharedMemoryHandle activeCounter =
sActiveChildCounter() ? sActiveChildCounter().Handle().Clone() : nullptr;
Maybe<SharedMemory::Handle> activeCounter;
if (SharedMemory::Handle handle =
sActiveChildCounter ? sActiveChildCounter->CloneHandle() : nullptr) {
activeCounter.emplace(std::move(handle));
}
uint32_t unusedId = 0;
for (uint32_t i = 0; i < NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT; ++i) {
@@ -217,9 +211,8 @@ IPCResult IdleSchedulerParent::RecvInitForIdleUse(
// If there wasn't an empty item, we'll fallback to 0.
mChildId = unusedId;
aResolve(
std::tuple<mozilla::Maybe<MutableSharedMemoryHandle>&&, const uint32_t&>(
Some(std::move(activeCounter)), mChildId));
aResolve(std::tuple<mozilla::Maybe<SharedMemory::Handle>&&, const uint32_t&>(
std::move(activeCounter), mChildId));
return IPC_OK();
}
@@ -325,9 +318,10 @@ IPCResult IdleSchedulerParent::RecvDoneGC() {
}
int32_t IdleSchedulerParent::ActiveCount() {
if (sActiveChildCounter()) {
return sActiveChildCounter().DataAsSpan<Atomic<int32_t>>()
[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER];
if (sActiveChildCounter) {
return (static_cast<Atomic<int32_t>*>(
sActiveChildCounter
->Memory())[NS_IDLE_SCHEDULER_INDEX_OF_ACTIVITY_COUNTER]);
}
return 0;
}

View File

@@ -13,7 +13,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ipc/PIdleSchedulerParent.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include <bitset>
#define NS_IDLE_SCHEDULER_COUNTER_ARRAY_LENGHT 1024
@@ -82,6 +82,14 @@ class IdleSchedulerParent final
bool IsDoingIdleTask() const { return !isInList() && mRequestedIdleBudget; }
bool IsNotDoingIdleTask() const { return !mRequestedIdleBudget; }
// Shared memory for counting how many child processes are running
// tasks. This memory is shared across all the child processes.
// The [0] is used for counting all the processes and
// [childId] is for counting per process activity.
// This way the global activity can be checked in a fast way by just looking
// at [0] value.
// [1] is used for cpu count for child processes.
static RefPtr<SharedMemory> sActiveChildCounter;
// 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
// sActiveChildCounter.

View File

@@ -5,7 +5,7 @@
include protocol PBackground;
using mozilla::TimeDuration from "mozilla/TimeStamp.h";
[MoveOnly] using mozilla::ipc::MutableSharedMemoryHandle from "mozilla/ipc/SharedMemoryHandle.h";
[MoveOnly] using mozilla::ipc::SharedMemoryHandle from "mozilla/ipc/SharedMemory.h";
namespace mozilla {
namespace ipc {
@@ -39,7 +39,7 @@ child:
async IdleTime(uint64_t id, TimeDuration budget);
parent:
async InitForIdleUse() returns (MutableSharedMemoryHandle? state, uint32_t childId);
async InitForIdleUse() returns (SharedMemoryHandle? state, uint32_t childId);
async RequestIdleTime(uint64_t id, TimeDuration budget);
async IdleTimeUsed(uint64_t id);

View File

@@ -55,18 +55,22 @@ void ProcessChild::AddPlatformBuildID(geckoargs::ChildProcessArgs& aExtraArgs) {
/* static */
bool ProcessChild::InitPrefs(int aArgc, char* aArgv[]) {
Maybe<ReadOnlySharedMemoryHandle> prefsHandle =
Maybe<SharedMemoryHandle> prefsHandle =
geckoargs::sPrefsHandle.Get(aArgc, aArgv);
Maybe<ReadOnlySharedMemoryHandle> prefMapHandle =
Maybe<SharedMemoryHandle> prefMapHandle =
geckoargs::sPrefMapHandle.Get(aArgc, aArgv);
Maybe<uint64_t> prefsLen = geckoargs::sPrefsLen.Get(aArgc, aArgv);
Maybe<uint64_t> prefMapSize = geckoargs::sPrefMapSize.Get(aArgc, aArgv);
if (prefsHandle.isNothing() || prefMapHandle.isNothing()) {
if (prefsLen.isNothing() || prefMapSize.isNothing() ||
prefsHandle.isNothing() || prefMapHandle.isNothing()) {
return false;
}
SharedPreferenceDeserializer deserializer;
return deserializer.DeserializeFromSharedMemory(std::move(*prefsHandle),
std::move(*prefMapHandle));
std::move(*prefMapHandle),
*prefsLen, *prefMapSize);
}
#ifdef ENABLE_TESTS

View File

@@ -12,8 +12,7 @@
#include "mozilla/GeckoArgs.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/Maybe.h"
#include "mozilla/Preferences.h"
#include "mozilla/RefPtr.h"
@@ -37,21 +36,22 @@ class SharedPreferenceSerializer final {
bool SerializeToSharedMemory(const GeckoProcessType aDestinationProcessType,
const nsACString& aDestinationRemoteType);
const ReadOnlySharedMemoryHandle& GetPrefsHandle() const {
return mPrefsHandle;
}
size_t GetPrefMapSize() const { return mPrefMapSize; }
size_t GetPrefsLength() const { return mPrefsLength; }
const ReadOnlySharedMemoryHandle& GetPrefMapHandle() const {
return mPrefMapHandle;
}
const SharedMemoryHandle& GetPrefsHandle() const { return mPrefsHandle; }
const SharedMemoryHandle& GetPrefMapHandle() const { return mPrefMapHandle; }
void AddSharedPrefCmdLineArgs(GeckoChildProcessHost& procHost,
geckoargs::ChildProcessArgs& aExtraOpts) const;
private:
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceSerializer);
ReadOnlySharedMemoryHandle mPrefMapHandle;
ReadOnlySharedMemoryHandle mPrefsHandle;
size_t mPrefMapSize;
size_t mPrefsLength;
SharedMemoryHandle mPrefMapHandle;
SharedMemoryHandle mPrefsHandle;
};
class SharedPreferenceDeserializer final {
@@ -59,13 +59,18 @@ class SharedPreferenceDeserializer final {
SharedPreferenceDeserializer();
~SharedPreferenceDeserializer();
bool DeserializeFromSharedMemory(ReadOnlySharedMemoryHandle&& aPrefsHandle,
ReadOnlySharedMemoryHandle&& aPrefMapHandle);
bool DeserializeFromSharedMemory(SharedMemoryHandle aPrefsHandle,
SharedMemoryHandle aPrefMapHandle,
uint64_t aPrefsLen, uint64_t aPrefMapSize);
const SharedMemoryHandle& GetPrefMapHandle() const;
private:
DISALLOW_COPY_AND_ASSIGN(SharedPreferenceDeserializer);
ReadOnlySharedMemoryHandle mPrefMapHandle;
ReadOnlySharedMemoryMapping mShmem;
Maybe<SharedMemoryHandle> mPrefMapHandle;
Maybe<size_t> mPrefsLen;
Maybe<size_t> mPrefMapSize;
RefPtr<SharedMemory> mShmem = MakeRefPtr<SharedMemory>();
};
// Generate command line argument to spawn a child process. If the shared memory
@@ -75,7 +80,7 @@ void ExportSharedJSInit(GeckoChildProcessHost& procHost,
// Initialize the content used by the JS engine during the initialization of a
// JS::Runtime.
bool ImportSharedJSInit(ReadOnlySharedMemoryHandle&& aJsInitHandle);
bool ImportSharedJSInit(SharedMemoryHandle aJsInitHandle, uint64_t aJsInitLen);
} // namespace ipc
} // namespace mozilla

View File

@@ -19,7 +19,8 @@
namespace mozilla {
namespace ipc {
SharedPreferenceSerializer::SharedPreferenceSerializer() {
SharedPreferenceSerializer::SharedPreferenceSerializer()
: mPrefMapSize(0), mPrefsLength(0) {
MOZ_COUNT_CTOR(SharedPreferenceSerializer);
}
@@ -29,7 +30,9 @@ SharedPreferenceSerializer::~SharedPreferenceSerializer() {
SharedPreferenceSerializer::SharedPreferenceSerializer(
SharedPreferenceSerializer&& aOther)
: mPrefMapHandle(std::move(aOther.mPrefMapHandle)),
: mPrefMapSize(aOther.mPrefMapSize),
mPrefsLength(aOther.mPrefsLength),
mPrefMapHandle(std::move(aOther.mPrefMapHandle)),
mPrefsHandle(std::move(aOther.mPrefsHandle)) {
MOZ_COUNT_CTOR(SharedPreferenceSerializer);
}
@@ -37,7 +40,7 @@ SharedPreferenceSerializer::SharedPreferenceSerializer(
bool SharedPreferenceSerializer::SerializeToSharedMemory(
const GeckoProcessType aDestinationProcessType,
const nsACString& aDestinationRemoteType) {
mPrefMapHandle = Preferences::EnsureSnapshot();
mPrefMapHandle = Preferences::EnsureSnapshot(&mPrefMapSize);
bool destIsWebContent =
aDestinationProcessType == GeckoProcessType_Content &&
@@ -47,38 +50,40 @@ bool SharedPreferenceSerializer::SerializeToSharedMemory(
// Serialize the early prefs.
nsAutoCStringN<1024> prefs;
Preferences::SerializePreferences(prefs, destIsWebContent);
auto prefsLength = prefs.Length();
mPrefsLength = prefs.Length();
RefPtr<SharedMemory> shm = MakeRefPtr<SharedMemory>();
// Set up the shared memory.
auto handle = shared_memory::Create(prefsLength);
if (!handle) {
if (!shm->Create(prefs.Length())) {
NS_ERROR("failed to create shared memory in the parent");
return false;
}
auto mapping = handle.Map();
if (!mapping) {
if (!shm->Map(prefs.Length())) {
NS_ERROR("failed to map shared memory in the parent");
return false;
}
// Copy the serialized prefs into the shared memory.
memcpy(mapping.DataAs<char>(), prefs.get(), prefsLength);
memcpy(static_cast<char*>(shm->Memory()), prefs.get(), mPrefsLength);
mPrefsHandle = std::move(handle).ToReadOnly();
mPrefsHandle = shm->TakeHandleAndUnmap();
return true;
}
void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
mozilla::ipc::GeckoChildProcessHost& procHost,
geckoargs::ChildProcessArgs& aExtraOpts) const {
auto prefsHandle = GetPrefsHandle().Clone();
MOZ_RELEASE_ASSERT(prefsHandle, "failed to clone prefs handle");
auto prefMapHandle = GetPrefMapHandle().Clone();
MOZ_RELEASE_ASSERT(prefMapHandle, "failed to clone pref map handle");
SharedMemoryHandle prefsHandle = SharedMemory::CloneHandle(GetPrefsHandle());
MOZ_RELEASE_ASSERT(prefsHandle, "failed to duplicate prefs handle");
SharedMemoryHandle prefMapHandle =
SharedMemory::CloneHandle(GetPrefMapHandle());
MOZ_RELEASE_ASSERT(prefMapHandle, "failed to duplicate pref map handle");
// Pass the handles via command line flags.
// Pass the handles and lengths via command line flags.
geckoargs::sPrefsHandle.Put(std::move(prefsHandle), aExtraOpts);
geckoargs::sPrefsLen.Put((uintptr_t)(GetPrefsLength()), aExtraOpts);
geckoargs::sPrefMapHandle.Put(std::move(prefMapHandle), aExtraOpts);
geckoargs::sPrefMapSize.Put((uintptr_t)(GetPrefMapSize()), aExtraOpts);
}
SharedPreferenceDeserializer::SharedPreferenceDeserializer() {
@@ -90,56 +95,79 @@ SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
}
bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
ReadOnlySharedMemoryHandle&& aPrefsHandle,
ReadOnlySharedMemoryHandle&& aPrefMapHandle) {
if (!aPrefsHandle || !aPrefMapHandle) {
SharedMemoryHandle aPrefsHandle, SharedMemoryHandle aPrefMapHandle,
uint64_t aPrefsLen, uint64_t aPrefMapSize) {
if (!aPrefsHandle || !aPrefMapHandle || !aPrefsLen || !aPrefMapSize) {
return false;
}
mPrefMapHandle = std::move(aPrefMapHandle);
mPrefMapHandle.emplace(std::move(aPrefMapHandle));
mPrefsLen = Some((uintptr_t)(aPrefsLen));
mPrefMapSize = Some((uintptr_t)(aPrefMapSize));
// Init the shared-memory base preference mapping first, so that only changed
// preferences wind up in heap memory.
Preferences::InitSnapshot(mPrefMapHandle);
Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
// Set up early prefs from the shared memory.
mShmem = aPrefsHandle.Map();
if (!mShmem) {
if (!mShmem->SetHandle(std::move(aPrefsHandle),
SharedMemory::RightsReadOnly)) {
NS_ERROR("failed to open shared memory in the child");
return false;
}
if (!mShmem->Map(*mPrefsLen)) {
NS_ERROR("failed to map shared memory in the child");
return false;
}
Preferences::DeserializePreferences(mShmem.DataAs<char>(), mShmem.Size());
Preferences::DeserializePreferences(static_cast<char*>(mShmem->Memory()),
*mPrefsLen);
return true;
}
const SharedMemoryHandle& SharedPreferenceDeserializer::GetPrefMapHandle()
const {
MOZ_ASSERT(mPrefMapHandle.isSome());
return mPrefMapHandle.ref();
}
void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
geckoargs::ChildProcessArgs& aExtraOpts) {
auto& shmem = xpc::SelfHostedShmem::GetSingleton();
auto handle = shmem.Handle().Clone();
SharedMemoryHandle handle = SharedMemory::CloneHandle(shmem.Handle());
size_t len = shmem.Content().Length();
// If the file is not found or the content is empty, then we would start the
// content process without this optimization.
if (!handle) {
if (!SharedMemory::IsHandleValid(handle) || !len) {
NS_ERROR("Can't use SelfHosted shared memory handle.");
return;
}
// command line: -jsInitHandle handle
// command line: -jsInitHandle handle -jsInitLen length
geckoargs::sJsInitHandle.Put(std::move(handle), aExtraOpts);
geckoargs::sJsInitLen.Put((uintptr_t)(len), aExtraOpts);
}
bool ImportSharedJSInit(ReadOnlySharedMemoryHandle&& aJsInitHandle) {
bool ImportSharedJSInit(SharedMemoryHandle aJsInitHandle, uint64_t aJsInitLen) {
// This is an optimization, and as such we can safely recover if the command
// line argument are not provided.
if (!aJsInitHandle) {
if (!aJsInitLen || !aJsInitHandle) {
return true;
}
size_t len = (uintptr_t)(aJsInitLen);
if (!len) {
return false;
}
// Initialize the shared memory with the file handle and size of the content
// of the self-hosted Xdr.
auto& shmem = xpc::SelfHostedShmem::GetSingleton();
if (!shmem.InitFromChild(std::move(aJsInitHandle))) {
if (!shmem.InitFromChild(std::move(aJsInitHandle), len)) {
NS_ERROR("failed to open shared memory in the child");
return false;
}

View File

@@ -339,13 +339,14 @@ IProtocol::~IProtocol() {
// almost directly do.
IProtocol* IProtocol::Lookup(int32_t aId) { return mToplevel->Lookup(aId); }
Shmem IProtocol::CreateSharedMemory(size_t aSize, bool aUnsafe) {
return mToplevel->CreateSharedMemory(aSize, aUnsafe);
Shmem::SharedMemory* IProtocol::CreateSharedMemory(size_t aSize, bool aUnsafe,
int32_t* aId) {
return mToplevel->CreateSharedMemory(aSize, aUnsafe, aId);
}
Shmem::Segment* IProtocol::LookupSharedMemory(int32_t aId) {
Shmem::SharedMemory* IProtocol::LookupSharedMemory(int32_t aId) {
return mToplevel->LookupSharedMemory(aId);
}
bool IProtocol::IsTrackingSharedMemory(const Shmem::Segment* aSegment) {
bool IProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* aSegment) {
return mToplevel->IsTrackingSharedMemory(aSegment);
}
bool IProtocol::DestroySharedMemory(Shmem& aShmem) {
@@ -419,8 +420,14 @@ bool IProtocol::AllocShmem(size_t aSize, Shmem* aOutMem) {
return false;
}
*aOutMem = CreateSharedMemory(aSize, false);
return aOutMem->IsReadable();
Shmem::id_t id;
Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, false, &id));
if (!rawmem) {
return false;
}
*aOutMem = Shmem(rawmem, id, aSize, false);
return true;
}
bool IProtocol::AllocUnsafeShmem(size_t aSize, Shmem* aOutMem) {
@@ -430,8 +437,14 @@ bool IProtocol::AllocUnsafeShmem(size_t aSize, Shmem* aOutMem) {
return false;
}
*aOutMem = CreateSharedMemory(aSize, true);
return aOutMem->IsReadable();
Shmem::id_t id;
Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, true, &id));
if (!rawmem) {
return false;
}
*aOutMem = Shmem(rawmem, id, aSize, true);
return true;
}
bool IProtocol::DeallocShmem(Shmem& aMem) {
@@ -746,30 +759,35 @@ IProtocol* IToplevelProtocol::Lookup(int32_t aId) {
return nullptr;
}
Shmem IToplevelProtocol::CreateSharedMemory(size_t aSize, bool aUnsafe) {
auto shmemBuilder = Shmem::Builder(aSize);
if (!shmemBuilder) {
return {};
Shmem::SharedMemory* IToplevelProtocol::CreateSharedMemory(size_t aSize,
bool aUnsafe,
Shmem::id_t* aId) {
RefPtr<Shmem::SharedMemory> segment(Shmem::Alloc(aSize));
if (!segment) {
return nullptr;
}
auto [createdMessage, shmem] =
shmemBuilder.Build(NextId(), aUnsafe, MSG_ROUTING_CONTROL);
if (!createdMessage) {
return {};
}
Unused << GetIPCChannel()->Send(std::move(createdMessage));
int32_t id = NextId();
Shmem shmem(segment.get(), id, aSize, aUnsafe);
MOZ_ASSERT(!mShmemMap.Contains(shmem.Id()),
"Don't insert with an existing ID");
mShmemMap.InsertOrUpdate(shmem.Id(), shmem.GetSegment());
return shmem;
UniquePtr<Message> descriptor = shmem.MkCreatedMessage(MSG_ROUTING_CONTROL);
if (!descriptor) {
return nullptr;
}
Unused << GetIPCChannel()->Send(std::move(descriptor));
*aId = shmem.Id();
Shmem::SharedMemory* rawSegment = segment.get();
MOZ_ASSERT(!mShmemMap.Contains(*aId), "Don't insert with an existing ID");
mShmemMap.InsertOrUpdate(*aId, std::move(segment));
return rawSegment;
}
Shmem::Segment* IToplevelProtocol::LookupSharedMemory(Shmem::id_t aId) {
Shmem::SharedMemory* IToplevelProtocol::LookupSharedMemory(Shmem::id_t aId) {
auto entry = mShmemMap.Lookup(aId);
return entry ? entry.Data().get() : nullptr;
}
bool IToplevelProtocol::IsTrackingSharedMemory(const Shmem::Segment* segment) {
bool IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* segment) {
for (const auto& shmem : mShmemMap.Values()) {
if (segment == shmem) {
return true;
@@ -780,7 +798,8 @@ bool IToplevelProtocol::IsTrackingSharedMemory(const Shmem::Segment* segment) {
bool IToplevelProtocol::DestroySharedMemory(Shmem& shmem) {
Shmem::id_t aId = shmem.Id();
if (!LookupSharedMemory(aId)) {
Shmem::SharedMemory* segment = LookupSharedMemory(aId);
if (!segment) {
return false;
}
@@ -802,12 +821,12 @@ void IToplevelProtocol::DeallocShmems() { mShmemMap.Clear(); }
bool IToplevelProtocol::ShmemCreated(const Message& aMsg) {
Shmem::id_t id;
RefPtr<Shmem::Segment> segment(Shmem::OpenExisting(aMsg, &id, true));
if (!segment) {
RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(aMsg, &id, true));
if (!rawmem) {
return false;
}
MOZ_ASSERT(!mShmemMap.Contains(id), "Don't insert with an existing ID");
mShmemMap.InsertOrUpdate(id, std::move(segment));
mShmemMap.InsertOrUpdate(id, std::move(rawmem));
return true;
}

View File

@@ -26,6 +26,7 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/ipc/MessageLink.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/ipc/Shmem.h"
#include "nsPrintfCString.h"
#include "nsTHashMap.h"
@@ -196,9 +197,10 @@ class IProtocol : public HasResultCodes {
// Lookup() is forwarded directly to the toplevel protocol.
IProtocol* Lookup(int32_t aId);
Shmem CreateSharedMemory(size_t aSize, bool aUnsafe);
Shmem::Segment* LookupSharedMemory(int32_t aId);
bool IsTrackingSharedMemory(const Shmem::Segment* aSegment);
Shmem::SharedMemory* CreateSharedMemory(size_t aSize, bool aUnsafe,
int32_t* aId);
Shmem::SharedMemory* LookupSharedMemory(int32_t aId);
bool IsTrackingSharedMemory(Shmem::SharedMemory* aSegment);
bool DestroySharedMemory(Shmem& aShmem);
MessageChannel* GetIPCChannel();
@@ -446,9 +448,10 @@ class IToplevelProtocol : public IRefCountedProtocol {
// Shadows the method on IProtocol, which will forward to the top.
IProtocol* Lookup(int32_t aId);
Shmem CreateSharedMemory(size_t aSize, bool aUnsafe);
Shmem::Segment* LookupSharedMemory(int32_t aId);
bool IsTrackingSharedMemory(const Shmem::Segment* aSegment);
Shmem::SharedMemory* CreateSharedMemory(size_t aSize, bool aUnsafe,
int32_t* aId);
Shmem::SharedMemory* LookupSharedMemory(int32_t aId);
bool IsTrackingSharedMemory(Shmem::SharedMemory* aSegment);
bool DestroySharedMemory(Shmem& aShmem);
MessageChannel* GetIPCChannel() { return &mChannel; }
@@ -558,7 +561,7 @@ class IToplevelProtocol : public IRefCountedProtocol {
// Used to be on mState
int32_t mLastLocalId;
IDMap<RefPtr<ActorLifecycleProxy>> mActorMap;
IDMap<RefPtr<Shmem::Segment>> mShmemMap;
IDMap<RefPtr<Shmem::SharedMemory>> mShmemMap;
MessageChannel mChannel;
};

108
ipc/glue/RawShmem.cpp Normal file
View File

@@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "RawShmem.h"
#include "mozilla/ipc/ProtocolUtils.h"
namespace mozilla::ipc {
UnsafeSharedMemoryHandle::UnsafeSharedMemoryHandle()
: mHandle(ipc::SharedMemory::NULLHandle()), mSize(0) {}
UnsafeSharedMemoryHandle::UnsafeSharedMemoryHandle(
UnsafeSharedMemoryHandle&& aOther) noexcept
: mHandle(std::move(aOther.mHandle)), mSize(aOther.mSize) {
aOther.mHandle = ipc::SharedMemory::NULLHandle();
aOther.mSize = 0;
}
UnsafeSharedMemoryHandle& UnsafeSharedMemoryHandle::operator=(
UnsafeSharedMemoryHandle&& aOther) noexcept {
if (this == &aOther) {
return *this;
}
mHandle = std::move(aOther.mHandle);
mSize = aOther.mSize;
aOther.mHandle = ipc::SharedMemory::NULLHandle();
aOther.mSize = 0;
return *this;
}
Maybe<std::pair<UnsafeSharedMemoryHandle, WritableSharedMemoryMapping>>
UnsafeSharedMemoryHandle::CreateAndMap(size_t aSize) {
if (aSize == 0) {
return Some(std::make_pair(UnsafeSharedMemoryHandle(),
WritableSharedMemoryMapping()));
}
RefPtr<ipc::SharedMemory> shm = MakeAndAddRef<ipc::SharedMemory>();
if (NS_WARN_IF(!shm->Create(aSize)) || NS_WARN_IF(!shm->Map(aSize))) {
return Nothing();
}
auto handle = shm->TakeHandle();
auto size = shm->Size();
return Some(std::make_pair(UnsafeSharedMemoryHandle(std::move(handle), size),
WritableSharedMemoryMapping(std::move(shm))));
}
WritableSharedMemoryMapping::WritableSharedMemoryMapping(
RefPtr<ipc::SharedMemory>&& aRef)
: mRef(aRef) {}
Maybe<WritableSharedMemoryMapping> WritableSharedMemoryMapping::Open(
UnsafeSharedMemoryHandle aHandle) {
if (aHandle.mSize == 0) {
return Some(WritableSharedMemoryMapping(nullptr));
}
RefPtr<ipc::SharedMemory> shm = MakeAndAddRef<ipc::SharedMemory>();
if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle.mHandle),
ipc::SharedMemory::RightsReadWrite)) ||
NS_WARN_IF(!shm->Map(aHandle.mSize))) {
return Nothing();
}
shm->CloseHandle();
return Some(WritableSharedMemoryMapping(std::move(shm)));
}
size_t WritableSharedMemoryMapping::Size() const {
if (!mRef) {
return 0;
}
return mRef->Size();
}
Span<uint8_t> WritableSharedMemoryMapping::Bytes() {
if (!mRef) {
return Span<uint8_t>();
}
uint8_t* mem = static_cast<uint8_t*>(mRef->Memory());
return Span(mem, mRef->Size());
}
} // namespace mozilla::ipc
namespace IPC {
auto ParamTraits<mozilla::ipc::UnsafeSharedMemoryHandle>::Write(
IPC::MessageWriter* aWriter, paramType&& aVar) -> void {
IPC::WriteParam(aWriter, std::move(aVar.mHandle));
IPC::WriteParam(aWriter, aVar.mSize);
}
auto ParamTraits<mozilla::ipc::UnsafeSharedMemoryHandle>::Read(
IPC::MessageReader* aReader, paramType* aVar) -> bool {
return IPC::ReadParam(aReader, &aVar->mHandle) &&
IPC::ReadParam(aReader, &aVar->mSize);
}
} // namespace IPC

114
ipc/glue/RawShmem.h Normal file
View File

@@ -0,0 +1,114 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_RAWSHMEM_H_
#define MOZILLA_IPC_RAWSHMEM_H_
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/ipc/SharedMemory.h"
#include "mozilla/Span.h"
#include <utility>
namespace mozilla::ipc {
class WritableSharedMemoryMapping;
/// A handle to shared memory.
///
/// See the doc comment for `WritableSharedMemoryMapping` below.
class UnsafeSharedMemoryHandle {
friend class WritableSharedMemoryMapping;
friend struct IPC::ParamTraits<UnsafeSharedMemoryHandle>;
public:
UnsafeSharedMemoryHandle();
UnsafeSharedMemoryHandle(UnsafeSharedMemoryHandle&& aOther) noexcept;
UnsafeSharedMemoryHandle& operator=(
UnsafeSharedMemoryHandle&& aOther) noexcept;
/// Attempts to allocate a shmem.
///
/// Returns `Nothing()` if allocation fails.
/// If `aSize` is zero, a valid empty WritableSharedMemoryMapping is returned.
static Maybe<std::pair<UnsafeSharedMemoryHandle, WritableSharedMemoryMapping>>
CreateAndMap(size_t aSize);
private:
UnsafeSharedMemoryHandle(SharedMemory::Handle&& aHandle, uint64_t aSize)
: mHandle(std::move(aHandle)), mSize(aSize) {}
SharedMemory::Handle mHandle;
uint64_t mSize;
};
/// A Shared memory buffer mapping.
///
/// Unlike `ipc::Shmem`, the underlying shared memory buffer on each side of
/// the process boundary is only deallocated with there respective
/// `WritableSharedMemoryMapping`.
///
/// ## Usage
///
/// Typical usage goes as follows:
/// - Allocate the memory using `UnsafeSharedMemoryHandle::Create`, returning a
/// handle and a mapping.
/// - Send the handle to the other process using an IPDL message.
/// - On the other process, map the shared memory by creating
/// WritableSharedMemoryMapping via `WritableSharedMemoryMapping::Open` and
/// the received handle.
///
/// Do not send the shared memory handle again, it is only intended to establish
/// the mapping on each side during initialization. The user of this class is
/// responsible for managing the lifetime of the buffers on each side, as well
/// as their identity, by for example storing them in hash map and referring to
/// them via IDs in IPDL message if need be.
///
/// ## Empty shmems
///
/// An empty WritableSharedMemoryMapping is one that was created with size zero.
/// It is analogous to a null RefPtr. It can be used like a non-empty shmem,
/// including sending the handle and openning it on another process (resulting
/// in an empty mapping on the other side).
class WritableSharedMemoryMapping {
friend class UnsafeSharedMemoryHandle;
public:
WritableSharedMemoryMapping() = default;
WritableSharedMemoryMapping(WritableSharedMemoryMapping&& aMoved) = default;
WritableSharedMemoryMapping& operator=(WritableSharedMemoryMapping&& aMoved) =
default;
/// Open the shmem and immediately close the handle.
static Maybe<WritableSharedMemoryMapping> Open(
UnsafeSharedMemoryHandle aHandle);
// Returns the size in bytes.
size_t Size() const;
// Returns the shared memory as byte range.
Span<uint8_t> Bytes();
private:
explicit WritableSharedMemoryMapping(
RefPtr<mozilla::ipc::SharedMemory>&& aRef);
RefPtr<mozilla::ipc::SharedMemory> mRef;
};
} // namespace mozilla::ipc
namespace IPC {
template <>
struct ParamTraits<mozilla::ipc::UnsafeSharedMemoryHandle> {
typedef mozilla::ipc::UnsafeSharedMemoryHandle paramType;
static void Write(IPC::MessageWriter* aWriter, paramType&& aVar);
static bool Read(IPC::MessageReader* aReader, paramType* aVar);
};
} // namespace IPC
#endif

211
ipc/glue/SharedMemory.cpp Normal file
View File

@@ -0,0 +1,211 @@
/* -*- 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 <utility>
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/Atomics.h"
#include "nsIMemoryReporter.h"
#ifdef FUZZING
# include "mozilla/ipc/SharedMemoryFuzzer.h"
#endif
namespace mozilla::ipc {
static Atomic<size_t> gShmemAllocated;
static Atomic<size_t> gShmemMapped;
class ShmemReporter final : public nsIMemoryReporter {
~ShmemReporter() = default;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
bool aAnonymize) override {
MOZ_COLLECT_REPORT(
"shmem-allocated", KIND_OTHER, UNITS_BYTES, gShmemAllocated,
"Memory shared with other processes that is accessible (but not "
"necessarily mapped).");
MOZ_COLLECT_REPORT(
"shmem-mapped", KIND_OTHER, UNITS_BYTES, gShmemMapped,
"Memory shared with other processes that is mapped into the address "
"space.");
return NS_OK;
}
};
NS_IMPL_ISUPPORTS(ShmemReporter, nsIMemoryReporter)
SharedMemory::SharedMemory() : mAllocSize(0), mMappedSize(0) {
static Atomic<bool> registered;
if (registered.compareExchange(false, true)) {
RegisterStrongMemoryReporter(new ShmemReporter());
}
}
SharedMemory::~SharedMemory() {
Unmap();
CloseHandle();
ResetImpl();
MOZ_ASSERT(gShmemAllocated >= mAllocSize,
"Can't destroy more than allocated");
gShmemAllocated -= mAllocSize;
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) {
Handle handle = CloneHandle(mHandle);
if (!handle) {
return false;
}
IPC::WriteParam(aWriter, std::move(handle));
return true;
}
bool SharedMemory::ReadHandle(IPC::MessageReader* aReader) {
Handle handle;
return IPC::ReadParam(aReader, &handle) && IsHandleValid(handle) &&
SetHandle(std::move(handle), RightsReadWrite);
}
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());
if (!memStart) MOZ_CRASH("SharedMemory region points at NULL!");
char* memEnd = memStart + Size();
char* protStart = aAddr;
if (!protStart) MOZ_CRASH("trying to Protect() a NULL region!");
char* protEnd = protStart + aSize;
if (!(memStart <= protStart && protEnd <= memEnd)) {
MOZ_CRASH("attempt to Protect() a region outside this SharedMemory");
}
// checks alignment etc.
SystemProtect(aAddr, aSize, aRights);
}
size_t SharedMemory::PageAlignedSize(size_t aSize) {
size_t pageSize = SystemPageSize();
size_t nPagesNeeded = size_t(ceil(double(aSize) / double(pageSize)));
return pageSize * nPagesNeeded;
}
} // namespace mozilla::ipc

190
ipc/glue/SharedMemory.h Normal file
View File

@@ -0,0 +1,190 @@
/* -*- 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). */
#ifndef mozilla_ipc_SharedMemory_h
#define mozilla_ipc_SharedMemory_h
#include <cstddef>
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
#if !(defined(XP_DARWIN) || defined(XP_WIN))
# include <string>
#endif
namespace IPC {
class MessageWriter;
class MessageReader;
} // namespace IPC
namespace {
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
} // namespace
namespace mozilla::ipc {
// Rust Bindgen code doesn't actually use these types, but `UniqueFileHandle`
// 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();
/// # Provided methods
public:
using Handle = SharedMemoryHandle;
enum OpenRights {
RightsReadOnly = RightsRead,
RightsReadWrite = RightsRead | RightsWrite,
};
SharedMemory();
// bug 1168843, compositor thread may create shared memory instances that are
// destroyed by main thread on shutdown, so this must use thread-safe RC to
// avoid hitting assertion
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)
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(); }
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 ReadHandle(IPC::MessageReader* aReader);
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);
[[nodiscard]] static bool SystemProtectFallible(char* aAddr, size_t aSize,
int aRights);
static Handle CloneHandle(const Handle& aHandle);
static size_t SystemPageSize();
static void* FindFreeAddressSpace(size_t size);
/// Private methods which should be defined as part of each implementation.
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;
}
};
#ifndef RUST_BINDGEN
using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;
#else
using UniqueMapping = void*;
#endif
// The held handle, if any.
Handle mHandle = NULLHandle();
// The size of the shmem region requested in Create(), if
// successful. SharedMemory instances that are opened from a
// foreign handle have an alloc size of 0, even though they have
// access to the alloc-size information.
size_t mAllocSize;
// The memory mapping, if any.
UniqueMapping mMemory;
// The size of the region mapped in Map(), if successful. All
// SharedMemorys that are mapped have a non-zero mapped size.
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
#endif // ifndef mozilla_ipc_SharedMemory_h

View File

@@ -4,8 +4,6 @@
* 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/MathAlgorithms.h"
#include "nsDebug.h"
#include "SharedMemoryCursor.h"
namespace mozilla::ipc::shared_memory {
@@ -29,7 +27,7 @@ void Cursor::Seek(uint64_t aOffset) {
}
}
MutableHandle Cursor::TakeHandle() {
Handle Cursor::TakeHandle() {
mMapping = nullptr;
return std::move(mHandle);
}
@@ -64,7 +62,7 @@ bool Cursor::Consume(void* aBuffer, size_t aCount, bool aWriteToShmem) {
size_t mappingRemaining = mMapping.Size() - mappingOffset;
size_t toCopy = std::min<size_t>(mappingRemaining, aCount - consumed);
void* shmemPtr = mMapping.DataAs<char>() + mappingOffset;
void* shmemPtr = static_cast<char*>(mMapping.Data()) + mappingOffset;
void* bufferPtr = static_cast<char*>(aBuffer) + consumed;
if (aWriteToShmem) {
memcpy(shmemPtr, bufferPtr, toCopy);

View File

@@ -30,7 +30,7 @@ class Cursor {
// Construct a new Cursor which can be used to read from or write to the
// shared memory region indicated by aHandle.
explicit Cursor(MutableHandle&& aHandle) : mHandle(std::move(aHandle)) {}
explicit Cursor(Handle&& aHandle) : mHandle(std::move(aHandle)) {}
bool IsValid() const { return mHandle.IsValid(); }
uint64_t Size() const { return mHandle.Size(); }
@@ -50,7 +50,7 @@ class Cursor {
void Seek(uint64_t aOffset);
// Invalidate the Cursor, and return the underlying handle.
MutableHandle TakeHandle();
Handle TakeHandle();
// Set the ChunkSize for the shared memory regions in this chunk. This is
// intended to be used for testing purposes.
@@ -76,9 +76,9 @@ class Cursor {
bool EnsureMapping();
// Shared memory handle this Cursor allows accessing.
MutableHandle mHandle;
Handle mHandle;
// Memory map for the currently active chunk. Lazily initialized.
MutableMapping mMapping;
Mapping mMapping;
// Absolute offset into the shared memory handle.
uint64_t mOffset = 0;
// Current size of each chunk. Always a power of two. May be reduced in

View File

@@ -45,27 +45,30 @@ Atomic<uint64_t> AllocationReporter::allocated;
NS_IMPL_ISUPPORTS(AllocationReporter, nsIMemoryReporter)
static void RegisterAllocationMemoryReporter() {
static void RegisterMemoryReporter() {
static Atomic<bool> registered;
if (registered.compareExchange(false, true)) {
RegisterStrongMemoryReporter(new AllocationReporter());
}
}
HandleBase::HandleBase() = default;
HandleBase::HandleBase() { RegisterMemoryReporter(); }
HandleBase::~HandleBase() {
if (mSize > 0) {
MOZ_ASSERT(AllocationReporter::allocated >= mSize,
"Can't destroy more than allocated");
SetSize(0);
}
MOZ_ASSERT(AllocationReporter::allocated >= mSize,
"Can't destroy more than allocated");
AllocationReporter::allocated -= mSize;
mHandle = nullptr;
mSize = 0;
}
HandleBase& HandleBase::operator=(HandleBase&& aOther) {
MOZ_ASSERT(AllocationReporter::allocated >= mSize,
"Can't destroy more than allocated");
AllocationReporter::allocated -= mSize;
mHandle = std::move(aOther.mHandle);
SetSize(std::exchange(aOther.mSize, 0));
mSize = std::exchange(aOther.mSize, 0);
return *this;
}
@@ -73,71 +76,45 @@ HandleBase HandleBase::Clone() const {
HandleBase hb;
hb.mHandle = Platform::CloneHandle(mHandle);
if (hb.mHandle) {
// TODO more intelligently handle clones to not count as additional
hb.mSize = mSize;
// TODO more intelligently handle clones to not count as addition
// allocations?
hb.SetSize(mSize);
AllocationReporter::allocated += mSize;
}
return hb;
}
void HandleBase::ToMessageWriter(IPC::MessageWriter* aWriter) && {
MOZ_ASSERT(AllocationReporter::allocated >= mSize,
"Can't destroy more than allocated");
AllocationReporter::allocated -= mSize;
WriteParam(aWriter, std::move(mHandle));
WriteParam(aWriter, mSize);
SetSize(0);
WriteParam(aWriter, std::exchange(mSize, 0));
}
bool HandleBase::FromMessageReader(IPC::MessageReader* aReader) {
mozilla::ipc::shared_memory::PlatformHandle handle;
if (!ReadParam(aReader, &handle)) {
aReader->FatalError("Failed to read shared memory PlatformHandle");
return false;
}
if (handle && !Platform::IsSafeToMap(handle)) {
aReader->FatalError("Shared memory PlatformHandle is not safe to map");
return false;
}
uint64_t size = 0;
if (!ReadParam(aReader, &size)) {
aReader->FatalError("Failed to read shared memory handle size");
return false;
}
if (handle && !size) {
aReader->FatalError(
"Unexpected PlatformHandle for zero-sized shared memory handle");
return false;
}
mHandle = std::move(handle);
SetSize(size);
if (!ReadParam(aReader, &mSize)) {
return false;
}
mozilla::ipc::shared_memory::AllocationReporter::allocated += mSize;
return true;
}
void HandleBase::SetSize(uint64_t aSize) {
RegisterAllocationMemoryReporter();
mozilla::ipc::shared_memory::AllocationReporter::allocated -= mSize;
mSize = aSize;
mozilla::ipc::shared_memory::AllocationReporter::allocated += mSize;
Mapping Handle::Map(void* aFixedAddress) const {
return Mapping(*this, aFixedAddress);
}
MutableMapping MutableHandle::Map(void* aFixedAddress) const {
return MutableMapping(*this, aFixedAddress);
}
MutableMapping MutableHandle::MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress) const {
return MutableMapping(*this, aOffset, aSize, aFixedAddress);
}
MutableMappingWithHandle MutableHandle::MapWithHandle(void* aFixedAddress) && {
return MutableMappingWithHandle(std::move(*this), aFixedAddress);
}
ReadOnlyHandle MutableHandle::ToReadOnly() && {
return std::move(*this).ConvertTo<Type::ReadOnly>();
}
const ReadOnlyHandle& MutableHandle::AsReadOnly() const {
static_assert(sizeof(ReadOnlyHandle) == sizeof(MutableHandle));
return reinterpret_cast<const ReadOnlyHandle&>(*this);
Mapping Handle::MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress) const {
return Mapping(*this, aOffset, aSize, aFixedAddress);
}
ReadOnlyMapping ReadOnlyHandle::Map(void* aFixedAddress) const {
@@ -149,24 +126,19 @@ ReadOnlyMapping ReadOnlyHandle::MapSubregion(uint64_t aOffset, size_t aSize,
return ReadOnlyMapping(*this, aOffset, aSize, aFixedAddress);
}
ReadOnlyMappingWithHandle ReadOnlyHandle::MapWithHandle(
void* aFixedAddress) && {
return ReadOnlyMappingWithHandle(std::move(*this), aFixedAddress);
}
FreezableHandle::~Handle() {
FreezableHandle::~FreezableHandle() {
NS_WARNING_ASSERTION(!IsValid(), "freezable shared memory was never frozen");
}
MutableHandle FreezableHandle::WontFreeze() && {
return std::move(*this).ConvertTo<Type::Mutable>();
Handle FreezableHandle::WontFreeze() && {
return std::move(*this).ConvertTo<Handle>();
}
ReadOnlyHandle FreezableHandle::Freeze() && {
DebugOnly<const uint64_t> previous_size = Size();
if (Platform::Freeze(*this)) {
MOZ_ASSERT(Size() == previous_size);
return std::move(*this).ConvertTo<Type::ReadOnly>();
return std::move(*this).ConvertTo<ReadOnlyHandle>();
}
return nullptr;
}
@@ -180,12 +152,13 @@ FreezableMapping FreezableHandle::MapSubregion(uint64_t aOffset, size_t aSize,
return FreezableMapping(std::move(*this), aOffset, aSize, aFixedAddress);
}
MutableHandle Create(uint64_t aSize) {
MutableHandle h;
Handle Create(uint64_t aSize) {
Handle h;
const auto success = Platform::Create(h, aSize);
MOZ_ASSERT(success == h.IsValid());
if (success) {
MOZ_ASSERT(aSize == h.Size());
AllocationReporter::allocated += h.Size();
}
return h;
}
@@ -196,6 +169,7 @@ FreezableHandle CreateFreezable(uint64_t aSize) {
MOZ_ASSERT(success == h.IsValid());
if (success) {
MOZ_ASSERT(aSize == h.Size());
AllocationReporter::allocated += h.Size();
}
return h;
}
@@ -204,15 +178,13 @@ FreezableHandle CreateFreezable(uint64_t aSize) {
namespace IPC {
void ParamTraits<mozilla::ipc::shared_memory::MutableHandle>::Write(
MessageWriter* aWriter,
mozilla::ipc::shared_memory::MutableHandle&& aParam) {
void ParamTraits<mozilla::ipc::shared_memory::Handle>::Write(
MessageWriter* aWriter, mozilla::ipc::shared_memory::Handle&& aParam) {
std::move(aParam).ToMessageWriter(aWriter);
}
bool ParamTraits<mozilla::ipc::shared_memory::MutableHandle>::Read(
MessageReader* aReader,
mozilla::ipc::shared_memory::MutableHandle* aResult) {
bool ParamTraits<mozilla::ipc::shared_memory::Handle>::Read(
MessageReader* aReader, mozilla::ipc::shared_memory::Handle* aResult) {
return aResult->FromMessageReader(aReader);
}

View File

@@ -9,31 +9,13 @@
#include <utility>
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/UniquePtrExtensions.h"
namespace IPC {
template <class P>
struct ParamTraits;
class MessageWriter;
class MessageReader;
} // namespace IPC
namespace mozilla::geckoargs {
template <typename T>
struct CommandLineArg;
}
namespace mozilla::ipc {
namespace shared_memory {
enum class Type {
Mutable,
ReadOnly,
MutableOrReadOnly,
Freezable,
};
// Rust Bindgen code doesn't actually use these types, but `UniqueFileHandle`
// and `UniqueMachSendRight` aren't defined and some headers need to type check,
// so we define a dummy pointer type.
@@ -45,23 +27,8 @@ using PlatformHandle = mozilla::UniqueMachSendRight;
using PlatformHandle = mozilla::UniqueFileHandle;
#endif
template <Type T>
struct Handle;
template <Type T, bool WithHandle = false>
struct Mapping;
using MutableHandle = Handle<Type::Mutable>;
using ReadOnlyHandle = Handle<Type::ReadOnly>;
using FreezableHandle = Handle<Type::Freezable>;
using MutableMapping = Mapping<Type::Mutable>;
using ReadOnlyMapping = Mapping<Type::ReadOnly>;
using MutableOrReadOnlyMapping = Mapping<Type::MutableOrReadOnly>;
using FreezableMapping = Mapping<Type::Freezable>;
using MutableMappingWithHandle = Mapping<Type::Mutable, true>;
using ReadOnlyMappingWithHandle = Mapping<Type::ReadOnly, true>;
struct ReadOnlyHandle;
class HandleBase {
public:
@@ -80,19 +47,9 @@ class HandleBase {
*/
explicit operator bool() const { return (bool)mHandle; }
/**
* Take the platform handle.
*
* This should be used with caution, as it drops all of the guarantees of the
* shared memory handle classes.
*/
PlatformHandle TakePlatformHandle() && { return std::move(mHandle); }
friend class Platform;
friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::MutableHandle>;
friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::Handle>;
friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>;
friend struct mozilla::geckoargs::CommandLineArg<
mozilla::ipc::shared_memory::ReadOnlyHandle>;
protected:
HandleBase();
@@ -110,14 +67,14 @@ class HandleBase {
HandleBase Clone() const;
template <Type T>
Handle<T> CloneAs() const {
return Clone().ConvertTo<T>();
template <typename Derived>
Derived CloneAs() const {
return Clone().ConvertTo<Derived>();
}
template <Type T>
Handle<T> ConvertTo() && {
Handle<T> d;
template <typename Derived>
Derived ConvertTo() && {
Derived d;
static_cast<HandleBase&>(d) = std::move(*this);
return d;
}
@@ -126,14 +83,6 @@ class HandleBase {
bool FromMessageReader(IPC::MessageReader* aReader);
private:
/**
* Set the size of the handle.
*
* This method must be used rather than setting `mSize` directly, as there is
* additional bookkeeping that goes along with this value.
*/
void SetSize(uint64_t aSize);
PlatformHandle mHandle = nullptr;
uint64_t mSize = 0;
};
@@ -141,8 +90,7 @@ class HandleBase {
/**
* A handle to a shared memory region.
*/
template <>
struct Handle<Type::Mutable> : HandleBase {
struct Handle : HandleBase {
/**
* Create an empty Handle.
*/
@@ -152,72 +100,45 @@ struct Handle<Type::Mutable> : HandleBase {
/**
* Clone the handle.
*/
Handle Clone() const { return CloneAs<Type::Mutable>(); }
/**
* Convert the handle to a read-only handle.
*
* Note that this doesn't enforce any sort of security or guarantees on the
* underlying shared memory.
*/
ReadOnlyHandle ToReadOnly() &&;
/**
* Use the handle as a read-only handle.
*
* Note that this doesn't enforce any sort of security or guarantees on the
* underlying shared memory.
*/
const ReadOnlyHandle& AsReadOnly() const;
Handle Clone() const { return CloneAs<Handle>(); }
/**
* Map the shared memory region into memory.
*/
MutableMapping Map(void* aFixedAddress = nullptr) const;
struct Mapping Map(void* aFixedAddress = nullptr) const;
/**
* Map a subregion of the shared memory region into memory.
*/
MutableMapping MapSubregion(uint64_t aOffset, size_t aSize,
struct Mapping MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr) const;
/**
* Map the shared memory region into memory, keeping the handle with it.
*/
MutableMappingWithHandle MapWithHandle(void* aFixedAddress = nullptr) &&;
};
/**
* A read-only handle to a shared memory region.
*/
template <>
struct Handle<Type::ReadOnly> : HandleBase {
struct ReadOnlyHandle : HandleBase {
/**
* Create an empty ReadOnlyHandle.
*/
Handle() = default;
MOZ_IMPLICIT Handle(std::nullptr_t) {}
ReadOnlyHandle() = default;
MOZ_IMPLICIT ReadOnlyHandle(std::nullptr_t) {}
/**
* Clone the handle.
*/
Handle Clone() const { return CloneAs<Type::ReadOnly>(); }
ReadOnlyHandle Clone() const { return CloneAs<ReadOnlyHandle>(); }
/**
* Map the shared memory region into memory.
*/
ReadOnlyMapping Map(void* aFixedAddress = nullptr) const;
struct ReadOnlyMapping Map(void* aFixedAddress = nullptr) const;
/**
* Map a subregion of the shared memory region into memory.
*/
ReadOnlyMapping MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr) const;
/**
* Map the shared memory region into memory, keeping the handle with it.
*/
ReadOnlyMappingWithHandle MapWithHandle(void* aFixedAddress = nullptr) &&;
struct ReadOnlyMapping MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr) const;
};
/**
@@ -226,22 +147,21 @@ struct Handle<Type::ReadOnly> : HandleBase {
* One cannot clone this handle, ensuring that at most one writable mapping
* exists. After freezing, no new writable mappings can be created.
*/
template <>
struct Handle<Type::Freezable> : HandleBase {
struct FreezableHandle : HandleBase {
/**
* Create an empty FreezableHandle.
*/
Handle() = default;
MOZ_IMPLICIT Handle(std::nullptr_t) {}
~Handle();
FreezableHandle() = default;
MOZ_IMPLICIT FreezableHandle(std::nullptr_t) {}
~FreezableHandle();
Handle(Handle&&) = default;
Handle& operator=(Handle&&) = default;
FreezableHandle(FreezableHandle&&) = default;
FreezableHandle& operator=(FreezableHandle&&) = default;
/**
* Convert to a normal handle if we will not freeze this handle.
*/
MutableHandle WontFreeze() &&;
Handle WontFreeze() &&;
/**
* Freeze this handle, returning a read-only handle.
@@ -251,13 +171,13 @@ struct Handle<Type::Freezable> : HandleBase {
/**
* Map the shared memory region into memory.
*/
FreezableMapping Map(void* aFixedAddress = nullptr) &&;
struct FreezableMapping Map(void* aFixedAddress = nullptr) &&;
/**
* Map a subregion of the shared memory region into memory.
*/
FreezableMapping MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr) &&;
struct FreezableMapping MapSubregion(uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr) &&;
friend class Platform;
#if !defined(XP_DARWIN) && !defined(XP_WIN) && !defined(ANDROID)
@@ -269,7 +189,7 @@ struct Handle<Type::Freezable> : HandleBase {
/**
* Create a new shared memory region.
*/
MutableHandle Create(uint64_t aSize);
Handle Create(uint64_t aSize);
/**
* Create a new freezable shared memory region.
@@ -283,20 +203,9 @@ MutableHandle Create(uint64_t aSize);
*/
FreezableHandle CreateFreezable(uint64_t aSize);
#if defined(XP_LINUX)
// 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.)
bool AppendPosixShmPrefix(std::string* str, pid_t pid);
// Returns whether POSIX shm is in use.
bool UsingPosixShm();
#endif
} // namespace shared_memory
using MutableSharedMemoryHandle = shared_memory::MutableHandle;
using MutableSharedMemoryHandle = shared_memory::Handle;
using ReadOnlySharedMemoryHandle = shared_memory::ReadOnlyHandle;
using FreezableSharedMemoryHandle = shared_memory::FreezableHandle;
@@ -305,11 +214,11 @@ using FreezableSharedMemoryHandle = shared_memory::FreezableHandle;
namespace IPC {
template <>
struct ParamTraits<mozilla::ipc::shared_memory::MutableHandle> {
struct ParamTraits<mozilla::ipc::shared_memory::Handle> {
static void Write(MessageWriter* aWriter,
mozilla::ipc::shared_memory::MutableHandle&& aParam);
mozilla::ipc::shared_memory::Handle&& aParam);
static bool Read(MessageReader* aReader,
mozilla::ipc::shared_memory::MutableHandle* aResult);
mozilla::ipc::shared_memory::Handle* aResult);
};
template <>

View File

@@ -45,14 +45,14 @@ Atomic<size_t> MappingReporter::mapped;
NS_IMPL_ISUPPORTS(MappingReporter, nsIMemoryReporter)
static void RegisterMappingMemoryReporter() {
static void RegisterMemoryReporter() {
static Atomic<bool> registered;
if (registered.compareExchange(false, true)) {
RegisterStrongMemoryReporter(new MappingReporter());
}
}
MappingBase::MappingBase() = default;
MappingBase::MappingBase() { RegisterMemoryReporter(); }
MappingBase& MappingBase::operator=(MappingBase&& aOther) {
// Swap members with `aOther`, and unmap that mapping.
@@ -62,7 +62,7 @@ MappingBase& MappingBase::operator=(MappingBase&& aOther) {
return *this;
}
void* MappingBase::Address() const {
void* MappingBase::Data() const {
#ifdef FUZZING
return SharedMemoryFuzzer::MutateSharedMemory(mMemory, mSize);
#else
@@ -70,12 +70,15 @@ void* MappingBase::Address() const {
#endif
}
LeakedMapping MappingBase::release() && {
// NOTE: this doesn't reduce gShmemMapped since it _is_ still mapped memory
// (and will be until the process terminates).
return LeakedMapping{static_cast<uint8_t*>(std::exchange(mMemory, nullptr)),
std::exchange(mSize, 0)};
}
bool MappingBase::Map(const HandleBase& aHandle, void* aFixedAddress,
bool aReadOnly) {
// Invalid handles will fail and result in an invalid mapping.
if (!aHandle) {
return false;
}
// Verify that the handle size can be stored as a mapping size first
// (otherwise it won't be possible to map in the address space and the Map
// call will fail).
@@ -101,8 +104,6 @@ bool MappingBase::MapSubregion(const HandleBase& aHandle, uint64_t aOffset,
return false;
}
RegisterMappingMemoryReporter();
if (auto mem =
Platform::Map(aHandle, aOffset, aSize, aFixedAddress, aReadOnly)) {
mMemory = *mem;
@@ -125,48 +126,43 @@ void MappingBase::Unmap() {
mSize = 0;
}
std::tuple<void*, size_t> MappingBase::Release() && {
// NOTE: this doesn't reduce gShmemMapped since it _is_ still mapped memory
// (and will be until the process terminates).
return std::make_tuple(std::exchange(mMemory, nullptr),
std::exchange(mSize, 0));
}
MutableOrReadOnlyMapping::Mapping(const MutableHandle& aHandle,
void* aFixedAddress)
: mReadOnly(false) {
Mapping::Mapping(const Handle& aHandle, void* aFixedAddress) {
Map(aHandle, aFixedAddress, false);
}
MutableOrReadOnlyMapping::Mapping(const ReadOnlyHandle& aHandle,
void* aFixedAddress)
: mReadOnly(true) {
Mapping::Mapping(const Handle& aHandle, uint64_t aOffset, size_t aSize,
void* aFixedAddress) {
MapSubregion(aHandle, aOffset, aSize, aFixedAddress, false);
}
ReadOnlyMapping::ReadOnlyMapping(const ReadOnlyHandle& aHandle,
void* aFixedAddress) {
Map(aHandle, aFixedAddress, true);
}
MutableOrReadOnlyMapping::Mapping(MutableMapping&& aMapping)
: MappingData(std::move(aMapping)), mReadOnly(false) {}
MutableOrReadOnlyMapping::Mapping(ReadOnlyMapping&& aMapping)
: MappingData(std::move(aMapping)), mReadOnly(true) {}
// We still store the handle if `Map` fails: the user may want to get it back
// (for instance, if fixed-address mapping doesn't work they may try mapping
// without one).
FreezableMapping::Mapping(FreezableHandle&& aHandle, void* aFixedAddress)
: mHandle(std::move(aHandle)) {
Map(mHandle, aFixedAddress, false);
ReadOnlyMapping::ReadOnlyMapping(const ReadOnlyHandle& aHandle,
uint64_t aOffset, size_t aSize,
void* aFixedAddress) {
MapSubregion(aHandle, aOffset, aSize, aFixedAddress, true);
}
FreezableMapping::Mapping(FreezableHandle&& aHandle, uint64_t aOffset,
size_t aSize, void* aFixedAddress)
: mHandle(std::move(aHandle)) {
MapSubregion(mHandle, aOffset, aSize, aFixedAddress, false);
FreezableMapping::FreezableMapping(FreezableHandle&& aHandle,
void* aFixedAddress) {
if (Map(aHandle, aFixedAddress, false)) {
mHandle = std::move(aHandle);
}
}
std::tuple<MutableMapping, ReadOnlyHandle> FreezableMapping::Freeze() && {
FreezableMapping::FreezableMapping(FreezableHandle&& aHandle, uint64_t aOffset,
size_t aSize, void* aFixedAddress) {
if (MapSubregion(aHandle, aOffset, aSize, aFixedAddress, false)) {
mHandle = std::move(aHandle);
}
}
std::tuple<Mapping, ReadOnlyHandle> FreezableMapping::Freeze() && {
auto handle = std::move(mHandle);
return std::make_tuple(ConvertMappingTo<Type::Mutable>(std::move(*this)),
return std::make_tuple(std::move(*this).ConvertTo<Mapping>(),
std::move(handle).Freeze());
}
@@ -176,10 +172,6 @@ FreezableHandle FreezableMapping::Unmap() && {
return handle;
}
bool LocalProtect(char* aAddr, size_t aSize, Access aAccess) {
return Platform::Protect(aAddr, aSize, aAccess);
}
void* FindFreeAddressSpace(size_t aSize) {
return Platform::FindFreeAddressSpace(aSize);
}
@@ -196,4 +188,8 @@ size_t PageAlignedSize(size_t aMinimum) {
return pageSize * nPagesNeeded;
}
bool Protect(char* aAddr, size_t aSize, Access aAccess) {
return Platform::Protect(aAddr, aSize, aAccess);
}
} // namespace mozilla::ipc::shared_memory

View File

@@ -8,7 +8,6 @@
#define mozilla_ipc_SharedMemoryMapping_h
#include <tuple>
#include <type_traits>
#include <utility>
#include "mozilla/Assertions.h"
#include "mozilla/Span.h"
@@ -23,19 +22,10 @@ namespace shared_memory {
*
* This memory will never be unmapped.
*/
template <Type T>
struct LeakedMapping : Span<uint8_t> {
using Span::Span;
};
template <>
struct LeakedMapping<Type::ReadOnly> : Span<const uint8_t> {
using Span::Span;
};
using LeakedMutableMapping = LeakedMapping<Type::Mutable>;
using LeakedReadOnlyMapping = LeakedMapping<Type::ReadOnly>;
class MappingBase {
public:
/**
@@ -46,7 +36,24 @@ class MappingBase {
/**
* The pointer to the mapping in memory.
*/
void* Address() const;
void* Data() const;
/**
* Get a `Span<T>` over the mapping.
*
* The mapping data must meet the alignment requirements of @p T.
*
* @tparam T The type of data in the mapping.
*
* @return A span of type @p T covering as much of the mapping as possible.
*/
template <typename T>
Span<T> DataAsSpan() const {
MOZ_ASSERT((reinterpret_cast<uintptr_t>(Data()) % alignof(T)) == 0,
"memory map does not meet alignment requirements of type");
size_t count = Size() / sizeof(T);
return {static_cast<T*>(Data()), count};
}
/**
* Whether this shared memory mapping is valid.
@@ -83,82 +90,11 @@ class MappingBase {
void* aFixedAddress, bool aReadOnly);
void Unmap();
template <Type T, Type S>
static Mapping<T> ConvertMappingTo(Mapping<S>&& from) {
Mapping<T> to;
static_cast<MappingBase&>(to) = std::move(from);
return to;
}
std::tuple<void*, size_t> Release() &&;
private:
void* mMemory = nullptr;
size_t mSize = 0;
};
template <bool CONST_MEMORY>
struct MappingData : MappingBase {
private:
template <typename T>
using DataType =
std::conditional_t<CONST_MEMORY, std::add_const_t<std::remove_const_t<T>>,
T>;
protected:
MappingData() = default;
explicit MappingData(MappingBase&& aOther) : MappingBase(std::move(aOther)) {}
public:
/**
* Get a pointer to the data in the mapping as a type T.
*
* The mapping data must meet the alignment requirements of @p T.
*
* @tparam T The type of data in the mapping.
*
* @return A pointer of type @p T*.
*/
template <typename T>
DataType<T>* DataAs() const {
MOZ_ASSERT((reinterpret_cast<uintptr_t>(Address()) % alignof(T)) == 0,
"memory map does not meet alignment requirements of type");
return static_cast<DataType<T>*>(Address());
}
/**
* Get a `Span<T>` over the mapping.
*
* The mapping data must meet the alignment requirements of @p T.
*
* @tparam T The type of data in the mapping.
*
* @return A span of type @p T covering as much of the mapping as possible.
*/
template <typename T>
Span<DataType<T>> DataAsSpan() const {
return {DataAs<T>(), Size() / sizeof(T)};
}
};
/**
* A shared memory mapping.
*/
template <Type T>
struct Mapping<T> : MappingData<T == Type::ReadOnly> {
/**
* Create an empty Mapping.
*/
Mapping() = default;
MOZ_IMPLICIT Mapping(std::nullptr_t) {}
explicit Mapping(const Handle<T>& aHandle, void* aFixedAddress = nullptr) {
MappingBase::Map(aHandle, aFixedAddress, T == Type::ReadOnly);
}
Mapping(const Handle<T>& aHandle, uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr) {
MappingBase::MapSubregion(aHandle, aOffset, aSize, aFixedAddress,
T == Type::ReadOnly);
template <typename Derived>
Derived ConvertTo() && {
Derived d;
static_cast<MappingBase&>(d) = std::move(*this);
return d;
}
/**
@@ -166,49 +102,55 @@ struct Mapping<T> : MappingData<T == Type::ReadOnly> {
*
* This will cause the memory to be mapped until the process exits.
*/
LeakedMapping<T> Release() && {
auto [ptr, size] = std::move(*this).MappingBase::Release();
return LeakedMapping<T>{
static_cast<typename LeakedMapping<T>::pointer>(ptr), size};
}
LeakedMapping release() &&;
private:
void* mMemory = nullptr;
size_t mSize = 0;
};
/**
* A shared memory mapping which has runtime-stored mutability.
* A shared memory mapping.
*/
template <>
struct Mapping<Type::MutableOrReadOnly> : MappingData<true> {
struct Mapping : MappingBase {
/**
* Create an empty MutableOrReadOnlyMapping.
* Create an empty Mapping.
*/
Mapping() = default;
MOZ_IMPLICIT Mapping(std::nullptr_t) {}
explicit Mapping(const ReadOnlyHandle& aHandle,
void* aFixedAddress = nullptr);
explicit Mapping(const MutableHandle& aHandle, void* aFixedAddress = nullptr);
MOZ_IMPLICIT Mapping(ReadOnlyMapping&& aMapping);
MOZ_IMPLICIT Mapping(MutableMapping&& aMapping);
explicit Mapping(const Handle& aHandle, void* aFixedAddress = nullptr);
Mapping(const Handle& aHandle, uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr);
using MappingBase::release;
};
/**
* A read-only shared memory mapping.
*/
struct ReadOnlyMapping : MappingBase {
/**
* Return whether the mapping is read-only.
* Create an empty ReadOnlyMapping.
*/
bool IsReadOnly() const { return mReadOnly; }
ReadOnlyMapping() = default;
MOZ_IMPLICIT ReadOnlyMapping(std::nullptr_t) {}
private:
bool mReadOnly = false;
explicit ReadOnlyMapping(const ReadOnlyHandle& aHandle,
void* aFixedAddress = nullptr);
ReadOnlyMapping(const ReadOnlyHandle& aHandle, uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr);
};
/**
* A freezable shared memory mapping.
*/
template <>
struct Mapping<Type::Freezable> : MappingData<false> {
struct FreezableMapping : MappingBase {
/**
* Create an empty FreezableMapping.
*/
Mapping() = default;
MOZ_IMPLICIT Mapping(std::nullptr_t) {}
FreezableMapping() = default;
MOZ_IMPLICIT FreezableMapping(std::nullptr_t) {}
/**
* Freezable mappings take ownership of a handle to ensure there is only one
@@ -216,9 +158,10 @@ struct Mapping<Type::Freezable> : MappingData<false> {
*
* Call `Unmap()` to get the handle back.
*/
explicit Mapping(FreezableHandle&& aHandle, void* aFixedAddress = nullptr);
Mapping(FreezableHandle&& aHandle, uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr);
explicit FreezableMapping(FreezableHandle&& aHandle,
void* aFixedAddress = nullptr);
FreezableMapping(FreezableHandle&& aHandle, uint64_t aOffset, size_t aSize,
void* aFixedAddress = nullptr);
/**
* Freeze the shared memory region.
@@ -226,7 +169,7 @@ struct Mapping<Type::Freezable> : MappingData<false> {
* The returned Mapping will still be valid and writable until it is deleted,
* however no new writable mappings can be created.
*/
std::tuple<MutableMapping, ReadOnlyHandle> Freeze() &&;
std::tuple<Mapping, ReadOnlyHandle> Freeze() &&;
/**
* Unmap the shared memory, returning the freezable handle.
@@ -236,35 +179,10 @@ struct Mapping<Type::Freezable> : MappingData<false> {
*/
FreezableHandle Unmap() &&;
protected:
private:
FreezableHandle mHandle;
};
template <Type T>
struct Mapping<T, true> : public Mapping<T> {
Mapping() {}
MOZ_IMPLICIT Mapping(std::nullptr_t) : Mapping<T>(nullptr) {}
explicit Mapping(Handle<T>&& aHandle, void* aFixedAddress = nullptr)
: Mapping<T>(aHandle, aFixedAddress), mHandle(std::move(aHandle)) {}
const Handle<T>& Handle() const { return mHandle; };
std::tuple<shared_memory::Handle<T>, Mapping<T>> Split() && {
auto handle = std::move(mHandle);
return std::make_tuple(std::move(handle), std::move(*this));
}
private:
shared_memory::Handle<T> mHandle;
};
// To uphold the guarantees of freezable mappings, we do not allow access to the
// handle (and since this should never be used in this way, we make it a useless
// type).
template <>
struct Mapping<Type::Freezable, true>;
// The access level permitted for memory protection.
enum Access {
AccessNone = 0,
@@ -320,16 +238,10 @@ size_t PageAlignedSize(size_t aMinimum);
} // namespace shared_memory
using SharedMemoryMapping = shared_memory::MutableMapping;
using SharedMemoryMapping = shared_memory::Mapping;
using ReadOnlySharedMemoryMapping = shared_memory::ReadOnlyMapping;
using MutableOrReadOnlySharedMemoryMapping =
shared_memory::MutableOrReadOnlyMapping;
using FreezableSharedMemoryMapping = shared_memory::FreezableMapping;
using SharedMemoryMappingWithHandle = shared_memory::MutableMappingWithHandle;
using ReadOnlySharedMemoryMappingWithHandle =
shared_memory::ReadOnlyMappingWithHandle;
} // namespace mozilla::ipc
#endif

View File

@@ -10,7 +10,6 @@
#include "mozilla/ipc/SharedMemoryHandle.h"
#include "mozilla/ipc/SharedMemoryMapping.h"
#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
namespace mozilla::ipc::shared_memory {
@@ -34,7 +33,7 @@ class Platform {
*
* @returns Whether the handle was successfully created.
*/
static bool Create(MutableHandle& aHandle, size_t aSize);
static bool Create(Handle& aHandle, size_t aSize);
/**
* Create a new freezable shared memory handle.

View File

@@ -41,13 +41,10 @@ static Maybe<PlatformHandle> CreateImpl(size_t aSize, bool aFreezable) {
return Some(fd);
}
bool AppendPosixShmPrefix(std::string* str, pid_t pid) { return false; }
bool UsingPosixShm() { return false; }
bool Platform::Create(MutableHandle& aHandle, size_t aSize) {
bool Platform::Create(Handle& aHandle, size_t aSize) {
if (auto ph = CreateImpl(aSize, false)) {
aHandle.mHandle = std::move(*ph);
aHandle.SetSize(aSize);
aHandle.mSize = aSize;
return true;
}
return false;
@@ -56,7 +53,7 @@ bool Platform::Create(MutableHandle& aHandle, size_t aSize) {
bool Platform::CreateFreezable(FreezableHandle& aHandle, size_t aSize) {
if (auto ph = CreateImpl(aSize, true)) {
aHandle.mHandle = std::move(*ph);
aHandle.SetSize(aSize);
aHandle.mSize = aSize;
return true;
}
return false;

View File

@@ -30,7 +30,6 @@
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Printf.h"
#include "nsDebug.h"
#ifdef DEBUG
# define LOG_ERROR(str, args...) \
@@ -70,10 +69,10 @@ static Maybe<PlatformHandle> CreateImpl(size_t aSize, bool aFreezable) {
return Some(std::move(handle));
}
bool Platform::Create(MutableHandle& aHandle, size_t aSize) {
bool Platform::Create(Handle& aHandle, size_t aSize) {
if (auto ph = CreateImpl(aSize, false)) {
aHandle.mHandle = std::move(*ph);
aHandle.SetSize(aSize);
aHandle.mSize = aSize;
return true;
}
return false;
@@ -82,7 +81,7 @@ bool Platform::Create(MutableHandle& aHandle, size_t aSize) {
bool Platform::CreateFreezable(FreezableHandle& aHandle, size_t aSize) {
if (auto ph = CreateImpl(aSize, true)) {
aHandle.mHandle = std::move(*ph);
aHandle.SetSize(aSize);
aHandle.mSize = aSize;
return true;
}
return false;

Some files were not shown because too many files have changed in this diff Show More