diff --git a/src/Win32_Interop/Win32_Common.cpp b/src/Win32_Interop/Win32_Common.cpp new file mode 100644 index 00000000..22cb853f --- /dev/null +++ b/src/Win32_Interop/Win32_Common.cpp @@ -0,0 +1,48 @@ +/* +* Copyright (c), Microsoft Open Technologies, Inc. +* All rights reserved. +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* - Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* - 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. +*/ +#include "Win32_Common.h" + +namespace Globals +{ + size_t pageSize = 0; +} + +/* This function is used to force the VEH on the entire size of the buffer length, + in the event that the buffer crosses the memory page boundaries */ +void EnsureMemoryIsMapped(const void *buffer, size_t size) { + /* Use 'volatile' to make sure the compiler doesn't remove "c = *((char*) (p + offset));" */ + volatile char c; + char* p = (char*) buffer; + char* pStart = p - ((size_t) p % Globals::pageSize); + char* pEnd = p + size; + if ((size_t) (pEnd - pStart) > Globals::pageSize) { + size_t offset = 0; + while (offset < size) { + if (size < offset) { + offset = size; + } else { + offset += Globals::pageSize; + } + c = *((char*) (p + offset)); + } + } +} diff --git a/src/Win32_Interop/Win32_Common.h b/src/Win32_Interop/Win32_Common.h new file mode 100644 index 00000000..57094f77 --- /dev/null +++ b/src/Win32_Interop/Win32_Common.h @@ -0,0 +1,33 @@ +/* +* Copyright (c), Microsoft Open Technologies, Inc. +* All rights reserved. +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* - Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* - 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. +*/ + +#ifndef WIN32_COMMON_H +#define WIN32_COMMON_H + +void EnsureMemoryIsMapped(const void *buffer, size_t size); + +namespace Globals { + // forward declarations only + extern size_t pageSize; +} + +#endif \ No newline at end of file diff --git a/src/Win32_Interop/Win32_Interop.vcxproj b/src/Win32_Interop/Win32_Interop.vcxproj index 85de0e5f..473c3e22 100644 --- a/src/Win32_Interop/Win32_Interop.vcxproj +++ b/src/Win32_Interop/Win32_Interop.vcxproj @@ -22,6 +22,7 @@ + @@ -45,6 +46,7 @@ + diff --git a/src/Win32_Interop/Win32_QFork.cpp b/src/Win32_Interop/Win32_QFork.cpp index 6fd83e06..1dd65dfe 100644 --- a/src/Win32_Interop/Win32_QFork.cpp +++ b/src/Win32_Interop/Win32_QFork.cpp @@ -22,6 +22,7 @@ #include "win32_types.h" #include "Win32_FDAPI.h" +#include "Win32_Common.h" #include #include @@ -161,7 +162,6 @@ const SIZE_T cAllocationGranularity = 1 << 18; // 256KB per h const int cMaxBlocks = 1 << 24; // 256KB * 16M heap blocks = 4TB. 4TB is the largest memory config Windows supports at present. const char* cMapFileBaseName = "RedisQFork"; const int cDeadForkWait = 30000; -size_t pageSize = 0; #ifndef _WIN64 size_t cDefaultmaxHeap32Bit = 1 << 29; // 512MB @@ -693,7 +693,7 @@ StartupStatus QForkStartup(int argc, char** argv) { ::redisLog(REDIS_WARNING, "Failing startup.\n"); return StartupStatus::ssFAILED; } - pageSize = perfinfo.PageSize; + Globals::pageSize = perfinfo.PageSize; /* Not specifying the maxmemory or maxheap flags will result in the default behavior of: new key generation not @@ -740,7 +740,7 @@ StartupStatus QForkStartup(int argc, char** argv) { maxheapBytes = cSentinelHeapSize; } else { #ifdef _WIN64 - maxheapBytes = perfinfo.PhysicalTotal * pageSize; + maxheapBytes = perfinfo.PhysicalTotal * Globals::pageSize; #else maxheapBytes = cDefaultmaxHeap32Bit; #endif diff --git a/src/Win32_Interop/Win32_fdapi_crt.cpp b/src/Win32_Interop/Win32_fdapi_crt.cpp index f112ca1c..62d2e466 100644 --- a/src/Win32_Interop/Win32_fdapi_crt.cpp +++ b/src/Win32_Interop/Win32_fdapi_crt.cpp @@ -21,6 +21,7 @@ */ #include "Win32_fdapi_crt.h" +#include "Win32_Common.h" #include #include @@ -56,22 +57,14 @@ int crtsetmode(int fd, int mode) { return ::_setmode(fd, mode); } -size_t crt_fwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File) { +size_t crt_fwrite(const void *buffer, size_t size, size_t count, FILE *file) { // fwrite() somehow locks its view of the buffer. If during a fork operation the buffer has not been loaded into the forkee's process space, // the VEH will be called to load the missing pages. Although the page gets loaded, fwrite() will not see the loaded page. The result is // that fwrite will fail with errno set to ERROR_INVALID_USER_BUFFER. The fix is to force the buffer into memory before fwrite(). This only - // impacts wirites that straddle page boundaries. - const intptr_t pageSize = 4096; - char* p = (char*)_Str; - char* pageStart = p - ((intptr_t)p % pageSize); - char* pEnd = p + _Size; - if ((intptr_t)(pEnd - pageStart) > pageSize) { - for (size_t n = 0; n < _Size; n++) { - char x = *((char*)_Str + n); - } - } + // impacts writes that straddle page boundaries. + EnsureMemoryIsMapped(buffer, size); + return ::fwrite(buffer, size, count, file); - return ::fwrite(_Str, _Size, _Count, _File); } int crt_fclose(FILE* file) { @@ -93,4 +86,3 @@ int crt_access(const char *pathname, int mode) { __int64 crt_lseek64(int fd, __int64 offset, int origin) { return _lseeki64(fd, offset, origin); } - diff --git a/src/Win32_Interop/Win32_fdapi_crt.h b/src/Win32_Interop/Win32_fdapi_crt.h index 6b59515e..5ce6244b 100644 --- a/src/Win32_Interop/Win32_fdapi_crt.h +++ b/src/Win32_Interop/Win32_fdapi_crt.h @@ -32,7 +32,7 @@ int crt_open(const char *filename, int oflag, int pmode); int crt_open_osfhandle(intptr_t osfhandle, int flags); intptr_t crtget_osfhandle(int fd); int crtsetmode(int fd, int mode); -size_t crt_fwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File); +size_t crt_fwrite(const void *buffer, size_t size, size_t count, FILE *file); int crt_fclose(FILE* file); int crt_fileno(FILE* file);