зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1515551 - Add functionality to SharedMemoryBasic to help map the shared memory at an arbitrary address. r=kmag
This patch adds two things: 1. An optional fixed_address argument to SharedMemoryBasic::Map, which is the address to map the shared memory at. 2. A FindFreeAddressSpace function that callers can use to find a contiguous block of free address space, which can then be used to determine an address to pass in to Map that is likely to be free. Patches in bug 1474793 will use these to place the User Agent style sheets in a shared memory buffer in the parent process at an address that is also likely to be free in content processes. Differential Revision: https://phabricator.services.mozilla.com/D15057 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f03ec4810c
Коммит
bc72d9813e
|
@ -67,7 +67,11 @@ class SharedMemory {
|
|||
// Maps the shared memory into the caller's address space.
|
||||
// Returns true on success, false otherwise. The memory address
|
||||
// is accessed via the memory() accessor.
|
||||
bool Map(size_t bytes);
|
||||
//
|
||||
// If the specified fixed address is not null, it is the address that the
|
||||
// shared memory must be mapped at. Returns false if the shared memory
|
||||
// could not be mapped at that address.
|
||||
bool Map(size_t bytes, void* fixed_address = nullptr);
|
||||
|
||||
// Unmaps the shared memory from the caller's address space.
|
||||
// Returns true if successful; returns false on error or if the
|
||||
|
@ -94,6 +98,15 @@ class SharedMemory {
|
|||
// It is safe to call Close repeatedly.
|
||||
void Close(bool unmap_view = true);
|
||||
|
||||
// Returns a page-aligned address at which the given number of bytes could
|
||||
// probably be mapped. Returns NULL on error or if there is insufficient
|
||||
// contiguous address space to map the required number of pages.
|
||||
//
|
||||
// Note that there is no guarantee that the given address space will actually
|
||||
// be free by the time this function returns, since another thread might map
|
||||
// something there in the meantime.
|
||||
static void* FindFreeAddressSpace(size_t size);
|
||||
|
||||
// Share the shared memory to another process. Attempts
|
||||
// to create a platform-specific new_handle which can be
|
||||
// used in a remote process to access the shared memory
|
||||
|
|
|
@ -156,16 +156,30 @@ bool SharedMemory::Create(size_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::Map(size_t bytes) {
|
||||
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
|
||||
if (mapped_file_ == -1) return false;
|
||||
|
||||
memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
|
||||
MAP_SHARED, mapped_file_, 0);
|
||||
|
||||
if (memory_) max_size_ = bytes;
|
||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
||||
// replace pages that are alread mapped at that address.
|
||||
memory_ =
|
||||
mmap(fixed_address, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
|
||||
MAP_SHARED, mapped_file_, 0);
|
||||
|
||||
bool mmap_succeeded = (memory_ != (void*)-1);
|
||||
|
||||
DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno;
|
||||
|
||||
if (mmap_succeeded) {
|
||||
if (fixed_address && memory_ != fixed_address) {
|
||||
bool munmap_succeeded = munmap(memory_, bytes) == 0;
|
||||
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
|
||||
memory_ = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
max_size_ = bytes;
|
||||
}
|
||||
|
||||
return mmap_succeeded;
|
||||
}
|
||||
|
||||
|
@ -178,6 +192,13 @@ bool SharedMemory::Unmap() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory =
|
||||
mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
munmap(memory, size);
|
||||
return memory != MAP_FAILED ? memory : NULL;
|
||||
}
|
||||
|
||||
bool SharedMemory::ShareToProcessCommon(ProcessId processId,
|
||||
SharedMemoryHandle* new_handle,
|
||||
bool close_self) {
|
||||
|
|
|
@ -109,17 +109,19 @@ bool SharedMemory::Create(size_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::Map(size_t bytes) {
|
||||
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
|
||||
if (mapped_file_ == NULL) return false;
|
||||
|
||||
if (external_section_ && !IsSectionSafeToMap(mapped_file_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memory_ = MapViewOfFile(
|
||||
memory_ = MapViewOfFileEx(
|
||||
mapped_file_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
0, 0, bytes);
|
||||
0, 0, bytes, fixed_address);
|
||||
if (memory_ != NULL) {
|
||||
MOZ_ASSERT(!fixed_address || memory_ == fixed_address,
|
||||
"MapViewOfFileEx returned an expected address");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -133,6 +135,14 @@ bool SharedMemory::Unmap() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void* SharedMemory::FindFreeAddressSpace(size_t size) {
|
||||
void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (memory) {
|
||||
VirtualFree(memory, 0, MEM_RELEASE);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
bool SharedMemory::ShareToProcessCommon(ProcessId processId,
|
||||
SharedMemoryHandle* new_handle,
|
||||
bool close_self) {
|
||||
|
|
|
@ -50,7 +50,7 @@ class SharedMemory {
|
|||
virtual void* memory() const = 0;
|
||||
|
||||
virtual bool Create(size_t size) = 0;
|
||||
virtual bool Map(size_t nBytes) = 0;
|
||||
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) = 0;
|
||||
|
||||
virtual void CloseHandle() = 0;
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ bool SharedMemoryBasic::Create(size_t aNbytes) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemoryBasic::Map(size_t nBytes) {
|
||||
bool SharedMemoryBasic::Map(size_t nBytes, void* fixed_address) {
|
||||
MOZ_ASSERT(nullptr == mMemory, "Already Map()d");
|
||||
|
||||
int prot = PROT_READ;
|
||||
|
@ -76,17 +76,37 @@ bool SharedMemoryBasic::Map(size_t nBytes) {
|
|||
prot |= PROT_WRITE;
|
||||
}
|
||||
|
||||
mMemory = mmap(nullptr, nBytes, prot, MAP_SHARED, mShmFd, 0);
|
||||
// Don't use MAP_FIXED when a fixed_address was specified, since that can
|
||||
// replace pages that are alread mapped at that address.
|
||||
mMemory = mmap(fixed_address, nBytes, prot, MAP_SHARED, mShmFd, 0);
|
||||
|
||||
if (MAP_FAILED == mMemory) {
|
||||
LogError("ShmemAndroid::Map()");
|
||||
if (!fixed_address) {
|
||||
LogError("ShmemAndroid::Map()");
|
||||
}
|
||||
mMemory = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fixed_address && mMemory != fixed_address) {
|
||||
if (munmap(mMemory, nBytes)) {
|
||||
LogError("ShmemAndroid::Map():unmap");
|
||||
mMemory = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Mapped(nBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
|
||||
void* memory =
|
||||
mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
munmap(memory, size);
|
||||
return memory != (void*)-1 ? memory : NULL;
|
||||
}
|
||||
|
||||
bool SharedMemoryBasic::ShareToProcess(base::ProcessId /*unused*/,
|
||||
Handle* aNewHandle) {
|
||||
MOZ_ASSERT(mShmFd >= 0, "Should have been Create()d by now");
|
||||
|
|
|
@ -32,7 +32,7 @@ class SharedMemoryBasic final
|
|||
|
||||
virtual bool Create(size_t aNbytes) override;
|
||||
|
||||
virtual bool Map(size_t nBytes) override;
|
||||
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) override;
|
||||
|
||||
virtual void CloseHandle() override;
|
||||
|
||||
|
@ -48,6 +48,8 @@ class SharedMemoryBasic final
|
|||
|
||||
static Handle NULLHandle() { return Handle(); }
|
||||
|
||||
static void* FindFreeAddressSpace(size_t aSize);
|
||||
|
||||
virtual bool IsHandleValid(const Handle& aHandle) const override {
|
||||
return aHandle.fd >= 0;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ class SharedMemoryBasic final
|
|||
return ok;
|
||||
}
|
||||
|
||||
virtual bool Map(size_t nBytes) override {
|
||||
bool ok = mSharedMemory.Map(nBytes);
|
||||
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) override {
|
||||
bool ok = mSharedMemory.Map(nBytes, fixed_address);
|
||||
if (ok) {
|
||||
Mapped(nBytes);
|
||||
}
|
||||
|
@ -76,6 +76,10 @@ class SharedMemoryBasic final
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void* FindFreeAddressSpace(size_t size) {
|
||||
return base::SharedMemory::FindFreeAddressSpace(size);
|
||||
}
|
||||
|
||||
private:
|
||||
~SharedMemoryBasic() {}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class SharedMemoryBasic final : public SharedMemoryCommon<mach_port_t> {
|
|||
|
||||
virtual bool Create(size_t aNbytes) override;
|
||||
|
||||
virtual bool Map(size_t nBytes) override;
|
||||
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) override;
|
||||
|
||||
virtual void CloseHandle() override;
|
||||
|
||||
|
@ -86,6 +86,8 @@ class SharedMemoryBasic final : public SharedMemoryCommon<mach_port_t> {
|
|||
|
||||
static Handle NULLHandle() { return Handle(); }
|
||||
|
||||
static void* FindFreeAddressSpace(size_t aSize);
|
||||
|
||||
virtual bool IsHandleValid(const Handle& aHandle) const override;
|
||||
|
||||
virtual bool ShareToProcess(base::ProcessId aProcessId,
|
||||
|
|
|
@ -512,7 +512,7 @@ bool SharedMemoryBasic::Create(size_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemoryBasic::Map(size_t size) {
|
||||
bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
|
||||
MOZ_ASSERT(mMemory == nullptr);
|
||||
|
||||
if (MACH_PORT_NULL == mPort) {
|
||||
|
@ -520,18 +520,31 @@ bool SharedMemoryBasic::Map(size_t size) {
|
|||
}
|
||||
|
||||
kern_return_t kr;
|
||||
mach_vm_address_t address = 0;
|
||||
mach_vm_address_t address = toVMAddress(fixed_address);
|
||||
|
||||
vm_prot_t vmProtection = VM_PROT_READ;
|
||||
if (mOpenRights == RightsReadWrite) {
|
||||
vmProtection |= VM_PROT_WRITE;
|
||||
}
|
||||
|
||||
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0, VM_FLAGS_ANYWHERE, mPort, 0,
|
||||
false, vmProtection, vmProtection, VM_INHERIT_NONE);
|
||||
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
||||
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
|
||||
mPort, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n", size,
|
||||
mach_task_self(), mPort, mach_error_string(kr), kr);
|
||||
if (!fixed_address) {
|
||||
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mPort, mach_error_string(kr), kr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fixed_address && fixed_address != toPointer(address)) {
|
||||
kr = vm_deallocate(mach_task_self(), address, size);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to unmap shared memory at unsuitable address "
|
||||
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mPort, mach_error_string(kr), kr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -540,6 +553,18 @@ bool SharedMemoryBasic::Map(size_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
|
||||
mach_vm_address_t address = 0;
|
||||
size = round_page(size);
|
||||
if (mach_vm_map(mach_task_self(), &address, size, 0,
|
||||
VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE,
|
||||
VM_PROT_NONE, VM_INHERIT_NONE) != KERN_SUCCESS ||
|
||||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
return toPointer(address);
|
||||
}
|
||||
|
||||
bool SharedMemoryBasic::ShareToProcess(base::ProcessId pid, Handle* aNewHandle) {
|
||||
if (pid == getpid()) {
|
||||
*aNewHandle = mPort;
|
||||
|
|
Загрузка…
Ссылка в новой задаче