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 guarantees 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 accessible 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: |
104 | BOOST_DLLEXPORT bool & get_lock() BOOST_USED { |
105 | static bool lock = false; |
106 | return lock; |
107 | } |
108 | |
109 | public: |
110 | BOOST_DLLEXPORT void lock(){ |
111 | get_lock() = true; |
112 | } |
113 | BOOST_DLLEXPORT void unlock(){ |
114 | get_lock() = false; |
115 | } |
116 | BOOST_DLLEXPORT bool is_locked(){ |
117 | return get_lock(); |
118 | } |
119 | }; |
120 | |
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 accessible even after |
134 | // destruction. This can be used to check, if the singleton is still |
135 | // accessible e.g. in destructors of other singletons. |
136 | template<class T> |
137 | class singleton_wrapper : public T |
138 | { |
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: |
147 | singleton_wrapper(){ |
148 | BOOST_ASSERT(! is_destroyed()); |
149 | } |
150 | ~singleton_wrapper(){ |
151 | get_is_destroyed() = true; |
152 | } |
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 |
165 | static void use(T const &) {} |
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 undefined behavior |
179 | // and reports an error. But I've been unable to find a different way |
180 | // of guaranteeing 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 |
188 | BOOST_DLLEXPORT singleton(){} |
189 | |
190 | public: |
191 | BOOST_DLLEXPORT static T & get_mutable_instance(){ |
192 | BOOST_ASSERT(! get_singleton_module().is_locked()); |
193 | return get_instance(); |
194 | } |
195 | BOOST_DLLEXPORT static const T & get_const_instance(){ |
196 | return get_instance(); |
197 | } |
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 | |