// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/utils/port/MemoryMapping.h" #include "td/utils/logging.h" #include "td/utils/misc.h" // TODO: // windows, // anonymous maps, // huge pages? #if TD_WINDOWS #else #include #include #endif namespace td { class MemoryMapping::Impl { public: Impl(MutableSlice data, int64 offset) : data_(data), offset_(offset) { } Slice as_slice() const { return data_.substr(narrow_cast(offset_)); } MutableSlice as_mutable_slice() const { return {}; } private: MutableSlice data_; int64 offset_; }; static Result get_page_size() { #if TD_WINDOWS return Status::Error("Unimplemented"); #else static Result page_size = []() -> Result { auto page_size = sysconf(_SC_PAGESIZE); if (page_size < 0) { return OS_ERROR("Can't load page size from sysconf"); } return page_size; }(); return page_size.clone(); #endif } Result MemoryMapping::create_anonymous(const MemoryMapping::Options &options) { return Status::Error("Unsupported yet"); } Result MemoryMapping::create_from_file(const FileFd &file_fd, const MemoryMapping::Options &options) { #if TD_WINDOWS return Status::Error("Unsupported yet"); #else if (file_fd.empty()) { return Status::Error("Can't create memory mapping: file is empty"); } TRY_RESULT(stat, file_fd.stat()); auto fd = file_fd.get_native_fd().fd(); auto begin = options.offset; if (begin < 0) { return Status::Error(PSLICE() << "Can't create memory mapping: negative offset " << options.offset); } int64 end; if (options.size < 0) { end = stat.size_; } else { end = begin + stat.size_; } TRY_RESULT(page_size, get_page_size()); auto fixed_begin = begin / page_size * page_size; auto data_offset = begin - fixed_begin; TRY_RESULT(data_size, narrow_cast_safe(end - fixed_begin)); void *data = mmap(nullptr, data_size, PROT_READ, MADV_MERGEABLE, fd, narrow_cast(fixed_begin)); if (data == MAP_FAILED) { return OS_ERROR("mmap call failed"); } return MemoryMapping(make_unique(MutableSlice(static_cast(data), data_size), data_offset)); #endif } MemoryMapping::MemoryMapping(MemoryMapping &&other) = default; MemoryMapping &MemoryMapping::operator=(MemoryMapping &&other) = default; MemoryMapping::~MemoryMapping() = default; MemoryMapping::MemoryMapping(unique_ptr impl) : impl_(std::move(impl)) { } Slice MemoryMapping::as_slice() const { return impl_->as_slice(); } MutableSlice MemoryMapping::as_mutable_slice() { return impl_->as_mutable_slice(); } } // namespace td