1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   named_scope.cpp
9  * \author Andrey Semashev
10  * \date   24.06.2007
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #include <boost/log/detail/config.hpp>
17 #include <utility>
18 #include <algorithm>
19 #include <boost/type_index.hpp>
20 #include <boost/optional/optional.hpp>
21 #include <boost/log/attributes/attribute.hpp>
22 #include <boost/log/attributes/attribute_value.hpp>
23 #include <boost/log/attributes/named_scope.hpp>
24 #include <boost/log/utility/type_dispatch/type_dispatcher.hpp>
25 #include <boost/log/detail/singleton.hpp>
26 #if !defined(BOOST_LOG_NO_THREADS)
27 #include <boost/thread/tss.hpp>
28 #endif
29 #include "unique_ptr.hpp"
30 #include <boost/log/detail/header.hpp>
31 
32 namespace boost {
33 
34 BOOST_LOG_OPEN_NAMESPACE
35 
36 namespace attributes {
37 
38 BOOST_LOG_ANONYMOUS_NAMESPACE {
39 
40     //! Actual implementation of the named scope list
41     class writeable_named_scope_list :
42         public named_scope_list
43     {
44         //! Base type
45         typedef named_scope_list base_type;
46 
47     public:
48         //! Const reference type
49         typedef base_type::const_reference const_reference;
50 
51     public:
52         //! The method pushes the scope to the back of the list
53         BOOST_FORCEINLINE void push_back(const_reference entry) BOOST_NOEXCEPT
54         {
55             aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
56             entry._m_pPrev = top;
57             entry._m_pNext = &this->m_RootNode;
58 
59             BOOST_LOG_ASSUME(&entry != 0);
60             this->m_RootNode._m_pPrev = top->_m_pNext =
61                 const_cast< aux::named_scope_list_node* >(
62                     static_cast< const aux::named_scope_list_node* >(&entry));
63 
64             ++this->m_Size;
65         }
66         //! The method removes the top scope entry from the list
67         BOOST_FORCEINLINE void pop_back() BOOST_NOEXCEPT
68         {
69             aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
70             top->_m_pPrev->_m_pNext = top->_m_pNext;
71             top->_m_pNext->_m_pPrev = top->_m_pPrev;
72             --this->m_Size;
73         }
74     };
75 
76     //! Named scope attribute value
77     class named_scope_value :
78         public attribute_value::impl
79     {
80         //! Scope names stack
81         typedef named_scope_list scope_stack;
82 
83         //! Pointer to the actual scope value
84         scope_stack* m_pValue;
85         //! A thread-independent value
86         optional< scope_stack > m_DetachedValue;
87 
88     public:
89         //! Constructor
90         explicit named_scope_value(scope_stack* p) : m_pValue(p) {}
91 
92         //! The method dispatches the value to the given object. It returns true if the
93         //! object was capable to consume the real attribute value type and false otherwise.
94         bool dispatch(type_dispatcher& dispatcher)
95         {
96             type_dispatcher::callback< scope_stack > callback =
97                 dispatcher.get_callback< scope_stack >();
98             if (callback)
99             {
100                 callback(*m_pValue);
101                 return true;
102             }
103             else
104                 return false;
105         }
106 
107         /*!
108          * \return The attribute value type
109          */
110         typeindex::type_index get_type() const { return typeindex::type_id< scope_stack >(); }
111 
112         //! The method is called when the attribute value is passed to another thread (e.g.
113         //! in case of asynchronous logging). The value should ensure it properly owns all thread-specific data.
114         intrusive_ptr< attribute_value::impl > detach_from_thread()
115         {
116             if (!m_DetachedValue)
117             {
118                 m_DetachedValue = *m_pValue;
119                 m_pValue = m_DetachedValue.get_ptr();
120             }
121 
122             return this;
123         }
124     };
125 
126 } // namespace
127 
128 //! Named scope attribute implementation
129 struct BOOST_SYMBOL_VISIBLE named_scope::impl :
130     public attribute::impl,
131     public log::aux::singleton<
132         impl,
133         intrusive_ptr< impl >
134     >
135 {
136     //! Singleton base type
137     typedef log::aux::singleton<
138         impl,
139         intrusive_ptr< impl >
140     > singleton_base_type;
141 
142     //! Writable scope list type
143     typedef writeable_named_scope_list scope_list;
144 
145 #if !defined(BOOST_LOG_NO_THREADS)
146     //! Pointer to the thread-specific scope stack
147     thread_specific_ptr< scope_list > pScopes;
148 
149 #if defined(BOOST_LOG_USE_COMPILER_TLS)
150     //! Cached pointer to the thread-specific scope stack
151     static BOOST_LOG_TLS scope_list* pScopesCache;
152 #endif
153 
154 #else
155     //! Pointer to the scope stack
156     log::aux::unique_ptr< scope_list > pScopes;
157 #endif
158 
159     //! The method returns current thread scope stack
get_scope_listboost::attributes::named_scope::impl160     scope_list& get_scope_list()
161     {
162 #if defined(BOOST_LOG_USE_COMPILER_TLS)
163         scope_list* p = pScopesCache;
164 #else
165         scope_list* p = pScopes.get();
166 #endif
167         if (!p)
168         {
169             log::aux::unique_ptr< scope_list > pNew(new scope_list());
170             pScopes.reset(pNew.get());
171 #if defined(BOOST_LOG_USE_COMPILER_TLS)
172             pScopesCache = p = pNew.release();
173 #else
174             p = pNew.release();
175 #endif
176         }
177 
178         return *p;
179     }
180 
181     //! Instance initializer
init_instanceboost::attributes::named_scope::impl182     static void init_instance()
183     {
184         singleton_base_type::get_instance().reset(new impl());
185     }
186 
187     //! The method returns the actual attribute value. It must not return NULL.
get_valueboost::attributes::named_scope::impl188     attribute_value get_value()
189     {
190         return attribute_value(new named_scope_value(&get_scope_list()));
191     }
192 
193 private:
implboost::attributes::named_scope::impl194     impl() {}
195 };
196 
197 #if defined(BOOST_LOG_USE_COMPILER_TLS)
198 //! Cached pointer to the thread-specific scope stack
199 BOOST_LOG_TLS named_scope::impl::scope_list*
200 named_scope::impl::pScopesCache = NULL;
201 #endif // defined(BOOST_LOG_USE_COMPILER_TLS)
202 
203 
204 //! Copy constructor
named_scope_list(named_scope_list const & that)205 BOOST_LOG_API named_scope_list::named_scope_list(named_scope_list const& that) :
206     allocator_type(static_cast< allocator_type const& >(that)),
207     m_Size(that.size()),
208     m_fNeedToDeallocate(!that.empty())
209 {
210     if (m_Size > 0)
211     {
212         // Copy the container contents
213         pointer p = allocator_type::allocate(that.size());
214         aux::named_scope_list_node* prev = &m_RootNode;
215         for (const_iterator src = that.begin(), end = that.end(); src != end; ++src, ++p)
216         {
217             allocator_type::construct(p, *src); // won't throw
218             p->_m_pPrev = prev;
219             prev->_m_pNext = p;
220             prev = p;
221         }
222         m_RootNode._m_pPrev = prev;
223         prev->_m_pNext = &m_RootNode;
224     }
225 }
226 
227 //! Destructor
~named_scope_list()228 BOOST_LOG_API named_scope_list::~named_scope_list()
229 {
230     if (m_fNeedToDeallocate)
231     {
232         iterator it(m_RootNode._m_pNext);
233         iterator end(&m_RootNode);
234         while (it != end)
235             allocator_type::destroy(&*(it++));
236         allocator_type::deallocate(static_cast< pointer >(m_RootNode._m_pNext), m_Size);
237     }
238 }
239 
240 //! Swaps two instances of the container
swap(named_scope_list & that)241 BOOST_LOG_API void named_scope_list::swap(named_scope_list& that)
242 {
243     if (!this->empty())
244     {
245         if (!that.empty())
246         {
247             // both containers are not empty
248             std::swap(m_RootNode._m_pNext->_m_pPrev, that.m_RootNode._m_pNext->_m_pPrev);
249             std::swap(m_RootNode._m_pPrev->_m_pNext, that.m_RootNode._m_pPrev->_m_pNext);
250             std::swap(m_RootNode, that.m_RootNode);
251             std::swap(m_Size, that.m_Size);
252             std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
253         }
254         else
255         {
256             // this is not empty
257             m_RootNode._m_pNext->_m_pPrev = m_RootNode._m_pPrev->_m_pNext = &that.m_RootNode;
258             that.m_RootNode = m_RootNode;
259             m_RootNode._m_pNext = m_RootNode._m_pPrev = &m_RootNode;
260             std::swap(m_Size, that.m_Size);
261             std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
262         }
263     }
264     else if (!that.empty())
265     {
266         // that is not empty
267         that.m_RootNode._m_pNext->_m_pPrev = that.m_RootNode._m_pPrev->_m_pNext = &m_RootNode;
268         m_RootNode = that.m_RootNode;
269         that.m_RootNode._m_pNext = that.m_RootNode._m_pPrev = &that.m_RootNode;
270         std::swap(m_Size, that.m_Size);
271         std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
272     }
273 }
274 
275 //! Constructor
named_scope()276 named_scope::named_scope() :
277     attribute(impl::instance)
278 {
279 }
280 
281 //! Constructor for casting support
named_scope(cast_source const & source)282 named_scope::named_scope(cast_source const& source) :
283     attribute(source.as< impl >())
284 {
285 }
286 
287 //! The method pushes the scope to the stack
push_scope(scope_entry const & entry)288 void named_scope::push_scope(scope_entry const& entry) BOOST_NOEXCEPT
289 {
290     impl::scope_list& s = impl::instance->get_scope_list();
291     s.push_back(entry);
292 }
293 
294 //! The method pops the top scope
pop_scope()295 void named_scope::pop_scope() BOOST_NOEXCEPT
296 {
297     impl::scope_list& s = impl::instance->get_scope_list();
298     s.pop_back();
299 }
300 
301 //! Returns the current thread's scope stack
get_scopes()302 named_scope::value_type const& named_scope::get_scopes()
303 {
304     return impl::instance->get_scope_list();
305 }
306 
307 } // namespace attributes
308 
309 BOOST_LOG_CLOSE_NAMESPACE // namespace log
310 
311 } // namespace boost
312 
313 #include <boost/log/detail/footer.hpp>
314