diff --git a/server/win32/mmap-win32.c b/server/win32/mmap-win32.c new file mode 100644 index 0000000..cc7f222 --- /dev/null +++ b/server/win32/mmap-win32.c @@ -0,0 +1,165 @@ +/* +* Copyright (c) 2014, Newcastle University, UK. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +// Memory mapped file - Implementation of mmap() for Windows +// Dan Jackson, 2014 - 'MMAP_CLEANUP' changes to clean up otherwise leaked handles from CreateFileMapping() +// Original author: Mike Frysinger , placed into the public domain. + +// References: +// CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx +// CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx +// MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx +// UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + +#define MMAP_CLEANUP // Dan + +#include +#include +#include + +#ifdef MMAP_CLEANUP +struct mmap_cleanup_tag; +typedef struct mmap_cleanup_tag +{ + void *addr; + HANDLE h; + struct mmap_cleanup_tag *next; +} mmap_cleanup_t; +mmap_cleanup_t *mmap_cleanup = NULL; +#endif + + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +/* This flag is only available in WinXP+ */ +#ifdef FILE_MAP_EXECUTE +#define PROT_EXEC 0x4 +#else +#define PROT_EXEC 0x0 +#define FILE_MAP_EXECUTE 0 +#endif + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +#ifdef __USE_FILE_OFFSET64 +# define DWORD_HI(x) (x >> 32) +# define DWORD_LO(x) ((x) & 0xffffffff) +#else +# define DWORD_HI(x) (0) +# define DWORD_LO(x) (x) +#endif + +static void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_READWRITE; + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = length + offset; + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); + if (ret == NULL) { + CloseHandle(h); + ret = MAP_FAILED; + } +#ifdef MMAP_CLEANUP + else + { + // Add a tracking element (to the start of our list) + mmap_cleanup_t *mc = (mmap_cleanup_t *)malloc(sizeof(mmap_cleanup_t)); + if (mc != NULL) + { + mc->addr = ret; + mc->h = h; + mc->next = mmap_cleanup; + mmap_cleanup = mc; + } + } +#endif + return ret; +} + +static void munmap(void *addr, size_t length) +{ + UnmapViewOfFile(addr); +#ifdef MMAP_CLEANUP + // Look up through the tracking elements to close the handle + mmap_cleanup_t **prevPtr = &mmap_cleanup; + mmap_cleanup_t *mc; + for (mc = *prevPtr; mc != NULL; prevPtr = &mc->next, mc = *prevPtr) + { + if (mc->addr == addr) + { + CloseHandle(mc->h); + *prevPtr = mc->next; + break; + } + } +#else + // ruh-ro, we leaked handle from CreateFileMapping() ... +#endif +} + +#undef DWORD_HI +#undef DWORD_LO diff --git a/server/win32/mmap-win32.h b/server/win32/mmap-win32.h new file mode 100644 index 0000000..639fb35 --- /dev/null +++ b/server/win32/mmap-win32.h @@ -0,0 +1,201 @@ +/* +* Copyright (c) 2014, Newcastle University, UK. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +// Memory mapped file - Implementation of mmap() for Windows +// Dan Jackson, 2014 +// - 'MMAP_CLEANUP' changes to clean up otherwise leaked handles from CreateFileMapping() +// - 'sysconf(_SC_PAGE_SIZE)' implementation +// Original author: Mike Frysinger , placed into the public domain. + +// References: +// CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx +// CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx +// MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx +// UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + + +// This file does nothing if not on Windows +#ifdef _WIN32 +#ifndef MMAP_WIN32_C // Designed to be included for local static versions +#define MMAP_WIN32_C + +#define MMAP_CLEANUP // Dan + +#include +#include +#include + +#ifdef MMAP_CLEANUP +struct mmap_cleanup_tag; +typedef struct mmap_cleanup_tag +{ + void *addr; + HANDLE h; + struct mmap_cleanup_tag *next; +} mmap_cleanup_t; +static mmap_cleanup_t *mmap_cleanup = NULL; +#endif + + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +/* This flag is only available in WinXP+ */ +#ifdef FILE_MAP_EXECUTE +#define PROT_EXEC 0x4 +#else +#define PROT_EXEC 0x0 +#define FILE_MAP_EXECUTE 0 +#endif + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +#ifdef __USE_FILE_OFFSET64 +# define MM_DWORD_HI(x) (x >> 32) +# define MM_DWORD_LO(x) ((x) & 0xffffffff) +#else +# define MM_DWORD_HI(x) (0) +# define MM_DWORD_LO(x) (x) +#endif + +static void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_READWRITE; + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = (off_t)(length + offset); + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, MM_DWORD_HI(end), MM_DWORD_LO(end), NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + void *ret = MapViewOfFile(h, dwDesiredAccess, MM_DWORD_HI(offset), MM_DWORD_LO(offset), length); + if (ret == NULL) { + CloseHandle(h); + ret = MAP_FAILED; + } +#ifdef MMAP_CLEANUP + else + { + // Add a tracking element (to the start of our list) + mmap_cleanup_t *mc = (mmap_cleanup_t *)malloc(sizeof(mmap_cleanup_t)); + if (mc != NULL) + { + mc->addr = ret; + mc->h = h; + mc->next = mmap_cleanup; + mmap_cleanup = mc; + } + } +#endif + return ret; +} + +static void munmap(void *addr, size_t length) +{ + UnmapViewOfFile(addr); +#ifdef MMAP_CLEANUP + // Look up through the tracking elements to close the handle + mmap_cleanup_t **prevPtr = &mmap_cleanup; + mmap_cleanup_t *mc; + for (mc = *prevPtr; mc != NULL; prevPtr = &mc->next, mc = *prevPtr) + { + if (mc->addr == addr) + { + CloseHandle(mc->h); + *prevPtr = mc->next; + break; + } + } +#else + // ruh-ro, we leaked handle from CreateFileMapping() ... +#endif +} + +#define _SC_PAGE_SIZE 1 +#define _SC_NPROCESSORS_CONF 2 +#define _SC_NPROCESSORS_ONLN 3 +#define getpagesize() sysconf(_SC_PAGE_SIZE) +#define get_nprocs_conf() sysconf(_SC_NPROCESSORS_CONF) +#define get_nprocs() sysconf(_SC_NPROCESSORS_ONLN) +static long sysconf(int name) +{ + switch (name) + { + case _SC_PAGE_SIZE: + { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + return systemInfo.dwAllocationGranularity; // NOT systemInfo.dwPageSize; + } + case _SC_NPROCESSORS_CONF: + case _SC_NPROCESSORS_ONLN: + { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + return systemInfo.dwNumberOfProcessors; + } + default: + return -1; + } +} + +#endif // MMAP_WIN32_C +#endif // _WIN32 diff --git a/server/win32/sys/mman.h b/server/win32/sys/mman.h new file mode 100644 index 0000000..1abd407 --- /dev/null +++ b/server/win32/sys/mman.h @@ -0,0 +1 @@ +#include "mmap-win32.h"