forked from mirrors/gecko-dev
This class implements a shared memory key-value store that fits into a single memory mapped segment. All of the runtime data for its instances are stored in the shared memory region, which means that memory overhead for each instance in each process is only a few bytes. Importantly, the key and value strings returned by this class are also pointers into the shared memory region, which means that once an instance is created, its memory cannot be unmapped until process shutdown. For the uses I intend to put it to, this is a reasonable constraint. If we need to use it for shorter-lived maps in the future, we can add an option to return non-literal dependent strings that will be copied if they need to be kept alive long term. MozReview-Commit-ID: 5BwAaDsb7HS --HG-- extra : rebase_source : b472fe628018f88a2c4d6b3de4b7143aeca55e14 extra : absorb_source : 5cdeb568cfd2b4a5a767191402e699e61e653b3b
164 lines
3.6 KiB
C++
164 lines
3.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
|
|
/* 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 "AutoMemMap.h"
|
|
#include "ScriptPreloader-inl.h"
|
|
|
|
#include "mozilla/Unused.h"
|
|
#include "nsIFile.h"
|
|
|
|
#include <private/pprio.h>
|
|
|
|
namespace mozilla {
|
|
namespace loader {
|
|
|
|
using namespace mozilla::ipc;
|
|
|
|
AutoMemMap::~AutoMemMap()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
FileDescriptor
|
|
AutoMemMap::cloneFileDescriptor() const
|
|
{
|
|
if (fd.get()) {
|
|
auto handle = FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd.get()));
|
|
return FileDescriptor(handle);
|
|
}
|
|
return FileDescriptor();
|
|
}
|
|
|
|
Result<Ok, nsresult>
|
|
AutoMemMap::init(nsIFile* file, int flags, int mode, PRFileMapProtect prot)
|
|
{
|
|
MOZ_ASSERT(!fd);
|
|
|
|
MOZ_TRY(file->OpenNSPRFileDesc(flags, mode, &fd.rwget()));
|
|
|
|
return initInternal(prot);
|
|
}
|
|
|
|
Result<Ok, nsresult>
|
|
AutoMemMap::init(const FileDescriptor& file, PRFileMapProtect prot,
|
|
size_t expectedSize)
|
|
{
|
|
MOZ_ASSERT(!fd);
|
|
if (!file.IsValid()) {
|
|
return Err(NS_ERROR_INVALID_ARG);
|
|
}
|
|
|
|
auto handle = file.ClonePlatformHandle();
|
|
|
|
fd = PR_ImportFile(PROsfd(handle.get()));
|
|
if (!fd) {
|
|
return Err(NS_ERROR_FAILURE);
|
|
}
|
|
Unused << handle.release();
|
|
|
|
return initInternal(prot, expectedSize);
|
|
}
|
|
|
|
Result<Ok, nsresult>
|
|
AutoMemMap::initInternal(PRFileMapProtect prot, size_t expectedSize)
|
|
{
|
|
MOZ_ASSERT(!fileMap);
|
|
MOZ_ASSERT(!addr);
|
|
|
|
PRFileInfo64 fileInfo;
|
|
MOZ_TRY(PR_GetOpenFileInfo64(fd.get(), &fileInfo));
|
|
|
|
if (fileInfo.size > UINT32_MAX)
|
|
return Err(NS_ERROR_INVALID_ARG);
|
|
|
|
fileMap = PR_CreateFileMap(fd, 0, prot);
|
|
if (!fileMap)
|
|
return Err(NS_ERROR_FAILURE);
|
|
|
|
size_ = fileInfo.size;
|
|
// The memory region size passed in certain IPC messages isn't necessary on
|
|
// Unix-like systems, since we can always stat the file descriptor to
|
|
// determine it accurately. But since we have it, anyway, sanity check that
|
|
// it matches the size returned by the stat.
|
|
MOZ_ASSERT_IF(expectedSize > 0, size_ == expectedSize);
|
|
|
|
addr = PR_MemMap(fileMap, 0, size_);
|
|
if (!addr)
|
|
return Err(NS_ERROR_FAILURE);
|
|
|
|
return Ok();
|
|
}
|
|
|
|
#ifdef XP_WIN
|
|
|
|
Result<Ok, nsresult>
|
|
AutoMemMap::initWithHandle(const FileDescriptor& file, size_t size, PRFileMapProtect prot)
|
|
{
|
|
MOZ_ASSERT(!fd);
|
|
MOZ_ASSERT(!handle_);
|
|
if (!file.IsValid()) {
|
|
return Err(NS_ERROR_INVALID_ARG);
|
|
}
|
|
|
|
handle_ = file.ClonePlatformHandle().release();
|
|
|
|
MOZ_ASSERT(!addr);
|
|
|
|
size_ = size;
|
|
|
|
addr = MapViewOfFile(
|
|
handle_,
|
|
prot == PR_PROT_READONLY ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
|
|
0, 0, size);
|
|
|
|
return Ok();
|
|
}
|
|
|
|
FileDescriptor
|
|
AutoMemMap::cloneHandle() const
|
|
{
|
|
return FileDescriptor(handle_);
|
|
}
|
|
|
|
#else
|
|
|
|
Result<Ok, nsresult>
|
|
AutoMemMap::initWithHandle(const FileDescriptor& file, size_t size, PRFileMapProtect prot)
|
|
{
|
|
return init(file, prot);
|
|
}
|
|
|
|
FileDescriptor
|
|
AutoMemMap::cloneHandle() const
|
|
{
|
|
return cloneFileDescriptor();
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
AutoMemMap::reset()
|
|
{
|
|
if (fileMap) {
|
|
if (addr && !persistent_) {
|
|
Unused << NS_WARN_IF(PR_MemUnmap(addr, size()) != PR_SUCCESS);
|
|
addr = nullptr;
|
|
}
|
|
|
|
Unused << NS_WARN_IF(PR_CloseFileMap(fileMap) != PR_SUCCESS);
|
|
fileMap = nullptr;
|
|
}
|
|
#ifdef XP_WIN
|
|
if (handle_) {
|
|
CloseHandle(handle_);
|
|
handle_ = nullptr;
|
|
}
|
|
#endif
|
|
fd.dispose();
|
|
}
|
|
|
|
} // namespace loader
|
|
} // namespace mozilla
|