-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ipcz: OS primitives for reference drivers
In preparation for landing an async multiprocess reference driver, this lands some foundational primitives first. These are essentially cheesier versions of what we find in Chromium for scoped handles and shared memory. As with all reference driver code, these are not intended for production use, but for documentation and use in tests. Bug: 1299283 Change-Id: I18357f3401073b2c4d4f9711737ab6a67ec64e43 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648395 Commit-Queue: Ken Rockot <[email protected]> Reviewed-by: Daniel Cheng <[email protected]> Cr-Commit-Position: refs/heads/main@{#1005512} NOKEYCHECK=True GitOrigin-RevId: a0ce43fb810d0f706b921663ca7b8793c1bb4e1e
- Loading branch information
1 parent
f3ee75f
commit fc046c5
Showing
18 changed files
with
957 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright 2022 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "reference_drivers/memory.h" | ||
|
||
#include <utility> | ||
|
||
#include "build/build_config.h" | ||
#include "third_party/abseil-cpp/absl/base/macros.h" | ||
|
||
namespace ipcz::reference_drivers { | ||
|
||
Memory::Mapping::Mapping() = default; | ||
|
||
Memory::Mapping::Mapping(void* base_address, size_t size) | ||
: base_address_(base_address), size_(size) {} | ||
|
||
Memory::Mapping::Mapping(Mapping&& other) | ||
: base_address_(std::exchange(other.base_address_, nullptr)), | ||
size_(std::exchange(other.size_, 0)) {} | ||
|
||
Memory::Mapping& Memory::Mapping::operator=(Mapping&& other) { | ||
Reset(); | ||
base_address_ = std::exchange(other.base_address_, nullptr); | ||
size_ = std::exchange(other.size_, 0); | ||
return *this; | ||
} | ||
|
||
Memory::Mapping::~Mapping() { | ||
Reset(); | ||
} | ||
|
||
Memory::Memory() = default; | ||
|
||
Memory::Memory(OSHandle handle, size_t size) | ||
: handle_(std::move(handle)), size_(size) {} | ||
|
||
Memory::Memory(Memory&&) = default; | ||
|
||
Memory& Memory::operator=(Memory&&) = default; | ||
|
||
Memory::~Memory() = default; | ||
|
||
Memory Memory::Clone() { | ||
ABSL_ASSERT(is_valid()); | ||
return Memory(handle_.Clone(), size_); | ||
} | ||
|
||
} // namespace ipcz::reference_drivers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2022 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef IPCZ_SRC_REFERENCE_DRIVERS_MEMORY_H_ | ||
#define IPCZ_SRC_REFERENCE_DRIVERS_MEMORY_H_ | ||
|
||
#include "reference_drivers/os_handle.h" | ||
#include "third_party/abseil-cpp/absl/types/span.h" | ||
|
||
namespace ipcz::reference_drivers { | ||
|
||
// Cross-platform abstraction for a shared memory region. | ||
class Memory { | ||
public: | ||
// Cross-platform abstraction for an active mapping of a shared memory region. | ||
// | ||
// Instances of this object should be acquired from Memory::Map(). | ||
class Mapping { | ||
public: | ||
Mapping(); | ||
Mapping(void* base_address, size_t size); | ||
Mapping(Mapping&&); | ||
Mapping& operator=(Mapping&&); | ||
Mapping(const Mapping&) = delete; | ||
Mapping& operator=(const Mapping&) = delete; | ||
~Mapping(); | ||
|
||
bool is_valid() const { return base_address_ != nullptr; } | ||
|
||
size_t size() const { return size_; } | ||
void* base() const { return base_address_; } | ||
|
||
absl::Span<uint8_t> bytes() const { | ||
return {static_cast<uint8_t*>(base()), size_}; | ||
} | ||
|
||
template <typename T> | ||
T* As() const { | ||
return static_cast<T*>(base()); | ||
} | ||
|
||
void Reset(); | ||
|
||
private: | ||
void* base_address_ = nullptr; | ||
size_t size_ = 0; | ||
}; | ||
|
||
// Constructs an invalid Memory object which cannot be mapped. | ||
Memory(); | ||
|
||
// Constructs a new Memory object over `handle`, an OSHandle which should have | ||
// been previously taken from some other valid Memory object. `size` must | ||
// correspond to the size of that original region. | ||
Memory(OSHandle handle, size_t size); | ||
|
||
// Constructs a new Memory object over a newly allocated shared memory region | ||
// of at least `size` bytes. | ||
explicit Memory(size_t size); | ||
|
||
Memory(Memory&&); | ||
Memory& operator=(Memory&&); | ||
Memory(const Memory&) = delete; | ||
Memory& operator=(const Memory&) = delete; | ||
~Memory(); | ||
|
||
size_t size() const { return size_; } | ||
bool is_valid() const { return handle_.is_valid(); } | ||
const OSHandle& handle() const { return handle_; } | ||
|
||
// Invalidates this Memory object and returns an OSHandle which can be used | ||
// later to reconstruct an equivalent Memory object, given the same size(). | ||
OSHandle TakeHandle() { return std::move(handle_); } | ||
|
||
// Resets this object, closing its handle to the underlying region. | ||
void reset() { handle_.reset(); } | ||
|
||
// Returns a new Memory object with its own handle to the same underlying | ||
// region as `this`. Must only be called on a valid Memory object (i.e. | ||
// is_valid() must be true.) | ||
Memory Clone(); | ||
|
||
// Maps the entire region owned by Memory and returns a Mapping for it. Must | ||
// only be called on a valid Memory object (i.e. is_valid() must be true.) | ||
Mapping Map(); | ||
|
||
private: | ||
OSHandle handle_; | ||
size_t size_ = 0; | ||
}; | ||
|
||
} // namespace ipcz::reference_drivers | ||
|
||
#endif // IPCZ_SRC_REFERENCE_DRIVERS_MEMORY_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2022 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "reference_drivers/memory.h" | ||
|
||
#include <sys/mman.h> | ||
#include <unistd.h> | ||
|
||
#include <cstddef> | ||
|
||
#include "reference_drivers/os_handle.h" | ||
#include "third_party/abseil-cpp/absl/base/macros.h" | ||
#include "third_party/ashmem/ashmem.h" | ||
|
||
namespace ipcz::reference_drivers { | ||
|
||
void Memory::Mapping::Reset() { | ||
if (base_address_) { | ||
munmap(base_address_, size_); | ||
base_address_ = nullptr; | ||
size_ = 0; | ||
} | ||
} | ||
|
||
Memory::Memory(size_t size) { | ||
const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE)); | ||
const size_t rounded_size = (size + page_size - 1) & (page_size - 1); | ||
int fd = ashmem_create_region("ipcz-memory", rounded_size); | ||
ABSL_ASSERT(fd >= 0); | ||
int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); | ||
ABSL_ASSERT(err == 0); | ||
handle_ = OSHandle(fd); | ||
size_ = size; | ||
} | ||
|
||
Memory::Mapping Memory::Map() { | ||
ABSL_ASSERT(is_valid()); | ||
void* addr = | ||
mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_SHARED, handle_.fd(), 0); | ||
ABSL_ASSERT(addr && addr != MAP_FAILED); | ||
return Mapping(addr, size_); | ||
} | ||
|
||
} // namespace ipcz::reference_drivers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2022 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "reference_drivers/memory.h" | ||
|
||
#include <lib/zx/vmar.h> | ||
#include <zircon/syscalls.h> | ||
|
||
#include <cstddef> | ||
#include <cstdint> | ||
#include <utility> | ||
|
||
#include "reference_drivers/os_handle.h" | ||
#include "third_party/abseil-cpp/absl/base/macros.h" | ||
|
||
namespace ipcz::reference_drivers { | ||
|
||
void Memory::Mapping::Reset() { | ||
if (base_address_) { | ||
uintptr_t addr = reinterpret_cast<uintptr_t>(base_address_); | ||
zx_status_t status = zx::vmar::root_self()->unmap(addr, size_); | ||
ABSL_ASSERT(status == ZX_OK); | ||
} | ||
} | ||
|
||
Memory::Memory(size_t size) { | ||
const uint32_t page_size = zx_system_get_page_size(); | ||
const size_t rounded_size = (size + page_size - 1) & (page_size - 1); | ||
zx::vmo vmo; | ||
zx_status_t status = zx::vmo::create(rounded_size, 0, &vmo); | ||
ABSL_ASSERT(status == ZX_OK); | ||
const int kNoExec = ZX_DEFAULT_VMO_RIGHTS & ~ZX_RIGHT_EXECUTE; | ||
status = vmo.replace(kNoExec, &vmo); | ||
ABSL_ASSERT(status == ZX_OK); | ||
handle_ = OSHandle(std::move(vmo)); | ||
size_ = size; | ||
} | ||
|
||
Memory::Mapping Memory::Map() { | ||
ABSL_ASSERT(is_valid()); | ||
uintptr_t addr; | ||
zx_vm_option_t options = | ||
ZX_VM_REQUIRE_NON_RESIZABLE | ZX_VM_PERM_READ | ZX_VM_PERM_WRITE; | ||
zx_status_t status = zx::vmar::root_self()->map( | ||
options, /*vmar_offset=*/0, *zx::unowned_vmo(handle_.handle().get()), 0, | ||
size_, &addr); | ||
if (status != ZX_OK) { | ||
return {}; | ||
} | ||
return Mapping(reinterpret_cast<void*>(addr), size_); | ||
} | ||
|
||
} // namespace ipcz::reference_drivers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright 2022 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "reference_drivers/memory.h" | ||
|
||
#include <mach/mach_vm.h> | ||
|
||
#include "reference_drivers/os_handle.h" | ||
#include "third_party/abseil-cpp/absl/base/macros.h" | ||
|
||
namespace ipcz::reference_drivers { | ||
|
||
void Memory::Mapping::Reset() { | ||
if (base_address_) { | ||
kern_return_t kr = mach_vm_deallocate( | ||
mach_task_self(), reinterpret_cast<mach_vm_address_t>(base_address_), | ||
size_); | ||
ABSL_ASSERT(kr == KERN_SUCCESS); | ||
} | ||
} | ||
|
||
Memory::Memory(size_t size) { | ||
mach_vm_size_t vm_size = size; | ||
mach_port_t named_right; | ||
kern_return_t kr = mach_make_memory_entry_64( | ||
mach_task_self(), &vm_size, 0, | ||
MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE, &named_right, | ||
MACH_PORT_NULL); | ||
ABSL_ASSERT(kr == KERN_SUCCESS); | ||
ABSL_ASSERT(vm_size >= size); | ||
handle_ = OSHandle(OSHandle::MachSendRight(named_right)); | ||
size_ = size; | ||
} | ||
|
||
Memory::Mapping Memory::Map() { | ||
ABSL_ASSERT(is_valid()); | ||
mach_vm_address_t address = 0; | ||
kern_return_t kr = mach_vm_map(mach_task_self(), &address, size_, 0, | ||
VM_FLAGS_ANYWHERE, handle_.mach_send_right(), | ||
0, FALSE, VM_PROT_READ | VM_PROT_WRITE, | ||
VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_NONE); | ||
ABSL_ASSERT(kr == KERN_SUCCESS); | ||
return Mapping(reinterpret_cast<void*>(address), size_); | ||
} | ||
|
||
} // namespace ipcz::reference_drivers |
Oops, something went wrong.