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.
17 #include <folly/portability/SysMman.h>
21 #include <folly/Portability.h>
22 #include <folly/portability/Windows.h>
24 static bool mmap_to_page_protection(int prot, DWORD& ret, DWORD& acc) {
25 if (prot == PROT_NONE) {
28 } else if (prot == PROT_READ) {
31 } else if (prot == PROT_EXEC) {
33 acc = FILE_MAP_EXECUTE;
34 } else if (prot == (PROT_READ | PROT_EXEC)) {
35 ret = PAGE_EXECUTE_READ;
36 acc = FILE_MAP_READ | FILE_MAP_EXECUTE;
37 } else if (prot == (PROT_READ | PROT_WRITE)) {
39 acc = FILE_MAP_READ | FILE_MAP_WRITE;
40 } else if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) {
41 ret = PAGE_EXECUTE_READWRITE;
42 acc = FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE;
49 static size_t alignToAllocationGranularity(size_t s) {
50 static size_t granularity = [] {
51 static SYSTEM_INFO inf;
53 return inf.dwAllocationGranularity;
55 return (s + granularity - 1) / granularity * granularity;
59 int madvise(const void* addr, size_t len, int advise) {
60 // We do nothing at all.
61 // Could probably implement dontneed via VirtualAlloc
62 // with the MEM_RESET and MEM_RESET_UNDO flags.
66 int mlock(const void* addr, size_t len) {
67 // For some strange reason, it's allowed to
68 // lock a nullptr as long as length is zero.
69 // VirtualLock doesn't allow it, so handle
71 if (addr == nullptr && len == 0) {
74 if (!VirtualLock((void*)addr, len)) {
81 constexpr uint32_t kMMapLengthMagic = 0xFACEB00C;
82 struct MemMapDebugTrailer {
88 void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) {
89 // Make sure it's something we support first.
92 if ((flags & (MAP_ANONYMOUS | MAP_SHARED)) == (MAP_ANONYMOUS | MAP_SHARED)) {
95 // No private copy on write.
96 if ((flags & MAP_PRIVATE) == MAP_PRIVATE && fd != -1) {
99 // Map isn't anon, must be file backed.
100 if (!(flags & MAP_ANONYMOUS) && fd == -1) {
106 if (!mmap_to_page_protection(prot, newProt, accessFlags)) {
111 if (!(flags & MAP_ANONYMOUS) || (flags & MAP_SHARED)) {
112 HANDLE h = INVALID_HANDLE_VALUE;
113 if (!(flags & MAP_ANONYMOUS)) {
114 h = (HANDLE)_get_osfhandle(fd);
117 HANDLE fmh = CreateFileMapping(
121 (DWORD)((length >> 32) & 0xFFFFFFFF),
122 (DWORD)(length & 0xFFFFFFFF),
124 if (fmh == nullptr) {
127 ret = MapViewOfFileEx(
130 (DWORD)((off >> 32) & 0xFFFFFFFF),
131 (DWORD)(off & 0xFFFFFFFF),
134 if (ret == nullptr) {
139 auto baseLength = length;
140 if (folly::kIsDebug) {
141 // In debug mode we keep track of the length to make
142 // sure you're only munmapping the entire thing if
143 // we're using VirtualAlloc.
144 length += sizeof(MemMapDebugTrailer);
147 // VirtualAlloc rounds size down to a multiple
148 // of the system allocation granularity :(
149 length = alignToAllocationGranularity(length);
150 ret = VirtualAlloc(addr, length, MEM_COMMIT | MEM_RESERVE, newProt);
151 if (ret == nullptr) {
155 if (folly::kIsDebug) {
156 auto deb = (MemMapDebugTrailer*)((char*)ret + baseLength);
157 deb->length = baseLength;
158 deb->magic = kMMapLengthMagic;
162 // TODO: Could technically implement MAP_POPULATE via PrefetchVirtualMemory
163 // Should also see about implementing MAP_NORESERVE
167 int mprotect(void* addr, size_t size, int prot) {
170 if (!mmap_to_page_protection(prot, newProt, access)) {
175 BOOL res = VirtualProtect(addr, size, newProt, &oldProt);
182 int munlock(const void* addr, size_t length) {
183 // See comment in mlock
184 if (addr == nullptr && length == 0) {
187 if (!VirtualUnlock((void*)addr, length)) {
193 int munmap(void* addr, size_t length) {
194 // Try to unmap it as a file, otherwise VirtualFree.
195 if (!UnmapViewOfFile(addr)) {
196 if (folly::kIsDebug) {
197 // We can't do partial unmapping with Windows, so
198 // assert that we aren't trying to do that if we're
200 MEMORY_BASIC_INFORMATION inf;
201 VirtualQuery(addr, &inf, sizeof(inf));
202 assert(inf.AllocationBase == addr);
204 auto deb = (MemMapDebugTrailer*)((char*)addr + length);
205 assert(deb->length == length);
206 assert(deb->magic == kMMapLengthMagic);
208 if (!VirtualFree(addr, 0, MEM_RELEASE)) {