From 8f76831a6491cf9d2ce3827563a2777d608019b1 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Thu, 15 Sep 2016 14:51:45 -0400 Subject: [PATCH] Port: Add mman.h compat for mingw MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Michael Jeanson Signed-off-by: Jérémie Galarneau --- cli/babeltrace-log.c | 2 +- compat/Makefile.am | 7 +- compat/compat_mman.c | 279 ++++++++++++++++++ include/babeltrace/compat/mman-internal.h | 28 +- .../ctf-writer/serialize-internal.h | 2 +- include/babeltrace/mmap-align-internal.h | 30 +- plugins/ctf/fs-src/data-stream-file.c | 2 +- plugins/ctf/lttng-live/data-stream.c | 2 +- 8 files changed, 343 insertions(+), 9 deletions(-) create mode 100644 compat/compat_mman.c diff --git a/cli/babeltrace-log.c b/cli/babeltrace-log.c index 27070fc5..a2d4884c 100644 --- a/cli/babeltrace-log.c +++ b/cli/babeltrace-log.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/compat/Makefile.am b/compat/Makefile.am index 33d49241..bf79838a 100644 --- a/compat/Makefile.am +++ b/compat/Makefile.am @@ -2,7 +2,12 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include noinst_LTLIBRARIES = libcompat.la -libcompat_la_SOURCES = compat_uuid.c +libcompat_la_SOURCES = compat_uuid.c \ + compat_mman.c libcompat_la_LDFLAGS = \ $(LD_NO_AS_NEEDED) + +if BABELTRACE_BUILD_WITH_MINGW +libcompat_la_LDFLAGS += -lrpcrt4 +endif diff --git a/compat/compat_mman.c b/compat/compat_mman.c new file mode 100644 index 00000000..813fac47 --- /dev/null +++ b/compat/compat_mman.c @@ -0,0 +1,279 @@ +/* + * compat/compat_mman.h + * + * Copyright (C) 2013 JP Ikaheimonen + * 2016 Michael Jeanson + * + * These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c + * file by Doug Lea, released to the public domain. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef __MINGW32__ + +#include +#include +#include +#include +#include +#include +#include + +struct mmap_info { + HANDLE file_handle; /* the duplicated handle */ + HANDLE map_handle; /* handle returned by CreateFileMapping */ + void *start; /* ptr returned by MapViewOfFile */ +}; + +/* + * This mutex protects the array of memory mappings and its associated + * counters. (mmap_infos, mmap_infos_cur mmap_infos_max) + */ +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; + +#define NEW_MMAP_STRUCT_CNT 10 + +static +void mmap_lock(void) +{ + if (pthread_mutex_lock(&mmap_mutex)) { + assert(0); + } +} + +static +void mmap_unlock(void) +{ + if (pthread_mutex_unlock(&mmap_mutex)) { + assert(0); + } +} + +/* + * Convert mmap memory protection flags to CreateFileMapping page protection + * flag and MapViewOfFile desired access flag. + */ +static +DWORD map_prot_flags(int prot, DWORD *dwDesiredAccess) +{ + if (prot & PROT_READ) { + if (prot & PROT_WRITE) { + *dwDesiredAccess = FILE_MAP_WRITE; + if (prot & PROT_EXEC) { + return PAGE_EXECUTE_READWRITE; + } + return PAGE_READWRITE; + } + if (prot & PROT_EXEC) { + *dwDesiredAccess = FILE_MAP_EXECUTE; + return PAGE_EXECUTE_READ; + } + *dwDesiredAccess = FILE_MAP_READ; + return PAGE_READONLY; + } + if (prot & PROT_WRITE) { + *dwDesiredAccess = FILE_MAP_COPY; + return PAGE_WRITECOPY; + } + if (prot & PROT_EXEC) { + *dwDesiredAccess = FILE_MAP_EXECUTE; + return PAGE_EXECUTE_READ; + } + + /* Mapping failed */ + *dwDesiredAccess = 0; + return 0; +} + +void *mmap(void *start, size_t length, int prot, int flags, int fd, + off_t offset) +{ + struct mmap_info mapping; + DWORD dwDesiredAccess; + DWORD flProtect; + HANDLE handle; + + /* Check for a valid fd */ + if (fd == -1) { + _set_errno(EBADF); + return MAP_FAILED; + } + + /* we don't support this atm */ + if (flags == MAP_FIXED) { + _set_errno(ENOTSUP); + return MAP_FAILED; + } + + /* Map mmap flags to windows API */ + flProtect = map_prot_flags(prot, &dwDesiredAccess); + if (flProtect == 0) { + _set_errno(EINVAL); + return MAP_FAILED; + } + + /* Get a handle from the fd */ + handle = (HANDLE) _get_osfhandle(fd); + + /* Duplicate the handle and store it in 'mapping.file_handle' */ + if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), + &mapping.file_handle, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + return MAP_FAILED; + } + + /* + * Create a file mapping object with a maximum size + * of 'offset' + 'length' + */ + mapping.map_handle = CreateFileMapping(mapping.file_handle, NULL, + flProtect, 0, offset + length, NULL); + if (mapping.map_handle == 0) { + if (!CloseHandle(mapping.file_handle)) { + assert(0); + } + _set_errno(EACCES); + return MAP_FAILED; + } + + /* Map the requested block starting at 'offset' for 'length' bytes */ + mapping.start = MapViewOfFile(mapping.map_handle, dwDesiredAccess, 0, + offset, length); + if (mapping.start == 0) { + DWORD dwLastErr = GetLastError(); + if (!CloseHandle(mapping.map_handle)) { + assert(0); + } + if (!CloseHandle(mapping.file_handle)) { + assert(0); + } + + if (dwLastErr == ERROR_MAPPED_ALIGNMENT) { + _set_errno(EINVAL); + } else { + _set_errno(EACCES); + } + + return MAP_FAILED; + } + + 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; + 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 array */ + memcpy(&mmap_infos[mmap_infos_cur], &mapping, + sizeof(struct mmap_info)); + mmap_infos_cur++; + + mmap_unlock(); + + return mapping.start; + +error_mutex_unlock: + mmap_unlock(); + + if (!CloseHandle(mapping.map_handle)) { + assert(0); + } + if (!CloseHandle(mapping.file_handle)) { + assert(0); + } + + _set_errno(ENOMEM); + return MAP_FAILED; +} + +int munmap(void *start, size_t length) +{ + int i, j; + + /* Find the mapping to unmap */ + for (i = 0; i < mmap_infos_cur; i++) { + if (mmap_infos[i].start == start) + break; + } + + /* Mapping was not found */ + if (i == mmap_infos_cur) { + _set_errno(EINVAL); + return -1; + } + + /* Cleanup of handles should never fail */ + if (!UnmapViewOfFile(mmap_infos[i].start)) { + assert(0); + } + if (!CloseHandle(mmap_infos[i].map_handle)) { + assert(0); + } + if (!CloseHandle(mmap_infos[i].file_handle)) { + assert(0); + } + + 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; + } + + mmap_unlock(); + + return 0; +} + +#endif diff --git a/include/babeltrace/compat/mman-internal.h b/include/babeltrace/compat/mman-internal.h index 061e244b..6d9fa926 100644 --- a/include/babeltrace/compat/mman-internal.h +++ b/include/babeltrace/compat/mman-internal.h @@ -4,7 +4,7 @@ /* * babeltrace/compat/mman.h * - * Copyright (C) 2015 Michael Jeanson + * Copyright (C) 2015-2016 Michael Jeanson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,8 +25,34 @@ * SOFTWARE. */ +#ifndef __MINGW32__ + #include +#else /* __MINGW32__ */ + +#include + +#define PROT_NONE 0x0 +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define PROT_EXEC 0x4 + +#define MAP_FILE 0 +#define MAP_SHARED 1 +#define MAP_PRIVATE 2 +#define MAP_TYPE 0xF +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + off_t offset); +int munmap(void *addr, size_t length); + +#endif /* __MINGW32__ */ + #ifndef MAP_ANONYMOUS # ifdef MAP_ANON # define MAP_ANONYMOUS MAP_ANON diff --git a/include/babeltrace/ctf-writer/serialize-internal.h b/include/babeltrace/ctf-writer/serialize-internal.h index e029764e..b0ef6cb9 100644 --- a/include/babeltrace/ctf-writer/serialize-internal.h +++ b/include/babeltrace/ctf-writer/serialize-internal.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/babeltrace/mmap-align-internal.h b/include/babeltrace/mmap-align-internal.h index 0667ab0c..e87f4a98 100644 --- a/include/babeltrace/mmap-align-internal.h +++ b/include/babeltrace/mmap-align-internal.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include /* @@ -48,6 +48,30 @@ struct mmap_align { size_t length; /* virtual mmap length */ }; +#ifdef __WIN32__ +#include + +/* + * On windows the memory mapping offset must be aligned to the memory + * allocator allocation granularity and not the page size. + */ +static inline +off_t get_page_aligned_offset(off_t offset, size_t page_size) +{ + SYSTEM_INFO sysinfo; + + GetNativeSystemInfo(&sysinfo); + + return ALIGN_FLOOR(offset, sysinfo.dwAllocationGranularity); +} +#else +static inline +off_t get_page_aligned_offset(off_t offset, size_t page_size) +{ + return ALIGN_FLOOR(offset, page_size); +} +#endif + static inline struct mmap_align *mmap_align(size_t length, int prot, int flags, int fd, off_t offset) @@ -62,7 +86,7 @@ struct mmap_align *mmap_align(size_t length, int prot, if (!mma) return MAP_FAILED; mma->length = length; - page_aligned_offset = ALIGN_FLOOR(offset, page_size); + page_aligned_offset = get_page_aligned_offset(offset, page_size); /* * Page aligned length needs to contain the requested range. * E.g., for a small range that fits within a single page, we might @@ -72,7 +96,7 @@ struct mmap_align *mmap_align(size_t length, int prot, mma->page_aligned_length = ALIGN(length + offset - page_aligned_offset, page_size); mma->page_aligned_addr = mmap(NULL, mma->page_aligned_length, prot, flags, fd, page_aligned_offset); - if (mma->page_aligned_addr == (void *) -1UL) { + if (mma->page_aligned_addr == MAP_FAILED) { free(mma); return MAP_FAILED; } diff --git a/plugins/ctf/fs-src/data-stream-file.c b/plugins/ctf/fs-src/data-stream-file.c index 94f2b9b3..4d264203 100644 --- a/plugins/ctf/fs-src/data-stream-file.c +++ b/plugins/ctf/fs-src/data-stream-file.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/plugins/ctf/lttng-live/data-stream.c b/plugins/ctf/lttng-live/data-stream.c index 5669b614..810c93aa 100644 --- a/plugins/ctf/lttng-live/data-stream.c +++ b/plugins/ctf/lttng-live/data-stream.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include "../common/notif-iter/notif-iter.h" #include -- 2.34.1