Fix the detection of preadv and pwritev on OSX in OSS
[folly.git] / folly / portability / SysMman.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
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 #include <folly/portability/SysMman.h>
18
19 #ifdef _WIN32
20 #include <folly/portability/Windows.h>
21
22 static bool mmap_to_page_protection(int prot, DWORD& ret) {
23   if (prot == PROT_NONE) {
24     ret = PAGE_NOACCESS;
25   } else if (prot == PROT_READ) {
26     ret = PAGE_READONLY;
27   } else if (prot == PROT_EXEC) {
28     ret = PAGE_EXECUTE;
29   } else if (prot == (PROT_READ | PROT_EXEC)) {
30     ret = PAGE_EXECUTE_READ;
31   } else if (prot == (PROT_READ | PROT_WRITE)) {
32     ret = PAGE_READWRITE;
33   } else if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) {
34     ret = PAGE_EXECUTE_READWRITE;
35   } else {
36     return false;
37   }
38   return true;
39 }
40
41 extern "C" {
42 int madvise(const void* addr, size_t len, int advise) {
43   // We do nothing at all.
44   // Could probably implement dontneed via VirtualAlloc
45   // with the MEM_RESET and MEM_RESET_UNDO flags.
46   return 0;
47 }
48
49 int mlock(const void* addr, size_t len) {
50   if (!VirtualLock((void*)addr, len)) {
51     return -1;
52   }
53   return 0;
54 }
55
56 void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) {
57   // Make sure it's something we support first.
58
59   // No Anon shared.
60   if ((flags & (MAP_ANONYMOUS | MAP_SHARED)) == (MAP_ANONYMOUS | MAP_SHARED)) {
61     return MAP_FAILED;
62   }
63   // No private copy on write.
64   if ((flags & MAP_PRIVATE) == MAP_PRIVATE && fd != -1) {
65     return MAP_FAILED;
66   }
67   // Map isn't anon, must be file backed.
68   if (!(flags & MAP_ANONYMOUS) && fd == -1) {
69     return MAP_FAILED;
70   }
71
72   DWORD newProt;
73   if (!mmap_to_page_protection(prot, newProt)) {
74     return MAP_FAILED;
75   }
76
77   void* ret;
78   if (!(flags & MAP_ANONYMOUS) || (flags & MAP_SHARED)) {
79     HANDLE h = INVALID_HANDLE_VALUE;
80     if (!(flags & MAP_ANONYMOUS)) {
81       h = (HANDLE)_get_osfhandle(fd);
82     }
83
84     HANDLE fmh = CreateFileMapping(
85         h,
86         nullptr,
87         newProt | SEC_COMMIT | SEC_RESERVE,
88         (DWORD)((length >> 32) & 0xFFFFFFFF),
89         (DWORD)(length & 0xFFFFFFFF),
90         nullptr);
91     ret = MapViewOfFileEx(
92         fmh,
93         FILE_MAP_ALL_ACCESS,
94         (DWORD)((off >> 32) & 0xFFFFFFFF),
95         (DWORD)(off & 0xFFFFFFFF),
96         0,
97         addr);
98     if (ret == nullptr) {
99       ret = MAP_FAILED;
100     }
101     CloseHandle(fmh);
102   } else {
103     ret = VirtualAlloc(addr, length, MEM_COMMIT | MEM_RESERVE, newProt);
104     if (ret == nullptr) {
105       return MAP_FAILED;
106     }
107   }
108
109   // TODO: Could technically implement MAP_POPULATE via PrefetchVirtualMemory
110   //       Should also see about implementing MAP_NORESERVE
111   return ret;
112 }
113
114 int mprotect(void* addr, size_t size, int prot) {
115   DWORD newProt;
116   if (!mmap_to_page_protection(prot, newProt)) {
117     return -1;
118   }
119
120   DWORD oldProt;
121   BOOL res = VirtualProtect(addr, size, newProt, &oldProt);
122   if (!res) {
123     return -1;
124   }
125   return 0;
126 }
127
128 int munlock(const void* addr, size_t length) {
129   if (!VirtualUnlock((void*)addr, length)) {
130     return -1;
131   }
132   return 0;
133 }
134
135 int munmap(void* addr, size_t length) {
136   // Try to unmap it as a file, otherwise VirtualFree.
137   if (!UnmapViewOfFile(addr)) {
138     if (!VirtualFree(addr, length, MEM_RELEASE)) {
139       return -1;
140     }
141     return 0;
142   }
143   return 0;
144 }
145 }
146 #endif