aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Neus <[email protected]>2016-03-07 20:46:09 +0100
committerDaniel Neus <[email protected]>2016-03-07 20:31:50 +0100
commit094e7bbcbf3ad930a01910e445bc3f2b6be2faf7 (patch)
tree33c0809f9497bbe11a402787ceeb7511f920f063
parent58c89ae470c68bf300ea937740c233e2b5715535 (diff)
add support for VirtualLock/VirtualUnlock on Windows
equivalent to mlock on Unix to prevent swapping out of memory
-rw-r--r--doc/license.txt2
-rw-r--r--doc/news.rst2
-rw-r--r--src/lib/utils/os_utils.cpp52
3 files changed, 54 insertions, 2 deletions
diff --git a/doc/license.txt b/doc/license.txt
index 873e55e37..ba4381c1b 100644
--- a/doc/license.txt
+++ b/doc/license.txt
@@ -26,7 +26,7 @@ Copyright (C) 1999-2013,2014,2015,2016 Jack Lloyd
2015 Simon Warta (Kullo GmbH)
2015 Matej Kenda (TopIT d.o.o.)
2015 René Korthaus
- 2015 Daniel Neus
+ 2015,2016 Daniel Neus
2015 Uri Blumenthal
All rights reserved.
diff --git a/doc/news.rst b/doc/news.rst
index 72f5fa88b..d5698d23e 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -37,6 +37,8 @@ Version 1.11.29, Not Yet Released
* Small optimizations to Keccak hash
+* Support for locking allocator on Windows using VirtualLock/VirtualUnlock
+
Version 1.10.12, 2016-02-03
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
index 8fa099bc6..5deea902a 100644
--- a/src/lib/utils/os_utils.cpp
+++ b/src/lib/utils/os_utils.cpp
@@ -1,6 +1,7 @@
/*
* OS and machine specific utility functions
* (C) 2015,2016 Jack Lloyd
+* (C) 2016 Daniel Neus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -50,7 +51,7 @@ uint64_t get_processor_timestamp()
#if defined(BOTAN_USE_GCC_INLINE_ASM)
#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
- if(CPUID::has_rdtsc()) // not availble on all x86 CPUs
+ if(CPUID::has_rdtsc()) // not available on all x86 CPUs
{
uint32_t rtc_low = 0, rtc_high = 0;
asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low));
@@ -140,6 +141,37 @@ size_t get_memory_locking_limit()
return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024);
}
+#elif defined BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK
+ SIZE_T working_min = 0, working_max = 0;
+ DWORD working_flags = 0;
+ if(!::GetProcessWorkingSetSizeEx(::GetCurrentProcess(), &working_min, &working_max, &working_flags))
+ {
+ return 0;
+ }
+
+ SYSTEM_INFO sSysInfo;
+ ::GetSystemInfo(&sSysInfo);
+
+ // According to Microsoft MSDN:
+ // The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead
+ // In the book "Windows Internals Part 2": the maximum lockable pages are minimum working set size - 8 pages
+ // But the information in the book seems to be inaccurate/outdated
+ // I've tested this on Windows 8.1 x64, Windows 10 x64 and Windows 7 x86
+ // On all three OS the value is 11 instead of 8
+ size_t overhead = sSysInfo.dwPageSize * 11ULL;
+ if(working_min > overhead)
+ {
+ size_t lockable_bytes = working_min - overhead;
+ if(lockable_bytes < (BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024ULL))
+ {
+ return lockable_bytes;
+ }
+ else
+ {
+ return BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024ULL;
+ }
+ }
+ return 0;
#endif
return 0;
@@ -182,6 +214,20 @@ void* allocate_locked_pages(size_t length)
::memset(ptr, 0, length);
return ptr;
+#elif defined BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK
+ LPVOID ptr = ::VirtualAlloc(nullptr, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if(!ptr)
+ {
+ return nullptr;
+ }
+
+ if(::VirtualLock(ptr, length) == 0)
+ {
+ ::VirtualFree(ptr, 0, MEM_RELEASE);
+ return nullptr; // failed to lock
+ }
+
+ return ptr;
#else
return nullptr; /* not implemented */
#endif
@@ -196,6 +242,10 @@ void free_locked_pages(void* ptr, size_t length)
zero_mem(ptr, length);
::munlock(ptr, length);
::munmap(ptr, length);
+#elif defined BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK
+ zero_mem(ptr, length);
+ ::VirtualUnlock(ptr, length);
+ ::VirtualFree(ptr, 0, MEM_RELEASE);
#else
// Invalid argument because no way this pointer was allocated by us
throw Invalid_Argument("Invalid ptr to free_locked_pages");