1 #ifndef OSMIUM_UTIL_MEMORY_MAPPING_HPP
2 #define OSMIUM_UTIL_MEMORY_MAPPING_HPP
43 #include <system_error>
46 # include <sys/mman.h>
47 # include <sys/statvfs.h>
52 # include <sys/types.h>
57 inline namespace util {
149 HANDLE get_handle() const noexcept;
150 HANDLE create_file_mapping() const noexcept;
151 void* map_view_of_file() const noexcept;
161 const int result = ::fstatvfs(
fd, &stat);
165 return stat.f_bsize * stat.f_bavail;
179 if (available > 0 && current_file_size + available <=
m_size) {
180 throw std::system_error{ENOSPC, std::system_category(),
"Could not resize file: Not enough space on filesystem"};
241 }
catch (
const std::system_error&) {
265 void resize(std::size_t new_size);
271 explicit operator bool() const noexcept {
280 std::size_t
size() const noexcept {
289 int fd() const noexcept {
305 template <
typename T =
void>
307 return reinterpret_cast<T*>(
m_addr);
335 void resize(std::size_t) =
delete;
349 template <
typename T>
389 sizeof(T) * offset) {
443 explicit operator bool() const noexcept {
452 std::size_t
size() const noexcept {
462 int fd() const noexcept {
505 const T*
cend() const noexcept {
523 const T*
end() const noexcept {
529 template <
typename T>
543 void resize(std::size_t) =
delete;
557 #pragma GCC diagnostic push
558 #pragma GCC diagnostic ignored "-Wold-style-cast"
561 return m_addr != MAP_FAILED;
568 #pragma GCC diagnostic pop
571 #ifndef MAP_ANONYMOUS
572 # define MAP_ANONYMOUS MAP_ANON
576 if (m_mapping_mode == mapping_mode::readonly) {
579 return PROT_READ | PROT_WRITE;
586 if (m_mapping_mode == mapping_mode::write_shared) {
593 m_size(check_size(size)),
596 m_mapping_mode(mode),
597 m_addr(::mmap(nullptr, m_size, get_protection(), get_flags(), m_fd, m_offset)) {
600 throw std::system_error{errno, std::system_category(),
"mmap failed"};
605 m_size(other.m_size),
606 m_offset(other.m_offset),
608 m_mapping_mode(other.m_mapping_mode),
609 m_addr(other.m_addr) {
610 other.make_invalid();
616 }
catch (
const std::system_error&) {
620 m_size = other.m_size;
621 m_offset = other.m_offset;
623 m_mapping_mode = other.m_mapping_mode;
624 m_addr = other.m_addr;
625 other.make_invalid();
631 if (::munmap(m_addr, m_size) != 0) {
632 throw std::system_error{errno, std::system_category(),
"munmap failed"};
639 assert(new_size > 0 &&
"can not resize to zero size");
642 m_addr = ::mremap(m_addr, m_size, new_size, MREMAP_MAYMOVE);
644 throw std::system_error{errno, std::system_category(),
"mremap failed"};
648 assert(
false &&
"can't resize anonymous mappings on non-linux systems");
654 m_addr = ::mmap(
nullptr, new_size, get_protection(), get_flags(), m_fd, m_offset);
656 throw std::system_error{errno, std::system_category(),
"mmap (remap) failed"};
674 inline namespace util {
676 inline DWORD dword_hi(uint64_t x) {
677 return static_cast<DWORD>(x >> 32);
680 inline DWORD dword_lo(uint64_t x) {
681 return static_cast<DWORD>(x & 0xffffffff);
689 switch (m_mapping_mode) {
690 case mapping_mode::readonly:
691 return PAGE_READONLY;
692 case mapping_mode::write_private:
693 return PAGE_WRITECOPY;
697 return PAGE_READWRITE;
701 switch (m_mapping_mode) {
702 case mapping_mode::readonly:
703 return FILE_MAP_READ;
704 case mapping_mode::write_private:
705 return FILE_MAP_COPY;
709 return FILE_MAP_WRITE;
712 inline HANDLE osmium::util::MemoryMapping::get_handle() const noexcept {
714 return INVALID_HANDLE_VALUE;
716 return reinterpret_cast<HANDLE>(_get_osfhandle(m_fd));
719 inline HANDLE osmium::util::MemoryMapping::create_file_mapping() const noexcept {
721 _setmode(m_fd, _O_BINARY);
723 return CreateFileMapping(get_handle(),
726 osmium::dword_hi(static_cast<uint64_t>(m_size) + m_offset),
727 osmium::dword_lo(static_cast<uint64_t>(m_size) + m_offset),
731 inline void* osmium::util::MemoryMapping::map_view_of_file() const noexcept {
732 return MapViewOfFile(m_handle,
734 osmium::dword_hi(m_offset),
735 osmium::dword_lo(m_offset),
740 return m_addr !=
nullptr;
750 inline int last_error() noexcept {
751 return static_cast<int>(GetLastError());
755 m_size(check_size(size)),
758 m_mapping_mode(mode),
759 m_handle(create_file_mapping()),
763 throw std::system_error{last_error(), std::system_category(),
"CreateFileMapping failed"};
766 m_addr = map_view_of_file();
768 throw std::system_error{last_error(), std::system_category(),
"MapViewOfFile failed"};
773 m_size(other.m_size),
774 m_offset(other.m_offset),
776 m_mapping_mode(other.m_mapping_mode),
777 m_handle(std::move(other.m_handle)),
778 m_addr(other.m_addr) {
779 other.make_invalid();
780 other.m_handle =
nullptr;
785 m_size = other.m_size;
786 m_offset = other.m_offset;
788 m_mapping_mode = other.m_mapping_mode;
789 m_handle = std::move(other.m_handle);
790 m_addr = other.m_addr;
791 other.make_invalid();
792 other.m_handle =
nullptr;
798 if (!UnmapViewOfFile(m_addr)) {
799 throw std::system_error{last_error(), std::system_category(),
"UnmapViewOfFile failed"};
805 if (!CloseHandle(m_handle)) {
806 throw std::system_error{last_error(), std::system_category(),
"CloseHandle failed"};
818 m_handle = create_file_mapping();
820 throw std::system_error{last_error(), std::system_category(),
"CreateFileMapping failed"};
823 m_addr = map_view_of_file();
825 throw std::system_error{last_error(), std::system_category(),
"MapViewOfFile failed"};
831 #endif // OSMIUM_UTIL_MEMORY_MAPPING_HPP