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