• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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() { return handle_; }
134 
135  private:
136   MmapHandle handle_;
137 };
138 
139 }  // namespace libtextclassifier3
140 
141 #endif  // LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_
142