From 30a1e466d387f7549bf05e5cef3f5bdd38daaefe Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Fri, 17 Nov 2017 01:20:12 -0800 Subject: [PATCH] lib: wrapper to manage memory-mapped files Signed-off-by: Rick Altherr Signed-off-by: Tim 'mithro' Ansell --- CMakeLists.txt | 7 +++++ lib/CMakeLists.txt | 11 +++++++ lib/include/prjxray/memory_mapped_file.h | 29 +++++++++++++++++ lib/memory_mapped_file.cc | 40 ++++++++++++++++++++++++ lib/memory_mapped_file_test.cc | 14 +++++++++ lib/test_data/small_file | 1 + 6 files changed, 102 insertions(+) create mode 100644 lib/CMakeLists.txt create mode 100644 lib/include/prjxray/memory_mapped_file.h create mode 100644 lib/memory_mapped_file.cc create mode 100644 lib/memory_mapped_file_test.cc create mode 100644 lib/test_data/small_file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2483ca25..36bea5b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,22 @@ cmake_minimum_required(VERSION 3.5.0) project(prjxray) +option(PRJXRAY_BUILD_TESTING "" ON) set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Werror ${CMAKE_CXX_FLAGS} -O3" ) # Hack for missing option in cctz option(BUILD_TESTING "" OFF) + +if(PRJXRAY_BUILD_TESTING) + enable_testing() +endif() + add_subdirectory(third_party/googletest EXCLUDE_FROM_ALL) add_subdirectory(third_party/gflags EXCLUDE_FROM_ALL) add_subdirectory(third_party/cctz EXCLUDE_FROM_ALL) add_subdirectory(third_party/abseil-cpp EXCLUDE_FROM_ALL) +add_subdirectory(lib) add_subdirectory(tools) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 00000000..89a84071 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(libprjxray + memory_mapped_file.cc) +target_include_directories(libprjxray PUBLIC "include") + +if (PRJXRAY_BUILD_TESTING) + add_executable(memory_mapped_file_test memory_mapped_file_test.cc) + target_link_libraries(memory_mapped_file_test libprjxray gtest_main) + add_test(NAME memory_mapped_file_test + COMMAND memory_mapped_file_test + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test_data) +endif() diff --git a/lib/include/prjxray/memory_mapped_file.h b/lib/include/prjxray/memory_mapped_file.h new file mode 100644 index 00000000..c62ea9b6 --- /dev/null +++ b/lib/include/prjxray/memory_mapped_file.h @@ -0,0 +1,29 @@ +#ifndef PRJXRAY_LIB_MEMORY_MAPPED_FILE +#define PRJXRAY_LIB_MEMORY_MAPPED_FILE + +#include +#include + +namespace prjxray { + +class MemoryMappedFile { + public: + ~MemoryMappedFile(); + + static std::unique_ptr InitWithFile( + const std::string &path); + + const void* data() { return data_; } + const size_t size() { return size_; } + + private: + MemoryMappedFile(void *data, size_t size) + : data_(data), size_(size) {}; + + void *data_; + size_t size_; +}; + +} // namespace prjxray + +#endif // PRJXRAY_LIB_MEMORY_MAPPED_FILE diff --git a/lib/memory_mapped_file.cc b/lib/memory_mapped_file.cc new file mode 100644 index 00000000..e01a5a3e --- /dev/null +++ b/lib/memory_mapped_file.cc @@ -0,0 +1,40 @@ +#include + +#include +#include +#include +#include +#include + +namespace prjxray { + +std::unique_ptr MemoryMappedFile::InitWithFile( + const std::string &path) { + + int fd = open(path.c_str(), O_RDONLY, 0); + if (fd == -1) return nullptr; + + struct stat statbuf; + if (fstat(fd, &statbuf) < 0) { + close(fd); + } + + void *file_map = mmap(NULL, statbuf.st_size, PROT_READ, + MAP_PRIVATE | MAP_POPULATE, fd, 0); + + // If mmap() succeeded, the fd is no longer needed as the mapping will + // keep the file open. If mmap() failed, the fd needs to be closed + // anyway. + close(fd); + + if (file_map == MAP_FAILED) return nullptr; + + return std::unique_ptr( + new MemoryMappedFile(file_map, statbuf.st_size)); +} + +MemoryMappedFile::~MemoryMappedFile() { + munmap(data_, size_); +} + +} // namepsace prjxray diff --git a/lib/memory_mapped_file_test.cc b/lib/memory_mapped_file_test.cc new file mode 100644 index 00000000..0c61d41e --- /dev/null +++ b/lib/memory_mapped_file_test.cc @@ -0,0 +1,14 @@ +#include + +#include + +TEST(MemoryMappedFileTest, NonExistantFile) { + EXPECT_FALSE(prjxray::MemoryMappedFile::InitWithFile("does_not_exist")); +} + +TEST(MemoryMappedFileTest, ExistingFile) { + auto file = prjxray::MemoryMappedFile::InitWithFile("small_file"); + ASSERT_TRUE(file); + EXPECT_EQ(static_cast(4), file->size()); + EXPECT_EQ(0, memcmp("foo\n", file->data(), 4)); +} diff --git a/lib/test_data/small_file b/lib/test_data/small_file new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/lib/test_data/small_file @@ -0,0 +1 @@ +foo