summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcostan <costan@google.com>2018-09-24 10:50:40 -0700
committerVictor Costan <pwnall@chromium.org>2018-09-24 13:37:31 -0700
commita7dc502e9f11c2e5c911ba45b999676c43eaa51f (patch)
tree878912d056bbf5861b67851ed6c7aa87208751eb
parentc43565dd398b2233db8eb49ba05234d62fb42e03 (diff)
downloadleveldb-a7dc502e9f11c2e5c911ba45b999676c43eaa51f.tar.gz
Rework once initialization in env_posix.cc.
C++11 guarantees thread-safe initialization of static variables inside functions. This is a more restricted form of std::call_once or pthread_once_t (e.g., single call site), so the compiler might be able to generate better code [1]. Equally important, having less platform-dependent code in env_posix.cc makes it easier to port to other platforms. Due to the change above, this CL introduced a new approach for storing the singleton PosixEnv instance returned by Env::Default(). The new approach avoids a dynamic memory allocation, which eliminates the false positive from LeakSanitizer reported in https://github.com/google/leveldb/issues/539 and https://github.com/google/leveldb/issues/113 [1] https://stackoverflow.com/a/27206650/ ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=214293129
-rw-r--r--util/env_posix.cc84
1 files changed, 70 insertions, 14 deletions
diff --git a/util/env_posix.cc b/util/env_posix.cc
index d6b0d61..68a8808 100644
--- a/util/env_posix.cc
+++ b/util/env_posix.cc
@@ -17,18 +17,21 @@
#include <unistd.h>
#include <atomic>
+#include <cstddef>
+#include <cstdint>
#include <cstring>
#include <limits>
#include <queue>
#include <set>
+#include <string>
#include <thread>
+#include <type_traits>
#include "leveldb/env.h"
#include "leveldb/slice.h"
+#include "leveldb/status.h"
#include "port/port.h"
#include "port/thread_annotations.h"
-#include "util/logging.h"
-#include "util/mutexlock.h"
#include "util/posix_logger.h"
#include "util/env_posix_test_helper.h"
@@ -401,12 +404,15 @@ class PosixLockTable {
std::set<std::string> locked_files_ GUARDED_BY(mu_);
public:
bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
- MutexLock l(&mu_);
- return locked_files_.insert(fname).second;
+ mu_.Lock();
+ bool succeeded = locked_files_.insert(fname).second;
+ mu_.Unlock();
+ return succeeded;
}
void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
- MutexLock l(&mu_);
+ mu_.Lock();
locked_files_.erase(fname);
+ mu_.Unlock();
}
};
@@ -693,7 +699,7 @@ PosixEnv::PosixEnv()
void PosixEnv::Schedule(
void (*background_work_function)(void* background_work_arg),
void* background_work_arg) {
- MutexLock lock(&background_work_mutex_);
+ background_work_mutex_.Lock();
// Start the background thread, if we haven't done so already.
if (!started_background_thread_) {
@@ -708,6 +714,7 @@ void PosixEnv::Schedule(
}
background_work_queue_.emplace(background_work_function, background_work_arg);
+ background_work_mutex_.Unlock();
}
void PosixEnv::BackgroundThreadMain() {
@@ -730,6 +737,59 @@ void PosixEnv::BackgroundThreadMain() {
}
}
+// Wraps an Env instance whose destructor is never created.
+//
+// Intended usage:
+// using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;
+// void ConfigurePosixEnv(int param) {
+// PlatformSingletonEnv::AssertEnvNotInitialized();
+// // set global configuration flags.
+// }
+// Env* Env::Default() {
+// static PlatformSingletonEnv default_env;
+// return default_env.env();
+// }
+template<typename EnvType>
+class SingletonEnv {
+ public:
+ SingletonEnv() {
+#if !defined(NDEBUG)
+ env_initialized_.store(true, std::memory_order::memory_order_relaxed);
+#endif // !defined(NDEBUG)
+ static_assert(sizeof(env_storage_) >= sizeof(EnvType),
+ "env_storage_ will not fit the Env");
+ static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),
+ "env_storage_ does not meet the Env's alignment needs");
+ new (&env_storage_) EnvType();
+ }
+ ~SingletonEnv() = default;
+
+ SingletonEnv(const SingletonEnv&) = delete;
+ SingletonEnv& operator=(const SingletonEnv&) = delete;
+
+ Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
+
+ static void AssertEnvNotInitialized() {
+#if !defined(NDEBUG)
+ assert(!env_initialized_.load(std::memory_order::memory_order_relaxed));
+#endif // !defined(NDEBUG)
+ }
+
+ private:
+ typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type
+ env_storage_;
+#if !defined(NDEBUG)
+ static std::atomic<bool> env_initialized_;
+#endif // !defined(NDEBUG)
+};
+
+#if !defined(NDEBUG)
+template<typename EnvType>
+std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
+#endif // !defined(NDEBUG)
+
+using PosixDefaultEnv = SingletonEnv<PosixEnv>;
+
} // namespace
void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg),
@@ -738,23 +798,19 @@ void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg),
new_thread.detach();
}
-static pthread_once_t once = PTHREAD_ONCE_INIT;
-static Env* default_env;
-static void InitDefaultEnv() { default_env = new PosixEnv; }
-
void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
- assert(default_env == nullptr);
+ PosixDefaultEnv::AssertEnvNotInitialized();
open_read_only_file_limit = limit;
}
void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
- assert(default_env == nullptr);
+ PosixDefaultEnv::AssertEnvNotInitialized();
mmap_limit = limit;
}
Env* Env::Default() {
- pthread_once(&once, InitDefaultEnv);
- return default_env;
+ static PosixDefaultEnv env_container;
+ return env_container.env();
}
} // namespace leveldb