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