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