From 6346da0d83b301d3c967ce6f53401387ff177c9c Mon Sep 17 00:00:00 2001 From: Christopher Dykes Date: Fri, 18 Mar 2016 14:57:46 -0700 Subject: [PATCH] Create the sys/mman.h portability header Summary: Something that Windows very definitely lacks. This is a fun one. Reviewed By: yfeldblum Differential Revision: D2979661 fb-gh-sync-id: e23c1db0cb8655b22308b874bd421a7cc1e4759e shipit-source-id: e23c1db0cb8655b22308b874bd421a7cc1e4759e --- folly/IndexedMemPool.h | 2 +- folly/Makefile.am | 2 + folly/MemoryMapping.cpp | 2 +- folly/Portability.h | 11 -- folly/detail/AtomicUnorderedMapUtils.h | 3 +- .../fibers/GuardPageAllocator.cpp | 2 +- folly/portability/SysMman.cpp | 146 ++++++++++++++++++ folly/portability/SysMman.h | 58 +++++++ folly/test/AtomicHashArrayTest.cpp | 9 +- 9 files changed, 213 insertions(+), 22 deletions(-) create mode 100755 folly/portability/SysMman.cpp create mode 100755 folly/portability/SysMman.h diff --git a/folly/IndexedMemPool.h b/folly/IndexedMemPool.h index 8cfe0e7f..f8771f33 100644 --- a/folly/IndexedMemPool.h +++ b/folly/IndexedMemPool.h @@ -21,10 +21,10 @@ #include #include #include -#include #include #include #include +#include // Ignore shadowing warnings within this file, so includers can use -Wshadow. #pragma GCC diagnostic push diff --git a/folly/Makefile.am b/folly/Makefile.am index 5428b5fa..fffd7edf 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -276,6 +276,7 @@ nobase_follyinclude_HEADERS = \ portability/Strings.h \ portability/Syscall.h \ portability/SysFile.h \ + portability/SysMman.h \ portability/SysStat.h \ portability/SysTime.h \ portability/SysTypes.h \ @@ -410,6 +411,7 @@ libfolly_la_SOURCES = \ portability/Environment.cpp \ portability/Strings.cpp \ portability/SysFile.cpp \ + portability/SysMman.cpp \ portability/SysStat.cpp \ portability/SysTime.cpp \ portability/Time.cpp \ diff --git a/folly/MemoryMapping.cpp b/folly/MemoryMapping.cpp index 5fa25acc..17f1e760 100644 --- a/folly/MemoryMapping.cpp +++ b/folly/MemoryMapping.cpp @@ -21,13 +21,13 @@ #include #include +#include #ifdef __linux__ #include #endif #include -#include #include #include #include diff --git a/folly/Portability.h b/folly/Portability.h index b1aa36e5..fb01114e 100644 --- a/folly/Portability.h +++ b/folly/Portability.h @@ -46,17 +46,6 @@ constexpr bool kHasUnalignedAccess = false; #endif } -// A change in folly/MemoryMapping.cpp uses MAP_ANONYMOUS, which is named -// MAP_ANON on OSX/BSD. -#if defined(__APPLE__) || defined(__FreeBSD__) - #include - #ifndef MAP_ANONYMOUS - #ifdef MAP_ANON - #define MAP_ANONYMOUS MAP_ANON - #endif - #endif -#endif - // compiler specific attribute translation // msvc should come first, so if clang is in msvc mode it gets the right defines diff --git a/folly/detail/AtomicUnorderedMapUtils.h b/folly/detail/AtomicUnorderedMapUtils.h index f5737972..4142ade8 100644 --- a/folly/detail/AtomicUnorderedMapUtils.h +++ b/folly/detail/AtomicUnorderedMapUtils.h @@ -2,9 +2,10 @@ #include #include -#include #include +#include + namespace folly { namespace detail { class MMapAlloc { diff --git a/folly/experimental/fibers/GuardPageAllocator.cpp b/folly/experimental/fibers/GuardPageAllocator.cpp index f4e7b790..0a732ae1 100644 --- a/folly/experimental/fibers/GuardPageAllocator.cpp +++ b/folly/experimental/fibers/GuardPageAllocator.cpp @@ -15,13 +15,13 @@ */ #include "GuardPageAllocator.h" -#include #include #include #include #include +#include #include diff --git a/folly/portability/SysMman.cpp b/folly/portability/SysMman.cpp new file mode 100755 index 00000000..8420c82b --- /dev/null +++ b/folly/portability/SysMman.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef _WIN32 +#include + +static bool mmap_to_page_protection(int prot, DWORD& ret) { + if (prot == PROT_NONE) { + ret = PAGE_NOACCESS; + } else if (prot == PROT_READ) { + ret = PAGE_READONLY; + } else if (prot == PROT_EXEC) { + ret = PAGE_EXECUTE; + } else if (prot == (PROT_READ | PROT_EXEC)) { + ret = PAGE_EXECUTE_READ; + } else if (prot == (PROT_READ | PROT_WRITE)) { + ret = PAGE_READWRITE; + } else if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) { + ret = PAGE_EXECUTE_READWRITE; + } else { + return false; + } + return true; +} + +extern "C" { +int madvise(const void* addr, size_t len, int advise) { + // We do nothing at all. + // Could probably implement dontneed via VirtualAlloc + // with the MEM_RESET and MEM_RESET_UNDO flags. + return 0; +} + +int mlock(const void* addr, size_t len) { + if (!VirtualLock((void*)addr, len)) { + return -1; + } + return 0; +} + +void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) { + // Make sure it's something we support first. + + // No Anon shared. + if ((flags & (MAP_ANONYMOUS | MAP_SHARED)) == (MAP_ANONYMOUS | MAP_SHARED)) { + return MAP_FAILED; + } + // No private copy on write. + if ((flags & MAP_PRIVATE) == MAP_PRIVATE && fd != -1) { + return MAP_FAILED; + } + // Map isn't anon, must be file backed. + if (!(flags & MAP_ANONYMOUS) && fd == -1) { + return MAP_FAILED; + } + + DWORD newProt; + if (!mmap_to_page_protection(prot, newProt)) { + return MAP_FAILED; + } + + void* ret; + if (!(flags & MAP_ANONYMOUS) || (flags & MAP_SHARED)) { + HANDLE h = INVALID_HANDLE_VALUE; + if (!(flags & MAP_ANONYMOUS)) { + h = (HANDLE)_get_osfhandle(fd); + } + + HANDLE fmh = CreateFileMapping( + h, + nullptr, + newProt | SEC_COMMIT | SEC_RESERVE, + (DWORD)((length >> 32) & 0xFFFFFFFF), + (DWORD)(length & 0xFFFFFFFF), + nullptr); + ret = MapViewOfFileEx( + fmh, + FILE_MAP_ALL_ACCESS, + (DWORD)((off >> 32) & 0xFFFFFFFF), + (DWORD)(off & 0xFFFFFFFF), + 0, + addr); + if (ret == nullptr) { + ret = MAP_FAILED; + } + CloseHandle(fmh); + } else { + ret = VirtualAlloc(addr, length, MEM_COMMIT | MEM_RESERVE, newProt); + if (ret == nullptr) { + return MAP_FAILED; + } + } + + // TODO: Could technically implement MAP_POPULATE via PrefetchVirtualMemory + // Should also see about implementing MAP_NORESERVE + return ret; +} + +int mprotect(void* addr, size_t size, int prot) { + DWORD newProt; + if (!mmap_to_page_protection(prot, newProt)) { + return -1; + } + + DWORD oldProt; + BOOL res = VirtualProtect(addr, size, newProt, &oldProt); + if (!res) { + return -1; + } + return 0; +} + +int munlock(const void* addr, size_t length) { + if (!VirtualUnlock((void*)addr, length)) { + return -1; + } + return 0; +} + +int munmap(void* addr, size_t length) { + // Try to unmap it as a file, otherwise VirtualFree. + if (!UnmapViewOfFile(addr)) { + if (!VirtualFree(addr, length, MEM_RELEASE)) { + return -1; + } + return 0; + } + return 0; +} +} +#endif diff --git a/folly/portability/SysMman.h b/folly/portability/SysMman.h new file mode 100755 index 00000000..52dd33c8 --- /dev/null +++ b/folly/portability/SysMman.h @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef _WIN32 +#include + +// MAP_ANONYMOUS is named MAP_ANON on OSX/BSD. +#if defined(__APPLE__) || defined(__FreeBSD__) +# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +#endif +#else +#include +#include + +#define MAP_ANONYMOUS 1 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_SHARED 2 +#define MAP_PRIVATE 4 +#define MAP_POPULATE 8 +#define MAP_NORESERVE 16 +#define MAP_FIXED 32 + +#define MAP_FAILED ((void*)-1) + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MADV_DONTNEED 0 +#define MADV_SEQUENTIAL 0 + +extern "C" { +int madvise(const void* addr, size_t len, int advise); +int mlock(const void* addr, size_t len); +void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off); +int mprotect(void* addr, size_t size, int prot); +int munlock(const void* addr, size_t length); +int munmap(void* addr, size_t length); +} +#endif diff --git a/folly/test/AtomicHashArrayTest.cpp b/folly/test/AtomicHashArrayTest.cpp index 5c3eb70a..4facc7d7 100644 --- a/folly/test/AtomicHashArrayTest.cpp +++ b/folly/test/AtomicHashArrayTest.cpp @@ -14,22 +14,17 @@ * limitations under the License. */ -#include - #include #include #include #include -#include #include +#include #include +#include #include -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif - using namespace std; using namespace folly; -- 2.34.1