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