2 * SPDX-License-Identifier: MIT
4 * Copyright (C) 2013 JP Ikaheimonen <jp_ikaheimonen@mentor.com>
5 * Copyright (C) 2016 Michael Jeanson <mjeanson@efficios.com>
7 * These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c
8 * file by Doug Lea, released to the public domain.
11 #define BT_LOG_OUTPUT_LEVEL (mapping->log_level)
12 #define BT_LOG_TAG "COMPAT/MMAN"
13 #include "logging/log.h"
15 #include "common/macros.h"
16 #include "common/common.h"
20 * On macOS, we need a dummy symbol so that the linker won't
21 * complain of an empty table of contents.
23 int bt_mman_dummy_symbol
;
24 #endif /* __APPLE__ */
35 #include "compat/mman.h"
40 /* The duplicated handle. */
42 /* Handle returned by CreateFileMapping. */
47 GHashTable
*mmap_mappings
= NULL
;
50 * This mutex protects the hashtable of memory mappings.
52 static pthread_mutex_t mmap_mutex
= PTHREAD_MUTEX_INITIALIZER
;
55 struct mmap_mapping
*mapping_create(int log_level
)
57 struct mmap_mapping
*mapping
;
59 mapping
= malloc(sizeof(struct mmap_mapping
));
61 mapping
->file_handle
= NULL
;
62 mapping
->map_handle
= NULL
;
63 mapping
->log_level
= log_level
;
70 void mapping_clean(struct mmap_mapping
*mapping
)
73 if (!CloseHandle(mapping
->map_handle
)) {
74 BT_LOGF_STR("Failed to close mmap map_handle.");
77 if (!CloseHandle(mapping
->file_handle
)) {
78 BT_LOGF_STR("Failed to close mmap file_handle.");
87 void addr_clean(void *addr
)
89 /* Cleanup of handles should never fail. */
90 if (!UnmapViewOfFile(addr
)) {
92 * FIXME: We don't have access to the mapping's log
93 * level here, so force a FATAL level.
95 BT_LOG_WRITE_CUR_LVL(BT_LOG_FATAL
, BT_LOG_FATAL
, BT_LOG_TAG
,
96 "Failed to unmap mmap mapping.");
102 void mmap_lock(int log_level
)
104 if (pthread_mutex_lock(&mmap_mutex
)) {
105 BT_LOG_WRITE_CUR_LVL(BT_LOG_FATAL
, log_level
, BT_LOG_TAG
, "Failed to acquire mmap_mutex.");
111 void mmap_unlock(int log_level
)
113 if (pthread_mutex_unlock(&mmap_mutex
)) {
114 BT_LOG_WRITE_CUR_LVL(BT_LOG_FATAL
, log_level
, BT_LOG_TAG
, "Failed to release mmap_mutex.");
120 * Convert mmap memory protection flags to CreateFileMapping page protection
121 * flag and MapViewOfFile desired access flag.
124 DWORD
map_prot_flags(int prot
, DWORD
*dwDesiredAccess
)
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
;
132 return PAGE_READWRITE
;
134 if (prot
& PROT_EXEC
) {
135 *dwDesiredAccess
= FILE_MAP_EXECUTE
;
136 return PAGE_EXECUTE_READ
;
138 *dwDesiredAccess
= FILE_MAP_READ
;
139 return PAGE_READONLY
;
141 if (prot
& PROT_WRITE
) {
142 *dwDesiredAccess
= FILE_MAP_COPY
;
143 return PAGE_WRITECOPY
;
145 if (prot
& PROT_EXEC
) {
146 *dwDesiredAccess
= FILE_MAP_EXECUTE
;
147 return PAGE_EXECUTE_READ
;
150 /* Mapping failed. */
151 *dwDesiredAccess
= 0;
155 void *bt_mmap(size_t length
, int prot
, int flags
, int fd
, off_t offset
,
158 struct mmap_mapping
*mapping
= NULL
;
160 DWORD dwDesiredAccess
;
164 /* Check for a valid fd. */
170 /* We don't support this at the moment. */
171 if (flags
== MAP_FIXED
) {
176 /* Map mmap flags to those of the Windows API. */
177 flProtect
= map_prot_flags(prot
, &dwDesiredAccess
);
178 if (flProtect
== 0) {
183 /* Allocate the mapping struct. */
184 mapping
= mapping_create(log_level
);
186 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
187 "Failed to allocate mmap mapping.");
192 /* Get a handle from the fd. */
193 handle
= (HANDLE
) _get_osfhandle(fd
);
195 /* Duplicate the handle and store it in 'mapping.file_handle'. */
196 if (!DuplicateHandle(GetCurrentProcess(), handle
, GetCurrentProcess(),
197 &mapping
->file_handle
, 0, FALSE
,
198 DUPLICATE_SAME_ACCESS
)) {
204 * Create a file mapping object with a maximum size
205 * of 'offset' + 'length'.
207 mapping
->map_handle
= CreateFileMapping(mapping
->file_handle
, NULL
,
208 flProtect
, 0, offset
+ length
, NULL
);
209 if (mapping
->map_handle
== 0) {
214 /* Map the requested block starting at 'offset' for 'length' bytes. */
215 mapping_addr
= MapViewOfFile(mapping
->map_handle
, dwDesiredAccess
, 0,
217 if (mapping_addr
== 0) {
218 DWORD dwLastErr
= GetLastError();
219 if (dwLastErr
== ERROR_MAPPED_ALIGNMENT
) {
227 mmap_lock(log_level
);
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.");
237 goto error_mutex_unlock
;
241 /* Add the new mapping to the hashtable. */
242 g_hash_table_insert(mmap_mappings
, mapping_addr
, mapping
);
244 mmap_unlock(log_level
);
249 mmap_unlock(log_level
);
251 mapping_clean(mapping
);
255 int bt_munmap(void *addr
, size_t length
__attribute__((unused
)))
258 struct mmap_mapping
*mapping
= addr
;
262 log_level
= mapping
->log_level
;
263 mmap_lock(log_level
);
265 /* Check if the mapping exists in the hashtable. */
266 if (!g_hash_table_lookup(mmap_mappings
, addr
)) {
273 if (!g_hash_table_remove(mmap_mappings
, addr
)) {
274 BT_LOGF_STR("Failed to remove mapping from hashtable.");
279 mmap_unlock(log_level
);
283 size_t bt_mmap_get_offset_align_size(int log_level
)
287 GetNativeSystemInfo(&sysinfo
);
288 BT_LOG_WRITE_PRINTF_CUR_LVL(BT_LOG_DEBUG
, log_level
, BT_LOG_TAG
,
289 "Allocator granularity is %lu.",
290 sysinfo
.dwAllocationGranularity
);
292 return sysinfo
.dwAllocationGranularity
;