aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/utils/os_utils.cpp
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2015-12-05 13:10:59 -0500
committerJack Lloyd <[email protected]>2015-12-05 13:10:59 -0500
commitf75ae7463a7f300a0b2a95693062b7129b6cc53d (patch)
treefaec9ed28956bcd2dda6e8d26f4ba094678bb454 /src/lib/utils/os_utils.cpp
parent2a472e9b33617afa62f5f899ec7eba90eb2f7ece (diff)
Add OS utility header
Provide abstractions for the locking allocator (allocate and free locked pages) to decouple it from the platform dependent code. Should make it easy to write a Windows version using VirtualAlloc+VirtualLock. Exposes max mlock limit as a build.h toggle
Diffstat (limited to 'src/lib/utils/os_utils.cpp')
-rw-r--r--src/lib/utils/os_utils.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
new file mode 100644
index 000000000..ae93d58d7
--- /dev/null
+++ b/src/lib/utils/os_utils.cpp
@@ -0,0 +1,131 @@
+/*
+* OS and machine specific utility functions
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/os_utils.h>
+#include <botan/exceptn.h>
+#include <botan/mem_ops.h>
+
+//TODO: defined(BOTAN_TARGET_OS_TYPE_IS_POSIX)
+
+#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
+ #include <sys/types.h>
+ #include <sys/mman.h>
+ #include <sys/resource.h>
+ #include <unistd.h>
+#endif
+
+namespace Botan {
+
+namespace OS {
+
+size_t get_memory_locking_limit()
+ {
+#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
+ /*
+ * Linux defaults to only 64 KiB of mlockable memory per process
+ * (too small) but BSDs offer a small fraction of total RAM (more
+ * than we need). Bound the total mlock size to 512 KiB which is
+ * enough to run the entire test suite without spilling to non-mlock
+ * memory (and thus presumably also enough for many useful
+ * programs), but small enough that we should not cause problems
+ * even if many processes are mlocking on the same machine.
+ */
+ size_t mlock_requested = BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB;
+
+ /*
+ * Allow override via env variable
+ */
+ if(const char* env = ::getenv("BOTAN_MLOCK_POOL_SIZE"))
+ {
+ try
+ {
+ const size_t user_req = std::stoul(env, nullptr);
+ mlock_requested = std::min(user_req, mlock_requested);
+ }
+ catch(std::exception&) { /* ignore it */ }
+ }
+
+ if(mlock_requested > 0)
+ {
+ struct ::rlimit limits;
+
+ ::getrlimit(RLIMIT_MEMLOCK, &limits);
+
+ if(limits.rlim_cur < limits.rlim_max)
+ {
+ limits.rlim_cur = limits.rlim_max;
+ ::setrlimit(RLIMIT_MEMLOCK, &limits);
+ ::getrlimit(RLIMIT_MEMLOCK, &limits);
+ }
+
+ return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024);
+ }
+#endif
+
+ return 0;
+ }
+
+void* allocate_locked_pages(size_t length)
+ {
+#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
+
+#if !defined(MAP_NOCORE)
+ #define MAP_NOCORE 0
+#endif
+
+#if !defined(MAP_ANONYMOUS)
+ #define MAP_ANONYMOUS MAP_ANON
+#endif
+
+ void* ptr = ::mmap(nullptr,
+ length,
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_SHARED | MAP_NOCORE,
+ /*fd*/-1,
+ /*offset*/0);
+
+ if(ptr == MAP_FAILED)
+ {
+ return nullptr;
+ }
+
+#if defined(MADV_DONTDUMP)
+ ::madvise(ptr, length, MADV_DONTDUMP);
+#endif
+
+ if(::mlock(ptr, length) != 0)
+ {
+ ::munmap(ptr, length);
+ return nullptr; // failed to lock
+ }
+
+ ::memset(ptr, 0, length);
+
+ return ptr;
+#else
+ return nullptr; /* not implemented */
+#endif
+ }
+
+void free_locked_pages(void* ptr, size_t length)
+ {
+ if(ptr == nullptr || length == 0)
+ return;
+
+#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
+ zero_mem(ptr, length);
+ ::munlock(ptr, length);
+ ::munmap(ptr, length);
+#else
+ // Invalid argument because no way this pointer was allocated by us
+ throw Invalid_Argument("Invalid ptr to free_locked_pages");
+#endif
+ }
+
+}
+
+}