de1d7b34a4d9bf5b07a39e0a7f28bb8fcd4922f3
[babeltrace.git] / src / compat / mman.c
1 /*
2 * compat/compat_mman.h
3 *
4 * Copyright (C) 2013 JP Ikaheimonen <jp_ikaheimonen@mentor.com>
5 * 2016 Michael Jeanson <mjeanson@efficios.com>
6 *
7 * These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c
8 * file by Doug Lea, released to the public domain.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #define BT_LOG_OUTPUT_LEVEL (mapping->log_level)
30 #define BT_LOG_TAG "COMPAT/MMAN"
31 #include "logging/log.h"
32
33 #include "common/macros.h"
34
35 #ifdef __APPLE__
36 /*
37 * On macOS, we need a dummy symbol so that the linker won't
38 * complain of an empty table of contents.
39 */
40 BT_HIDDEN
41 int bt_mman_dummy_symbol;
42 #endif /* __APPLE__ */
43
44 #ifdef __MINGW32__
45
46 #include <errno.h>
47 #include <glib.h>
48 #include <io.h>
49 #include <pthread.h>
50 #include <stdlib.h>
51 #include <windows.h>
52
53 #include "compat/mman.h"
54
55 struct mmap_mapping {
56 int log_level;
57
58 /* The duplicated handle. */
59 HANDLE file_handle;
60 /* Handle returned by CreateFileMapping. */
61 HANDLE map_handle;
62 };
63
64 static
65 GHashTable *mmap_mappings = NULL;
66
67 /*
68 * This mutex protects the hashtable of memory mappings.
69 */
70 static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
71
72 static
73 struct mmap_mapping *mapping_create(void)
74 {
75 struct mmap_mapping *mapping;
76
77 mapping = malloc(sizeof(struct mmap_mapping));
78 if (mapping != NULL) {
79 mapping->file_handle = NULL;
80 mapping->map_handle = NULL;
81 }
82
83 return mapping;
84 }
85
86 static
87 void mapping_clean(struct mmap_mapping *mapping)
88 {
89 if (mapping) {
90 if (!CloseHandle(mapping->map_handle)) {
91 BT_LOGF_STR("Failed to close mmap map_handle.");
92 abort();
93 }
94 if (!CloseHandle(mapping->file_handle)) {
95 BT_LOGF_STR("Failed to close mmap file_handle.");
96 abort();
97 }
98 free(mapping);
99 mapping = NULL;
100 }
101 }
102
103 static
104 void addr_clean(void *addr)
105 {
106 /* Cleanup of handles should never fail. */
107 if (!UnmapViewOfFile(addr)) {
108 /*
109 * FIXME: We don't have access to the mapping's log
110 * level here, so force a FATAL level.
111 */
112 BT_LOG_WRITE_CUR_LVL(BT_LOG_FATAL, BT_LOG_FATAL, BT_LOG_TAG,
113 "Failed to unmap mmap mapping.");
114 abort();
115 }
116 }
117
118 static
119 void mmap_lock(int log_level)
120 {
121 if (pthread_mutex_lock(&mmap_mutex)) {
122 BT_LOGF_STR("Failed to acquire mmap_mutex.");
123 abort();
124 }
125 }
126
127 static
128 void mmap_unlock(int log_level)
129 {
130 if (pthread_mutex_unlock(&mmap_mutex)) {
131 BT_LOGF_STR("Failed to release mmap_mutex.");
132 abort();
133 }
134 }
135
136 /*
137 * Convert mmap memory protection flags to CreateFileMapping page protection
138 * flag and MapViewOfFile desired access flag.
139 */
140 static
141 DWORD map_prot_flags(int prot, DWORD *dwDesiredAccess)
142 {
143 if (prot & PROT_READ) {
144 if (prot & PROT_WRITE) {
145 *dwDesiredAccess = FILE_MAP_WRITE;
146 if (prot & PROT_EXEC) {
147 return PAGE_EXECUTE_READWRITE;
148 }
149 return PAGE_READWRITE;
150 }
151 if (prot & PROT_EXEC) {
152 *dwDesiredAccess = FILE_MAP_EXECUTE;
153 return PAGE_EXECUTE_READ;
154 }
155 *dwDesiredAccess = FILE_MAP_READ;
156 return PAGE_READONLY;
157 }
158 if (prot & PROT_WRITE) {
159 *dwDesiredAccess = FILE_MAP_COPY;
160 return PAGE_WRITECOPY;
161 }
162 if (prot & PROT_EXEC) {
163 *dwDesiredAccess = FILE_MAP_EXECUTE;
164 return PAGE_EXECUTE_READ;
165 }
166
167 /* Mapping failed. */
168 *dwDesiredAccess = 0;
169 return 0;
170 }
171
172 BT_HIDDEN
173 void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
174 off_t offset, int log_level)
175 {
176 struct mmap_mapping *mapping = NULL;
177 void *mapping_addr;
178 DWORD dwDesiredAccess;
179 DWORD flProtect;
180 HANDLE handle;
181
182 /* Check for a valid fd. */
183 if (fd == -1) {
184 _set_errno(EBADF);
185 goto error;
186 }
187
188 /* We don't support this at the moment. */
189 if (flags == MAP_FIXED) {
190 _set_errno(ENOTSUP);
191 goto error;
192 }
193
194 /* Map mmap flags to those of the Windows API. */
195 flProtect = map_prot_flags(prot, &dwDesiredAccess);
196 if (flProtect == 0) {
197 _set_errno(EINVAL);
198 goto error;
199 }
200
201 /* Allocate the mapping struct. */
202 mapping = mapping_create(log_level);
203 if (!mapping) {
204 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG,
205 "Failed to allocate mmap mapping.");
206 _set_errno(ENOMEM);
207 goto error;
208 }
209
210 /* Get a handle from the fd. */
211 handle = (HANDLE) _get_osfhandle(fd);
212
213 /* Duplicate the handle and store it in 'mapping.file_handle'. */
214 if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
215 &mapping->file_handle, 0, FALSE,
216 DUPLICATE_SAME_ACCESS)) {
217 _set_errno(ENOMEM);
218 goto error;
219 }
220
221 /*
222 * Create a file mapping object with a maximum size
223 * of 'offset' + 'length'.
224 */
225 mapping->map_handle = CreateFileMapping(mapping->file_handle, NULL,
226 flProtect, 0, offset + length, NULL);
227 if (mapping->map_handle == 0) {
228 _set_errno(EACCES);
229 goto error;
230 }
231
232 /* Map the requested block starting at 'offset' for 'length' bytes. */
233 mapping_addr = MapViewOfFile(mapping->map_handle, dwDesiredAccess, 0,
234 offset, length);
235 if (mapping_addr == 0) {
236 DWORD dwLastErr = GetLastError();
237 if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
238 _set_errno(EINVAL);
239 } else {
240 _set_errno(EACCES);
241 }
242 goto error;
243 }
244
245 mmap_lock(log_level);
246
247 /* If we have never done any mappings, allocate the hashtable. */
248 if (!mmap_mappings) {
249 mmap_mappings = g_hash_table_new_full(g_direct_hash,
250 g_direct_equal, (GDestroyNotify) addr_clean,
251 (GDestroyNotify) mapping_clean);
252 if (!mmap_mappings) {
253 BT_LOGE_STR("Failed to allocate mmap hashtable.");
254 _set_errno(ENOMEM);
255 goto error_mutex_unlock;
256 }
257 }
258
259 /* Add the new mapping to the hashtable. */
260 g_hash_table_insert(mmap_mappings, mapping_addr, mapping);
261
262 mmap_unlock(log_level);
263
264 return mapping_addr;
265
266 error_mutex_unlock:
267 mmap_unlock(log_level);
268 error:
269 mapping_clean(mapping);
270 return MAP_FAILED;
271 }
272
273 BT_HIDDEN
274 int bt_munmap(void *addr, size_t length)
275 {
276 int ret = 0;
277 struct mmap_mapping *mapping = addr;
278 int log_level;
279
280 BT_ASSERT(mapping);
281 log_level = mapping->log_level;
282 mmap_lock(log_level);
283
284 /* Check if the mapping exists in the hashtable. */
285 if (g_hash_table_lookup(mmap_mappings, addr) == NULL) {
286 _set_errno(EINVAL);
287 ret = -1;
288 goto end;
289 }
290
291 /* Remove it. */
292 if (!g_hash_table_remove(mmap_mappings, addr)) {
293 BT_LOGF_STR("Failed to remove mapping from hashtable.");
294 abort();
295 }
296
297 end:
298 mmap_unlock(log_level);
299 return ret;
300 }
301
302 #endif
This page took 0.034511 seconds and 3 git commands to generate.