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