fd: Add MMap handle object
This makes it possible to have an RAII managed MMap
Change-Id: Id61cea650a68087ca9d263a57dd780791845eb85
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/meson.build b/src/meson.build
index 9b4ad23..af7399c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -57,6 +57,7 @@
'stdplus/fd/dupable.cpp',
'stdplus/fd/impl.cpp',
'stdplus/fd/managed.cpp',
+ 'stdplus/fd/mmap.cpp',
'stdplus/fd/ops.cpp',
]
@@ -67,6 +68,7 @@
'stdplus/fd/impl.hpp',
'stdplus/fd/intf.hpp',
'stdplus/fd/managed.hpp',
+ 'stdplus/fd/mmap.hpp',
'stdplus/fd/ops.hpp',
subdir: 'stdplus/fd')
elif get_option('fd').enabled()
diff --git a/src/stdplus/fd/gmock.hpp b/src/stdplus/fd/gmock.hpp
index 97a4f01..ca3b2af 100644
--- a/src/stdplus/fd/gmock.hpp
+++ b/src/stdplus/fd/gmock.hpp
@@ -35,6 +35,11 @@
MOCK_METHOD(FdFlags, fcntlGetfd, (), (const, override));
MOCK_METHOD(void, fcntlSetfl, (FileFlags flags), (override));
MOCK_METHOD(FileFlags, fcntlGetfl, (), (const, override));
+ MOCK_METHOD(std::span<std::byte>, mmap,
+ (std::span<std::byte> window, ProtFlags prot, MMapFlags flags,
+ off_t offset),
+ (override));
+ MOCK_METHOD(void, munmap, (std::span<std::byte> window), (override));
};
} // namespace fd
diff --git a/src/stdplus/fd/impl.cpp b/src/stdplus/fd/impl.cpp
index 2d92b72..34b365f 100644
--- a/src/stdplus/fd/impl.cpp
+++ b/src/stdplus/fd/impl.cpp
@@ -179,5 +179,22 @@
return FileFlags(CHECK_ERRNO(::fcntl(get(), F_GETFL), "fcntl getfl"));
}
+std::span<std::byte> FdImpl::mmap(std::span<std::byte> window, ProtFlags prot,
+ MMapFlags flags, off_t offset)
+{
+ auto ret = ::mmap(window.data(), window.size(), static_cast<int>(prot),
+ static_cast<int>(flags), get(), offset);
+ if (ret == MAP_FAILED)
+ {
+ util::doError(errno, "mmap");
+ }
+ return {reinterpret_cast<std::byte*>(ret), window.size()};
+}
+
+void FdImpl::munmap(std::span<std::byte> window)
+{
+ CHECK_ERRNO(::munmap(window.data(), window.size()), "munmap");
+}
+
} // namespace fd
} // namespace stdplus
diff --git a/src/stdplus/fd/impl.hpp b/src/stdplus/fd/impl.hpp
index b4e134c..9d5acaf 100644
--- a/src/stdplus/fd/impl.hpp
+++ b/src/stdplus/fd/impl.hpp
@@ -31,6 +31,11 @@
FdFlags fcntlGetfd() const override;
void fcntlSetfl(FileFlags flags) override;
FileFlags fcntlGetfl() const override;
+
+ protected:
+ std::span<std::byte> mmap(std::span<std::byte> window, ProtFlags prot,
+ MMapFlags flags, off_t offset) override;
+ void munmap(std::span<std::byte> window) override;
};
} // namespace fd
diff --git a/src/stdplus/fd/intf.hpp b/src/stdplus/fd/intf.hpp
index 7778ae1..4d9553d 100644
--- a/src/stdplus/fd/intf.hpp
+++ b/src/stdplus/fd/intf.hpp
@@ -4,6 +4,7 @@
#include <optional>
#include <span>
#include <stdplus/flags.hpp>
+#include <sys/mman.h>
#include <sys/socket.h>
#include <tuple>
@@ -80,6 +81,40 @@
};
using FileFlags = BitFlags<int, FileFlag>;
+enum class ProtFlag : int
+{
+ Exec = PROT_EXEC,
+ Read = PROT_READ,
+ Write = PROT_WRITE,
+};
+using ProtFlags = BitFlags<int, ProtFlag>;
+
+enum class MMapAccess : int
+{
+ Shared = MAP_SHARED,
+ Private = MAP_PRIVATE,
+};
+
+enum class MMapFlag : int
+{
+};
+
+class MMapFlags : public BitFlags<int, MMapFlag>
+{
+ public:
+ inline MMapFlags(MMapAccess access) :
+ BitFlags<int, MMapFlag>(static_cast<int>(access))
+ {
+ }
+
+ inline MMapFlags(BitFlags<int, MMapFlag> flags) :
+ BitFlags<int, MMapFlag>(flags)
+ {
+ }
+};
+
+class MMap;
+
class Fd
{
public:
@@ -106,6 +141,13 @@
virtual FdFlags fcntlGetfd() const = 0;
virtual void fcntlSetfl(FileFlags flags) = 0;
virtual FileFlags fcntlGetfl() const = 0;
+
+ protected:
+ virtual std::span<std::byte> mmap(std::span<std::byte> window,
+ ProtFlags prot, MMapFlags flags,
+ off_t offset) = 0;
+ virtual void munmap(std::span<std::byte> window) = 0;
+ friend class MMap;
};
} // namespace fd
diff --git a/src/stdplus/fd/mmap.cpp b/src/stdplus/fd/mmap.cpp
new file mode 100644
index 0000000..079815d
--- /dev/null
+++ b/src/stdplus/fd/mmap.cpp
@@ -0,0 +1,26 @@
+#include <stdplus/fd/mmap.hpp>
+#include <stdplus/util/cexec.hpp>
+
+namespace stdplus
+{
+namespace fd
+{
+
+MMap::MMap(Fd& fd, std::span<std::byte> window, ProtFlags prot, MMapFlags flags,
+ off_t offset) :
+ mapping(fd.mmap(window, prot, flags, offset), fd)
+{
+}
+
+std::span<std::byte> MMap::get() const
+{
+ return *mapping;
+}
+
+void MMap::drop(std::span<std::byte>&& mapping, std::reference_wrapper<Fd>& fd)
+{
+ fd.get().munmap(mapping);
+}
+
+} // namespace fd
+} // namespace stdplus
diff --git a/src/stdplus/fd/mmap.hpp b/src/stdplus/fd/mmap.hpp
new file mode 100644
index 0000000..06b7944
--- /dev/null
+++ b/src/stdplus/fd/mmap.hpp
@@ -0,0 +1,36 @@
+#pragma once
+#include <cstddef>
+#include <functional>
+#include <span>
+#include <stdplus/fd/intf.hpp>
+#include <stdplus/handle/managed.hpp>
+
+namespace stdplus
+{
+namespace fd
+{
+
+class MMap
+{
+ public:
+ inline MMap(Fd& fd, size_t window_size, ProtFlags prot, MMapFlags flags,
+ off_t offset) :
+ MMap(
+ fd,
+ std::span<std::byte>{static_cast<std::byte*>(nullptr), window_size},
+ prot, flags, offset)
+ {
+ }
+ MMap(Fd& fd, std::span<std::byte> window, ProtFlags prot, MMapFlags flags,
+ off_t offset);
+
+ std::span<std::byte> get() const;
+
+ private:
+ static void drop(std::span<std::byte>&&, std::reference_wrapper<Fd>&);
+ Managed<std::span<std::byte>, std::reference_wrapper<Fd>>::Handle<drop>
+ mapping;
+};
+
+} // namespace fd
+} // namespace stdplus
diff --git a/test/fd/mmap.cpp b/test/fd/mmap.cpp
new file mode 100644
index 0000000..3f1ab33
--- /dev/null
+++ b/test/fd/mmap.cpp
@@ -0,0 +1,26 @@
+#include <array>
+#include <gtest/gtest.h>
+#include <stdplus/fd/create.hpp>
+#include <stdplus/fd/mmap.hpp>
+
+namespace stdplus
+{
+namespace fd
+{
+
+TEST(MMap, Basic)
+{
+ auto fd = open("/dev/zero", OpenAccess::ReadOnly);
+ auto map = MMap(fd, 32, ProtFlags().set(ProtFlag::Read),
+ MMapFlags{MMapAccess::Private}, 0);
+ auto sp = map.get();
+ ASSERT_NE(nullptr, sp.data());
+ ASSERT_EQ(32, sp.size());
+ for (size_t i = 0; i < 32; ++i)
+ {
+ EXPECT_EQ(sp[i], std::byte{});
+ }
+}
+
+} // namespace fd
+} // namespace stdplus
diff --git a/test/meson.build b/test/meson.build
index 7d26297..2634c45 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -45,6 +45,7 @@
'fd/managed',
'fd/intf',
'fd/impl',
+ 'fd/mmap',
'fd/mock',
'fd/ops',
]