2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <folly/FBString.h>
20 #include <folly/File.h>
21 #include <folly/Range.h>
22 #include <glog/logging.h>
23 #include <boost/noncopyable.hpp>
28 * Maps files in memory (read-only).
30 * @author Tudor Bosman (tudorb@fb.com)
32 class MemoryMapping : boost::noncopyable {
35 * Lock the pages in memory?
36 * TRY_LOCK = try to lock, log warning if permission denied
37 * MUST_LOCK = lock, fail assertion if permission denied.
44 * Map a portion of the file indicated by filename in memory, causing a CHECK
47 * By default, map the whole file. length=-1: map from offset to EOF.
48 * Unlike the mmap() system call, offset and length don't need to be
49 * page-aligned. length is clipped to the end of the file if it's too large.
51 * The mapping will be destroyed (and the memory pointed-to by data() will
52 * likely become inaccessible) when the MemoryMapping object is destroyed.
57 // Convenience methods; return *this for chaining.
58 Options& setPageSize(off_t v) { pageSize = v; return *this; }
59 Options& setShared(bool v) { shared = v; return *this; }
60 Options& setPrefault(bool v) { prefault = v; return *this; }
61 Options& setReadable(bool v) { readable = v; return *this; }
62 Options& setWritable(bool v) { writable = v; return *this; }
63 Options& setGrow(bool v) { grow = v; return *this; }
65 // Page size. 0 = use appropriate page size.
66 // (On Linux, we use a huge page size if the file is on a hugetlbfs
67 // file system, and the default page size otherwise)
70 // If shared (default), the memory mapping is shared with other processes
71 // mapping the same file (or children); if not shared (private), each
72 // process has its own mapping. Changes in writable, private mappings are
73 // not reflected to the underlying file. See the discussion of
74 // MAP_PRIVATE vs MAP_SHARED in the mmap(2) manual page.
77 // Populate page tables; subsequent accesses should not be blocked
78 // by page faults. This is a hint, as it may not be supported.
79 bool prefault = false;
81 // Map the pages readable. Note that mapping pages without read permissions
82 // is not universally supported (not supported on hugetlbfs on Linux, for
86 // Map the pages writable.
87 bool writable = false;
89 // When mapping a file in writable mode, grow the file to the requested
90 // length (using ftruncate()) before mapping; if false, truncate the
91 // mapping to the actual file size instead.
94 // Fix map at this address, if not nullptr. Must be aligned to a multiple
95 // of the appropriate page size.
96 void* address = nullptr;
99 // Options to emulate the old WritableMemoryMapping: readable and writable,
100 // allow growing the file if mapping past EOF.
101 static Options writable() {
102 return Options().setWritable(true).setGrow(true);
110 * Create an anonymous mapping.
112 MemoryMapping(AnonymousType, off_t length, Options options=Options());
114 explicit MemoryMapping(File file,
117 Options options=Options());
119 explicit MemoryMapping(const char* name,
122 Options options=Options());
124 explicit MemoryMapping(int fd,
127 Options options=Options());
129 MemoryMapping(MemoryMapping&&) noexcept;
133 MemoryMapping& operator=(MemoryMapping);
135 void swap(MemoryMapping& other) noexcept;
138 * Lock the pages in memory
140 bool mlock(LockMode lock);
144 * If dontneed is true, the kernel is instructed to release these pages
145 * (per madvise(MADV_DONTNEED)).
147 void munlock(bool dontneed = false);
150 * Hint that these pages will be scanned linearly.
151 * madvise(MADV_SEQUENTIAL)
153 void hintLinearScan();
156 * Advise the kernel about memory access.
158 void advise(int advice) const;
159 void advise(int advice, size_t offset, size_t length) const;
162 * A bitwise cast of the mapped bytes as range of values. Only intended for
163 * use with POD or in-place usable types.
166 Range<const T*> asRange() const {
167 size_t count = data_.size() / sizeof(T);
168 return Range<const T*>(static_cast<const T*>(
169 static_cast<const void*>(data_.data())),
174 * A range of bytes mapped by this mapping.
176 ByteRange range() const {
181 * A bitwise cast of the mapped bytes as range of mutable values. Only
182 * intended for use with POD or in-place usable types.
185 Range<T*> asWritableRange() const {
186 DCHECK(options_.writable); // you'll segfault anyway...
187 size_t count = data_.size() / sizeof(T);
188 return Range<T*>(static_cast<T*>(
189 static_cast<void*>(data_.data())),
194 * A range of mutable bytes mapped by this mapping.
196 MutableByteRange writableRange() const {
197 DCHECK(options_.writable); // you'll segfault anyway...
202 * Return the memory area where the file was mapped.
203 * Deprecated; use range() instead.
205 StringPiece data() const {
206 return asRange<const char>();
209 bool mlocked() const {
213 int fd() const { return file_.fd(); }
222 void init(off_t offset, off_t length);
225 void* mapStart_ = nullptr;
226 off_t mapLength_ = 0;
228 bool locked_ = false;
229 MutableByteRange data_;
232 void swap(MemoryMapping&, MemoryMapping&) noexcept;
235 * A special case of memcpy() that always copies memory forwards.
236 * (libc's memcpy() is allowed to copy memory backwards, and will do so
237 * when using SSSE3 instructions).
239 * Assumes src and dest are aligned to alignof(unsigned long).
241 * Useful when copying from/to memory mappings after hintLinearScan();
242 * copying backwards renders any prefetching useless (even harmful).
244 void alignedForwardMemcpy(void* dest, const void* src, size_t size);
247 * Copy a file using mmap(). Overwrites dest.
249 void mmapFileCopy(const char* src, const char* dest, mode_t mode = 0666);