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