|
13 | 13 | #include <memory> |
14 | 14 | #include <span> |
15 | 15 | #include <string_view> |
| 16 | +#include <sys/mman.h> |
| 17 | +#include <sys/stat.h> |
16 | 18 | #include <tuple> |
17 | 19 | #include <type_traits> |
18 | 20 | #include <utility> |
@@ -45,6 +47,73 @@ inline constexpr std::string_view UDP_SCHEME_PREFIX = "udp://"; |
45 | 47 |
|
46 | 48 | // ================================================================================================ |
47 | 49 |
|
| 50 | +class mmap { |
| 51 | + k2::descriptor m_descriptor{k2::INVALID_PLATFORM_DESCRIPTOR}; |
| 52 | + void* m_addr{nullptr}; |
| 53 | + size_t m_length{}; |
| 54 | + |
| 55 | + mmap(k2::descriptor descriptor, void* addr, size_t length) noexcept |
| 56 | + : m_descriptor{descriptor}, |
| 57 | + m_addr{addr}, |
| 58 | + m_length{length} {} |
| 59 | + |
| 60 | +public: |
| 61 | + mmap(mmap&& other) noexcept |
| 62 | + : m_descriptor{std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR)}, |
| 63 | + m_addr{std::exchange(other.m_addr, nullptr)}, |
| 64 | + m_length{std::exchange(other.m_length, {})} {} |
| 65 | + |
| 66 | + mmap& operator=(mmap&& other) noexcept { |
| 67 | + if (this != std::addressof(other)) { |
| 68 | + std::ignore = close(); |
| 69 | + m_descriptor = std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR); |
| 70 | + m_addr = std::exchange(other.m_addr, nullptr); |
| 71 | + m_length = std::exchange(other.m_length, {}); |
| 72 | + } |
| 73 | + return *this; |
| 74 | + } |
| 75 | + |
| 76 | + ~mmap() { |
| 77 | + std::ignore = close(); |
| 78 | + } |
| 79 | + |
| 80 | + mmap(const mmap&) = delete; |
| 81 | + mmap& operator=(const mmap&) = delete; |
| 82 | + |
| 83 | + static auto create(size_t length, int32_t prot, int32_t flags, k2::descriptor fd, uint64_t offset) noexcept -> std::expected<mmap, int32_t>; |
| 84 | + |
| 85 | + auto madvise(int32_t advise) noexcept -> std::expected<void, int32_t>; |
| 86 | + auto data() const noexcept -> std::span<const std::byte>; |
| 87 | + auto close() noexcept -> std::expected<void, int32_t>; |
| 88 | +}; |
| 89 | + |
| 90 | +inline auto mmap::create(size_t length, int32_t prot, int32_t flags, k2::descriptor fd, uint64_t offset) noexcept -> std::expected<mmap, int32_t> { |
| 91 | + k2::descriptor descriptor{k2::INVALID_PLATFORM_DESCRIPTOR}; |
| 92 | + auto* addr{k2::mmap(std::addressof(descriptor), nullptr, length, prot, flags, fd, offset)}; |
| 93 | + if (addr == MAP_FAILED) [[unlikely]] { |
| 94 | + return std::unexpected{k2::errno_efault}; |
| 95 | + } |
| 96 | + return mmap{descriptor, addr, length}; |
| 97 | +} |
| 98 | + |
| 99 | +inline auto mmap::madvise(int32_t advise) noexcept -> std::expected<void, int32_t> { |
| 100 | + return k2::madvise(m_addr, m_length, advise); |
| 101 | +} |
| 102 | + |
| 103 | +inline auto mmap::data() const noexcept -> std::span<const std::byte> { |
| 104 | + return {reinterpret_cast<const std::byte*>(m_addr), m_length}; |
| 105 | +} |
| 106 | + |
| 107 | +inline auto mmap::close() noexcept -> std::expected<void, int32_t> { |
| 108 | + if (m_descriptor == k2::INVALID_PLATFORM_DESCRIPTOR) [[unlikely]] { |
| 109 | + return std::unexpected{k2::errno_enodev}; |
| 110 | + } |
| 111 | + k2::free_descriptor(std::exchange(m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR)); |
| 112 | + return {}; |
| 113 | +} |
| 114 | + |
| 115 | +// ================================================================================================ |
| 116 | + |
48 | 117 | struct resource : public refcountable_polymorphic_php_classes<may_be_mixed_base> { |
49 | 118 | const char* get_class() const noexcept final { |
50 | 119 | return "resource"; |
@@ -146,7 +215,29 @@ inline auto file::pread(std::span<std::byte> buf, uint64_t offset) noexcept -> s |
146 | 215 | } |
147 | 216 |
|
148 | 217 | inline auto file::get_contents() noexcept -> std::expected<string, int32_t> { |
149 | | - return std::unexpected{m_descriptor != k2::INVALID_PLATFORM_DESCRIPTOR ? k2::errno_efault : k2::errno_enodev}; |
| 218 | + struct stat stat_buf {}; |
| 219 | + |
| 220 | + if (auto expected{k2::fstat(m_descriptor, std::addressof(stat_buf))}; !expected.has_value()) { |
| 221 | + return std::unexpected{expected.error()}; |
| 222 | + } |
| 223 | + if (!S_ISREG(stat_buf.st_mode)) { |
| 224 | + return std::unexpected{k2::errno_einval}; |
| 225 | + } |
| 226 | + |
| 227 | + const size_t size{static_cast<size_t>(stat_buf.st_size)}; |
| 228 | + if (size > string::max_size()) { |
| 229 | + return std::unexpected{k2::errno_erange}; |
| 230 | + } |
| 231 | + |
| 232 | + auto expected_mmap{kphp::fs::mmap::create(size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, m_descriptor, 0)}; |
| 233 | + if (!expected_mmap.has_value()) { |
| 234 | + return std::unexpected{expected_mmap.error()}; |
| 235 | + } |
| 236 | + |
| 237 | + auto& mmap{*expected_mmap}; |
| 238 | + std::ignore = mmap.madvise(MADV_SEQUENTIAL); |
| 239 | + auto data{mmap.data()}; |
| 240 | + return string{reinterpret_cast<const char*>(data.data()), static_cast<string::size_type>(data.size())}; |
150 | 241 | } |
151 | 242 |
|
152 | 243 | inline auto file::flush() noexcept -> std::expected<void, int32_t> { |
|
0 commit comments