diff --git a/beast/utility/static_initializer.h b/beast/utility/static_initializer.h new file mode 100644 index 0000000000..72aa0dbf4f --- /dev/null +++ b/beast/utility/static_initializer.h @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_STATIC_INITIALIZER_H_INCLUDED +#define BEAST_UTILITY_STATIC_INITIALIZER_H_INCLUDED + +#ifdef _MSC_VER + +#include +#include +#include +#include +#include +#include + +namespace beast { + +/** Returns an object with static storage duration. + This is a workaround for Visual Studio 2013 and earlier non-thread + safe initialization of function local objects with static storage duration. + + Usage: + @code + my_class& foo() + { + static static_initializer instance; + return *instance; + } + @endcode +*/ +template +class static_initializer +{ +private: + T* instance_; + +public: + template + static_initializer(Args&&... args) + { + static std::aligned_storage ::value>::type storage; + instance_ = reinterpret_cast(&storage); + + // double checked lock + static bool volatile initialized; + if (! initialized) + { + static std::atomic_flag lock; + while (lock.test_and_set()) + std::this_thread::sleep_for ( + std::chrono::milliseconds(10)); + if (! initialized) + { + try + { + ::new(instance_) T(std::forward(args)...); + + struct destroyer + { + T* t_; + + destroyer (T* t) + : t_(t) + { + } + + ~destroyer() + { + t_->~T(); + } + }; + + static destroyer on_exit (instance_); + } + catch(...) + { + lock.clear(); + throw; + } + initialized = true; + } + lock.clear(); + } + } + + T& + get() noexcept + { + return *instance_; + } + + T& + operator*() noexcept + { + return *instance_; + } +}; + +} + +#endif + +#endif