#define BT_LOG_TAG "COMPAT-MMAN"
#include "logging.h"
+#ifdef __APPLE__
+/*
+ * On macOS, we need a dummy symbol so that the linker won't
+ * complain of an empty table of contents.
+ */
+BT_HIDDEN
+int bt_mman_dummy_symbol;
+#endif /* __APPLE__ */
+
#ifdef __MINGW32__
-#include <assert.h>
#include <errno.h>
#include <io.h>
#include <pthread.h>
#include <windows.h>
#include <babeltrace/compat/mman-internal.h>
-struct mmap_info {
- HANDLE file_handle; /* the duplicated handle */
- HANDLE map_handle; /* handle returned by CreateFileMapping */
- void *start; /* ptr returned by MapViewOfFile */
+struct mmap_mapping {
+ /* The duplicated handle. */
+ HANDLE file_handle;
+ /* Handle returned by CreateFileMapping. */
+ HANDLE map_handle;
};
+static
+GHashTable *mmap_mappings = NULL;
+
/*
- * This mutex protects the array of memory mappings and its associated
- * counters. (mmap_infos, mmap_infos_cur mmap_infos_max)
+ * This mutex protects the hashtable of memory mappings.
*/
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
-static int mmap_infos_cur = 0;
-static int mmap_infos_max = 0;
-static struct mmap_info *mmap_infos = NULL;
+static
+struct mmap_mapping *mapping_create(void)
+{
+ struct mmap_mapping *mapping;
+
+ mapping = malloc(sizeof(struct mmap_mapping));
+ if (mapping != NULL) {
+ mapping->file_handle = NULL;
+ mapping->map_handle = NULL;
+ }
+
+ return mapping;
+}
+
+static
+void mapping_clean(struct mmap_mapping *mapping)
+{
+ if (mapping) {
+ if (!CloseHandle(mapping->map_handle)) {
+ BT_LOGF_STR("Failed to close mmap map_handle.");
+ abort();
+ }
+ if (!CloseHandle(mapping->file_handle)) {
+ BT_LOGF_STR("Failed to close mmap file_handle.");
+ abort();
+ }
+ free(mapping);
+ mapping = NULL;
+ }
+}
-#define NEW_MMAP_STRUCT_CNT 10
+static
+void addr_clean(void *addr)
+{
+ /* Cleanup of handles should never fail. */
+ if (!UnmapViewOfFile(addr)) {
+ BT_LOGF_STR("Failed to unmap mmap mapping.");
+ abort();
+ }
+}
static
void mmap_lock(void)
{
if (pthread_mutex_lock(&mmap_mutex)) {
+ BT_LOGF_STR("Failed to acquire mmap_mutex.");
abort();
}
}
void mmap_unlock(void)
{
if (pthread_mutex_unlock(&mmap_mutex)) {
+ BT_LOGF_STR("Failed to release mmap_mutex.");
abort();
}
}
return PAGE_EXECUTE_READ;
}
- /* Mapping failed */
+ /* Mapping failed. */
*dwDesiredAccess = 0;
return 0;
}
-void *mmap(void *start, size_t length, int prot, int flags, int fd,
+BT_HIDDEN
+void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset)
{
- struct mmap_info mapping;
+ struct mmap_mapping *mapping = NULL;
+ void *mapping_addr;
DWORD dwDesiredAccess;
DWORD flProtect;
HANDLE handle;
- /* Check for a valid fd */
+ /* Check for a valid fd. */
if (fd == -1) {
_set_errno(EBADF);
- return MAP_FAILED;
+ goto error;
}
- /* we don't support this atm */
+ /* We don't support this at the moment. */
if (flags == MAP_FIXED) {
_set_errno(ENOTSUP);
- return MAP_FAILED;
+ goto error;
}
- /* Map mmap flags to windows API */
+ /* Map mmap flags to those of the Windows API. */
flProtect = map_prot_flags(prot, &dwDesiredAccess);
if (flProtect == 0) {
_set_errno(EINVAL);
- return MAP_FAILED;
+ goto error;
+ }
+
+ /* Allocate the mapping struct. */
+ mapping = mapping_create();
+ if (!mapping) {
+ BT_LOGE_STR("Failed to allocate mmap mapping.");
+ _set_errno(ENOMEM);
+ goto error;
}
- /* Get a handle from the fd */
+ /* Get a handle from the fd. */
handle = (HANDLE) _get_osfhandle(fd);
- /* Duplicate the handle and store it in 'mapping.file_handle' */
+ /* Duplicate the handle and store it in 'mapping.file_handle'. */
if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
- &mapping.file_handle, 0, FALSE,
+ &mapping->file_handle, 0, FALSE,
DUPLICATE_SAME_ACCESS)) {
- return MAP_FAILED;
+ _set_errno(ENOMEM);
+ goto error;
}
/*
* Create a file mapping object with a maximum size
- * of 'offset' + 'length'
+ * of 'offset' + 'length'.
*/
- mapping.map_handle = CreateFileMapping(mapping.file_handle, NULL,
+ mapping->map_handle = CreateFileMapping(mapping->file_handle, NULL,
flProtect, 0, offset + length, NULL);
- if (mapping.map_handle == 0) {
- if (!CloseHandle(mapping.file_handle)) {
- abort();
- }
+ if (mapping->map_handle == 0) {
_set_errno(EACCES);
- return MAP_FAILED;
+ goto error;
}
- /* Map the requested block starting at 'offset' for 'length' bytes */
- mapping.start = MapViewOfFile(mapping.map_handle, dwDesiredAccess, 0,
+ /* Map the requested block starting at 'offset' for 'length' bytes. */
+ mapping_addr = MapViewOfFile(mapping->map_handle, dwDesiredAccess, 0,
offset, length);
- if (mapping.start == 0) {
+ if (mapping_addr == 0) {
DWORD dwLastErr = GetLastError();
- if (!CloseHandle(mapping.map_handle)) {
- abort();
- }
- if (!CloseHandle(mapping.file_handle)) {
- abort();
- }
-
if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
_set_errno(EINVAL);
} else {
_set_errno(EACCES);
}
-
- return MAP_FAILED;
+ goto error;
}
mmap_lock();
- /* If we have never done any mappings, allocate the array */
- if (mmap_infos == NULL) {
- mmap_infos_max = NEW_MMAP_STRUCT_CNT;
- mmap_infos = (struct mmap_info *) calloc(mmap_infos_max,
- sizeof(struct mmap_info));
- if (mmap_infos == NULL) {
- mmap_infos_max = 0;
+ /* If we have never done any mappings, allocate the hashtable. */
+ if (!mmap_mappings) {
+ mmap_mappings = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, (GDestroyNotify) addr_clean,
+ (GDestroyNotify) mapping_clean);
+ if (!mmap_mappings) {
+ BT_LOGE_STR("Failed to allocate mmap hashtable.");
+ _set_errno(ENOMEM);
goto error_mutex_unlock;
}
}
- /* if we have reached our current mapping limit, expand it */
- if (mmap_infos_cur == mmap_infos_max) {
- struct mmap_info *realloc_mmap_infos = NULL;
-
- mmap_infos_max += NEW_MMAP_STRUCT_CNT;
- realloc_mmap_infos = (struct mmap_info *) realloc(mmap_infos,
- mmap_infos_max * sizeof(struct mmap_info));
- if (realloc_mmap_infos == NULL) {
- mmap_infos_max -= NEW_MMAP_STRUCT_CNT;
- goto error_mutex_unlock;
- }
- mmap_infos = realloc_mmap_infos;
+ /* Add the new mapping to the hashtable. */
+ if (!g_hash_table_insert(mmap_mappings, mapping_addr, mapping)) {
+ BT_LOGF_STR("Failed to insert mapping in the hashtable.");
+ abort();
}
- /* Add the new mapping to the array */
- memcpy(&mmap_infos[mmap_infos_cur], &mapping,
- sizeof(struct mmap_info));
- mmap_infos_cur++;
-
mmap_unlock();
- return mapping.start;
+ return mapping_addr;
error_mutex_unlock:
mmap_unlock();
-
- if (!CloseHandle(mapping.map_handle)) {
- abort();
- }
- if (!CloseHandle(mapping.file_handle)) {
- abort();
- }
-
- _set_errno(ENOMEM);
+error:
+ mapping_clean(mapping);
return MAP_FAILED;
}
-int munmap(void *start, size_t length)
+BT_HIDDEN
+int bt_munmap(void *addr, size_t length)
{
- int i, j;
+ int ret = 0;
- /* Find the mapping to unmap */
- for (i = 0; i < mmap_infos_cur; i++) {
- if (mmap_infos[i].start == start)
- break;
- }
+ mmap_lock();
- /* Mapping was not found */
- if (i == mmap_infos_cur) {
+ /* Check if the mapping exists in the hashtable. */
+ if (g_hash_table_lookup(mmap_mappings, addr) == NULL) {
_set_errno(EINVAL);
- return -1;
+ ret = -1;
+ goto end;
}
- /* Cleanup of handles should never fail */
- if (!UnmapViewOfFile(mmap_infos[i].start)) {
- abort();
- }
- if (!CloseHandle(mmap_infos[i].map_handle)) {
- abort();
- }
- if (!CloseHandle(mmap_infos[i].file_handle)) {
+ /* Remove it. */
+ if (!g_hash_table_remove(mmap_mappings, addr)) {
+ BT_LOGF_STR("Failed to remove mapping from hashtable.");
abort();
}
- mmap_lock();
-
- /* Clean the mapping list */
- for (j = i + 1; j < mmap_infos_cur; j++) {
- memcpy(&mmap_infos[j - 1], &mmap_infos[j],
- sizeof(struct mmap_info));
- }
- mmap_infos_cur--;
-
- /* If the mapping list is now empty, free it */
- if (mmap_infos_cur == 0) {
- free(mmap_infos);
- mmap_infos = NULL;
- mmap_infos_max = 0;
- }
-
+end:
mmap_unlock();
-
- return 0;
+ return ret;
}
#endif