1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_ 18 #define LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_ 19 20 #include <stddef.h> 21 22 #include <string> 23 24 #include "utils/base/integral_types.h" 25 #include "utils/strings/stringpiece.h" 26 27 namespace libtextclassifier3 { 28 29 // Handle for a memory area where a file has been mmapped. 30 // 31 // Similar to a pointer: you "allocate" it using MmapFile(filename) and "delete" 32 // it using Unmap(). Just like a pointer, it is passed around by value (see 33 // signature of MmapFile and Unmap; fortunately, it's a small class, so there 34 // shouldn't be any significant performance penalty) and its usage is not 35 // necessarily scoped (that's why the destructor is not performing the unmap). 36 // 37 // Note: on program termination, each still unmapped file is automatically 38 // unmapped. Hence, it is not an error if you don't call Unmap() (provided you 39 // are ok keeping that file in memory the whole time). 40 class MmapHandle { 41 public: 42 MmapHandle(void *start, size_t num_bytes, void *unmap_addr = nullptr) start_(start)43 : start_(start), num_bytes_(num_bytes), unmap_addr_(unmap_addr) {} 44 45 // Returns start address for the memory area where a file has been mmapped. start()46 void *start() const { return start_; } 47 48 // Returns address to use for munmap call. If unmap_addr was not specified 49 // the start address is used. unmap_addr()50 void *unmap_addr() const { 51 if (unmap_addr_ != nullptr) { 52 return unmap_addr_; 53 } else { 54 return start_; 55 } 56 } 57 58 // Returns number of bytes of the memory area from start(). num_bytes()59 size_t num_bytes() const { return num_bytes_; } 60 61 // Shortcut to simplify checking success of MmapFile(). See usage example 62 // from the doc of that function. ok()63 bool ok() const { return start() != nullptr; } 64 65 // Returns a StringPiece pointing to the same underlying bytes. to_stringpiece()66 StringPiece to_stringpiece() const { 67 return StringPiece(reinterpret_cast<char *>(start_), num_bytes_); 68 } 69 70 private: 71 // See doc for start(). Not owned. 72 void *const start_; 73 74 // See doc for num_bytes(). 75 const size_t num_bytes_; 76 77 // Address to use for unmapping. 78 void *const unmap_addr_; 79 }; 80 81 // Maps the full content of a file in memory (using mmap). 82 // 83 // When done using the file content, one can unmap using Unmap(). Otherwise, 84 // all mapped files are unmapped when the program terminates. 85 // 86 // Sample usage: 87 // 88 // MmapHandle mmap_handle = MmapFile(filename); 89 // TC3_DCHECK(mmap_handle.ok()) << "Unable to mmap " << filename; 90 // 91 // ... use data from addresses 92 // ... [mmap_handle.start, mmap_handle.start + mmap_handle.num_bytes) 93 // 94 // Unmap(mmap_handle); // Unmap logs errors internally. 95 // 96 // Note: one can read *and* write the num_bytes bytes from start, but those 97 // writes are not propagated to the underlying file, nor to other processes that 98 // may have mmapped that file (all changes are local to current process). 99 MmapHandle MmapFile(const std::string &filename); 100 101 // Like MmapFile(const std::string &filename), but uses a file descriptor. 102 MmapHandle MmapFile(int fd); 103 104 // Maps a segment of a file to memory. File is given by a file descriptor, and 105 // offset (relative to the beginning of the file) and size specify the segment 106 // to be mapped. NOTE: Internally, we align the offset for the call to mmap 107 // system call to be a multiple of page size, so offset does NOT have to be a 108 // multiply of the page size. 109 MmapHandle MmapFile(int fd, int64 segment_offset, int64 segment_size); 110 111 // Unmaps a file mapped using MmapFile. Returns true on success, false 112 // otherwise. 113 bool Unmap(MmapHandle mmap_handle); 114 115 // Scoped mmapping of a file. Mmaps a file on construction, unmaps it on 116 // destruction. 117 class ScopedMmap { 118 public: ScopedMmap(const std::string & filename)119 explicit ScopedMmap(const std::string &filename) 120 : handle_(MmapFile(filename)) {} 121 ScopedMmap(int fd)122 explicit ScopedMmap(int fd) : handle_(MmapFile(fd)) {} 123 ScopedMmap(int fd,int segment_offset,int segment_size)124 ScopedMmap(int fd, int segment_offset, int segment_size) 125 : handle_(MmapFile(fd, segment_offset, segment_size)) {} 126 ~ScopedMmap()127 ~ScopedMmap() { 128 if (handle_.ok()) { 129 Unmap(handle_); 130 } 131 } 132 handle()133 const MmapHandle &handle() const { return handle_; } 134 135 private: 136 MmapHandle handle_; 137 }; 138 139 } // namespace libtextclassifier3 140 141 #endif // LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_ 142