Cleanup: remove private babeltrace.h
[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_TAG "COMPAT-MMAN"
30 #include "logging.h"
31
32 #include "common/macros.h"
33
34 #ifdef __APPLE__
35 /*
36 * On macOS, we need a dummy symbol so that the linker won't
37 * complain of an empty table of contents.
38 */
39 BT_HIDDEN
40 int bt_mman_dummy_symbol;
41 #endif /* __APPLE__ */
42
43 #ifdef __MINGW32__
44
45 #include <errno.h>
46 #include <io.h>
47 #include <pthread.h>
48 #include <stdlib.h>
49 #include <windows.h>
50 #include "compat/mman.h"
51
52 struct mmap_mapping {
53 /* The duplicated handle. */
54 HANDLE file_handle;
55 /* Handle returned by CreateFileMapping. */
56 HANDLE map_handle;
57 };
58
59 static
60 GHashTable *mmap_mappings = NULL;
61
62 /*
63 * This mutex protects the hashtable of memory mappings.
64 */
65 static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
66
67 static
68 struct mmap_mapping *mapping_create(void)
69 {
70 struct mmap_mapping *mapping;
71
72 mapping = malloc(sizeof(struct mmap_mapping));
73 if (mapping != NULL) {
74 mapping->file_handle = NULL;
75 mapping->map_handle = NULL;
76 }
77
78 return mapping;
79 }
80
81 static
82 void mapping_clean(struct mmap_mapping *mapping)
83 {
84 if (mapping) {
85 if (!CloseHandle(mapping->map_handle)) {
86 BT_LOGF_STR("Failed to close mmap map_handle.");
87 abort();
88 }
89 if (!CloseHandle(mapping->file_handle)) {
90 BT_LOGF_STR("Failed to close mmap file_handle.");
91 abort();
92 }
93 free(mapping);
94 mapping = NULL;
95 }
96 }
97
98 static
99 void addr_clean(void *addr)
100 {
101 /* Cleanup of handles should never fail. */
102 if (!UnmapViewOfFile(addr)) {
103 BT_LOGF_STR("Failed to unmap mmap mapping.");
104 abort();
105 }
106 }
107
108 static
109 void mmap_lock(void)
110 {
111 if (pthread_mutex_lock(&mmap_mutex)) {
112 BT_LOGF_STR("Failed to acquire mmap_mutex.");
113 abort();
114 }
115 }
116
117 static
118 void mmap_unlock(void)
119 {
120 if (pthread_mutex_unlock(&mmap_mutex)) {
121 BT_LOGF_STR("Failed to release mmap_mutex.");
122 abort();
123 }
124 }
125
126 /*
127 * Convert mmap memory protection flags to CreateFileMapping page protection
128 * flag and MapViewOfFile desired access flag.
129 */
130 static
131 DWORD map_prot_flags(int prot, DWORD *dwDesiredAccess)
132 {
133 if (prot & PROT_READ) {
134 if (prot & PROT_WRITE) {
135 *dwDesiredAccess = FILE_MAP_WRITE;
136 if (prot & PROT_EXEC) {
137 return PAGE_EXECUTE_READWRITE;
138 }
139 return PAGE_READWRITE;
140 }
141 if (prot & PROT_EXEC) {
142 *dwDesiredAccess = FILE_MAP_EXECUTE;
143 return PAGE_EXECUTE_READ;
144 }
145 *dwDesiredAccess = FILE_MAP_READ;
146 return PAGE_READONLY;
147 }
148 if (prot & PROT_WRITE) {
149 *dwDesiredAccess = FILE_MAP_COPY;
150 return PAGE_WRITECOPY;
151 }
152 if (prot & PROT_EXEC) {
153 *dwDesiredAccess = FILE_MAP_EXECUTE;
154 return PAGE_EXECUTE_READ;
155 }
156
157 /* Mapping failed. */
158 *dwDesiredAccess = 0;
159 return 0;
160 }
161
162 BT_HIDDEN
163 void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
164 off_t offset)
165 {
166 struct mmap_mapping *mapping = NULL;
167 void *mapping_addr;
168 DWORD dwDesiredAccess;
169 DWORD flProtect;
170 HANDLE handle;
171
172 /* Check for a valid fd. */
173 if (fd == -1) {
174 _set_errno(EBADF);
175 goto error;
176 }
177
178 /* We don't support this at the moment. */
179 if (flags == MAP_FIXED) {
180 _set_errno(ENOTSUP);
181 goto error;
182 }
183
184 /* Map mmap flags to those of the Windows API. */
185 flProtect = map_prot_flags(prot, &dwDesiredAccess);
186 if (flProtect == 0) {
187 _set_errno(EINVAL);
188 goto error;
189 }
190
191 /* Allocate the mapping struct. */
192 mapping = mapping_create();
193 if (!mapping) {
194 BT_LOGE_STR("Failed to allocate mmap mapping.");
195 _set_errno(ENOMEM);
196 goto error;
197 }
198
199 /* Get a handle from the fd. */
200 handle = (HANDLE) _get_osfhandle(fd);
201
202 /* Duplicate the handle and store it in 'mapping.file_handle'. */
203 if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
204 &mapping->file_handle, 0, FALSE,
205 DUPLICATE_SAME_ACCESS)) {
206 _set_errno(ENOMEM);
207 goto error;
208 }
209
210 /*
211 * Create a file mapping object with a maximum size
212 * of 'offset' + 'length'.
213 */
214 mapping->map_handle = CreateFileMapping(mapping->file_handle, NULL,
215 flProtect, 0, offset + length, NULL);
216 if (mapping->map_handle == 0) {
217 _set_errno(EACCES);
218 goto error;
219 }
220
221 /* Map the requested block starting at 'offset' for 'length' bytes. */
222 mapping_addr = MapViewOfFile(mapping->map_handle, dwDesiredAccess, 0,
223 offset, length);
224 if (mapping_addr == 0) {
225 DWORD dwLastErr = GetLastError();
226 if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
227 _set_errno(EINVAL);
228 } else {
229 _set_errno(EACCES);
230 }
231 goto error;
232 }
233
234 mmap_lock();
235
236 /* If we have never done any mappings, allocate the hashtable. */
237 if (!mmap_mappings) {
238 mmap_mappings = g_hash_table_new_full(g_direct_hash,
239 g_direct_equal, (GDestroyNotify) addr_clean,
240 (GDestroyNotify) mapping_clean);
241 if (!mmap_mappings) {
242 BT_LOGE_STR("Failed to allocate mmap hashtable.");
243 _set_errno(ENOMEM);
244 goto error_mutex_unlock;
245 }
246 }
247
248 /* Add the new mapping to the hashtable. */
249 g_hash_table_insert(mmap_mappings, mapping_addr, mapping);
250
251 mmap_unlock();
252
253 return mapping_addr;
254
255 error_mutex_unlock:
256 mmap_unlock();
257 error:
258 mapping_clean(mapping);
259 return MAP_FAILED;
260 }
261
262 BT_HIDDEN
263 int bt_munmap(void *addr, size_t length)
264 {
265 int ret = 0;
266
267 mmap_lock();
268
269 /* Check if the mapping exists in the hashtable. */
270 if (g_hash_table_lookup(mmap_mappings, addr) == NULL) {
271 _set_errno(EINVAL);
272 ret = -1;
273 goto end;
274 }
275
276 /* Remove it. */
277 if (!g_hash_table_remove(mmap_mappings, addr)) {
278 BT_LOGF_STR("Failed to remove mapping from hashtable.");
279 abort();
280 }
281
282 end:
283 mmap_unlock();
284 return ret;
285 }
286
287 #endif
This page took 0.03476 seconds and 4 git commands to generate.