1 #ifndef BOOST_SERIALIZATION_SINGLETON_HPP 2 #define BOOST_SERIALIZATION_SINGLETON_HPP 3 4 /////////1/////////2///////// 3/////////4/////////5/////////6/////////7/////////8 5 // singleton.hpp 6 // 7 // Copyright David Abrahams 2006. Original version 8 // 9 // Copyright Robert Ramey 2007. Changes made to permit 10 // application throughout the serialization library. 11 // 12 // Copyright Alexander Grund 2018. Corrections to singleton lifetime 13 // 14 // Distributed under the Boost 15 // Software License, Version 1.0. (See accompanying 16 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 17 // 18 // The intention here is to define a template which will convert 19 // any class into a singleton with the following features: 20 // 21 // a) initialized before first use. 22 // b) thread-safe for const access to the class 23 // c) non-locking 24 // 25 // In order to do this, 26 // a) Initialize dynamically when used. 27 // b) Require that all singletons be initialized before main 28 // is called or any entry point into the shared library is invoked. 29 // This guarentees no race condition for initialization. 30 // In debug mode, we assert that no non-const functions are called 31 // after main is invoked. 32 // 33 34 // MS compatible compilers support #pragma once 35 #if defined(_MSC_VER) 36 # pragma once 37 #endif 38 39 #include <boost/assert.hpp> 40 #include <boost/config.hpp> 41 #include <boost/noncopyable.hpp> 42 #include <boost/serialization/force_include.hpp> 43 #include <boost/serialization/config.hpp> 44 45 #include <boost/archive/detail/auto_link_archive.hpp> 46 #include <boost/archive/detail/abi_prefix.hpp> // must be the last header 47 48 #ifdef BOOST_MSVC 49 # pragma warning(push) 50 # pragma warning(disable : 4511 4512) 51 #endif 52 53 namespace boost { 54 namespace serialization { 55 56 ////////////////////////////////////////////////////////////////////// 57 // Provides a dynamically-initialized (singleton) instance of T in a 58 // way that avoids LNK1179 on vc6. See http://tinyurl.com/ljdp8 or 59 // http://lists.boost.org/Archives/boost/2006/05/105286.php for 60 // details. 61 // 62 63 // Singletons created by this code are guaranteed to be unique 64 // within the executable or shared library which creates them. 65 // This is sufficient and in fact ideal for the serialization library. 66 // The singleton is created when the module is loaded and destroyed 67 // when the module is unloaded. 68 69 // This base class has two functions. 70 71 // First it provides a module handle for each singleton indicating 72 // the executable or shared library in which it was created. This 73 // turns out to be necessary and sufficient to implement the tables 74 // used by serialization library. 75 76 // Second, it provides a mechanism to detect when a non-const function 77 // is called after initialization. 78 79 // Make a singleton to lock/unlock all singletons for alteration. 80 // The intent is that all singletons created/used by this code 81 // are to be initialized before main is called. A test program 82 // can lock all the singletons when main is entered. Thus any 83 // attempt to retrieve a mutable instance while locked will 84 // generate an assertion if compiled for debug. 85 86 // The singleton template can be used in 2 ways: 87 // 1 (Recommended): Publicly inherit your type T from singleton<T>, 88 // make its ctor protected and access it via T::get_const_instance() 89 // 2: Simply access singleton<T> without changing T. Note that this only 90 // provides a global instance accesible by singleton<T>::get_const_instance() 91 // or singleton<T>::get_mutable_instance() to prevent using multiple instances 92 // of T make its ctor protected 93 94 // Note on usage of BOOST_DLLEXPORT: These functions are in danger of 95 // being eliminated by the optimizer when building an application in 96 // release mode. Usage of the macro is meant to signal the compiler/linker 97 // to avoid dropping these functions which seem to be unreferenced. 98 // This usage is not related to autolinking. 99 100 class BOOST_SYMBOL_VISIBLE singleton_module : 101 public boost::noncopyable 102 { 103 private: get_lock()104 BOOST_DLLEXPORT bool & get_lock() BOOST_USED { 105 static bool lock = false; 106 return lock; 107 } 108 109 public: lock()110 BOOST_DLLEXPORT void lock(){ 111 get_lock() = true; 112 } unlock()113 BOOST_DLLEXPORT void unlock(){ 114 get_lock() = false; 115 } is_locked()116 BOOST_DLLEXPORT bool is_locked(){ 117 return get_lock(); 118 } 119 }; 120 get_singleton_module()121static inline singleton_module & get_singleton_module(){ 122 static singleton_module m; 123 return m; 124 } 125 126 namespace detail { 127 128 // This is the class actually instantiated and hence the real singleton. 129 // So there will only be one instance of this class. This does not hold 130 // for singleton<T> as a class derived from singleton<T> could be 131 // instantiated multiple times. 132 // It also provides a flag `is_destroyed` which returns true, when the 133 // class was destructed. It is static and hence accesible even after 134 // destruction. This can be used to check, if the singleton is still 135 // accesible e.g. in destructors of other singletons. 136 template<class T> 137 class singleton_wrapper : public T 138 { get_is_destroyed()139 static bool & get_is_destroyed(){ 140 // Prefer a static function member to avoid LNK1179. 141 // Note: As this is for a singleton (1 instance only) it must be set 142 // never be reset (to false)! 143 static bool is_destroyed_flag = false; 144 return is_destroyed_flag; 145 } 146 public: singleton_wrapper()147 singleton_wrapper(){ 148 BOOST_ASSERT(! is_destroyed()); 149 } ~singleton_wrapper()150 ~singleton_wrapper(){ 151 get_is_destroyed() = true; 152 } is_destroyed()153 static bool is_destroyed(){ 154 return get_is_destroyed(); 155 } 156 }; 157 158 } // detail 159 160 template <class T> 161 class singleton { 162 private: 163 static T * m_instance; 164 // include this to provoke instantiation at pre-execution time use(T const &)165 static void use(T const &) {} get_instance()166 static T & get_instance() { 167 BOOST_ASSERT(! is_destroyed()); 168 169 // use a wrapper so that types T with protected constructors can be used 170 // Using a static function member avoids LNK1179 171 static detail::singleton_wrapper< T > t; 172 173 // note that the following is absolutely essential. 174 // commenting out this statement will cause compilers to fail to 175 // construct the instance at pre-execution time. This would prevent 176 // our usage/implementation of "locking" and introduce uncertainty into 177 // the sequence of object initialization. 178 // Unfortunately, this triggers detectors of undefine behavior 179 // and reports an error. But I've been unable to find a different 180 // of guarenteeing that the the singleton is created at pre-main time. 181 if (m_instance) use(* m_instance); 182 183 return static_cast<T &>(t); 184 } 185 protected: 186 // Do not allow instantiation of a singleton<T>. But we want to allow 187 // `class T: public singleton<T>` so we can't delete this ctor singleton()188 BOOST_DLLEXPORT singleton(){} 189 190 public: get_mutable_instance()191 BOOST_DLLEXPORT static T & get_mutable_instance(){ 192 BOOST_ASSERT(! get_singleton_module().is_locked()); 193 return get_instance(); 194 } get_const_instance()195 BOOST_DLLEXPORT static const T & get_const_instance(){ 196 return get_instance(); 197 } is_destroyed()198 BOOST_DLLEXPORT static bool is_destroyed(){ 199 return detail::singleton_wrapper< T >::is_destroyed(); 200 } 201 }; 202 203 // Assigning the instance reference to a static member forces initialization 204 // at startup time as described in 205 // https://groups.google.com/forum/#!topic/microsoft.public.vc.language/kDVNLnIsfZk 206 template<class T> 207 T * singleton< T >::m_instance = & singleton< T >::get_instance(); 208 209 } // namespace serialization 210 } // namespace boost 211 212 #include <boost/archive/detail/abi_suffix.hpp> // pops abi_suffix.hpp pragmas 213 214 #ifdef BOOST_MSVC 215 #pragma warning(pop) 216 #endif 217 218 #endif // BOOST_SERIALIZATION_SINGLETON_HPP 219