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()121 static 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