• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   thread_specific.cpp
9  * \author Andrey Semashev
10  * \date   01.03.2008
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 <string>
18 #include <stdexcept>
19 #include <boost/log/exceptions.hpp>
20 #include <boost/log/detail/thread_specific.hpp>
21 
22 #if !defined(BOOST_LOG_NO_THREADS)
23 
24 #if defined(BOOST_THREAD_PLATFORM_WIN32)
25 
26 #include <windows.h>
27 #include <boost/system/error_code.hpp>
28 #include <boost/log/detail/header.hpp>
29 
30 namespace boost {
31 
32 BOOST_LOG_OPEN_NAMESPACE
33 
34 namespace aux {
35 
thread_specific_base()36 thread_specific_base::thread_specific_base()
37 {
38     m_Key = TlsAlloc();
39     if (BOOST_UNLIKELY(m_Key == TLS_OUT_OF_INDEXES))
40     {
41         BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (boost::system::errc::not_enough_memory));
42     }
43 }
44 
~thread_specific_base()45 thread_specific_base::~thread_specific_base()
46 {
47     TlsFree(m_Key);
48 }
49 
get_content() const50 void* thread_specific_base::get_content() const
51 {
52     return TlsGetValue(m_Key);
53 }
54 
set_content(void * value) const55 void thread_specific_base::set_content(void* value) const
56 {
57     TlsSetValue(m_Key, value);
58 }
59 
60 } // namespace aux
61 
62 BOOST_LOG_CLOSE_NAMESPACE // namespace log
63 
64 } // namespace boost
65 
66 #elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
67 
68 #include <cstddef>
69 #include <cstring>
70 #include <pthread.h>
71 #include <boost/cstdint.hpp>
72 #include <boost/type_traits/conditional.hpp>
73 #include <boost/type_traits/is_integral.hpp>
74 #include <boost/type_traits/is_signed.hpp>
75 #include <boost/log/detail/header.hpp>
76 
77 namespace boost {
78 
79 BOOST_LOG_OPEN_NAMESPACE
80 
81 namespace aux {
82 
83 BOOST_LOG_ANONYMOUS_NAMESPACE {
84 
85 //! Some portability magic to detect how to store the TLS key
86 template< typename KeyT, bool IsStoreableV = sizeof(KeyT) <= sizeof(void*), bool IsIntegralV = boost::is_integral< KeyT >::value >
87 struct pthread_key_traits
88 {
89     typedef KeyT pthread_key_type;
90 
91     static void allocate(void*& stg)
92     {
93         pthread_key_type* pkey = new pthread_key_type();
94         const int res = pthread_key_create(pkey, NULL);
95         if (BOOST_UNLIKELY(res != 0))
96         {
97             delete pkey;
98             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
99         }
100         stg = pkey;
101     }
102 
103     static void deallocate(void* stg)
104     {
105         pthread_key_type* pkey = static_cast< pthread_key_type* >(stg);
106         pthread_key_delete(*pkey);
107         delete pkey;
108     }
109 
110     static void set_value(void* stg, void* value)
111     {
112         const int res = pthread_setspecific(*static_cast< pthread_key_type* >(stg), value);
113         if (BOOST_UNLIKELY(res != 0))
114         {
115             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
116         }
117     }
118 
119     static void* get_value(void* stg)
120     {
121         return pthread_getspecific(*static_cast< pthread_key_type* >(stg));
122     }
123 };
124 
125 template< typename KeyT >
126 struct pthread_key_traits< KeyT, true, true >
127 {
128     typedef KeyT pthread_key_type;
129 
130 #if defined(BOOST_HAS_INTPTR_T)
131     typedef typename boost::conditional<
132         boost::is_signed< pthread_key_type >::value,
133         intptr_t,
134         uintptr_t
135     >::type intptr_type;
136 #else
137     typedef typename boost::conditional<
138         boost::is_signed< pthread_key_type >::value,
139         std::ptrdiff_t,
140         std::size_t
141     >::type intptr_type;
142 #endif
143 
144     static void allocate(void*& stg)
145     {
146         pthread_key_type key;
147         const int res = pthread_key_create(&key, NULL);
148         if (BOOST_UNLIKELY(res != 0))
149         {
150             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
151         }
152         stg = (void*)(intptr_type)key;
153     }
154 
155     static void deallocate(void* stg)
156     {
157         pthread_key_delete((pthread_key_type)(intptr_type)stg);
158     }
159 
160     static void set_value(void* stg, void* value)
161     {
162         const int res = pthread_setspecific((pthread_key_type)(intptr_type)stg, value);
163         if (BOOST_UNLIKELY(res != 0))
164         {
165             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
166         }
167     }
168 
169     static void* get_value(void* stg)
170     {
171         return pthread_getspecific((pthread_key_type)(intptr_type)stg);
172     }
173 };
174 
175 template< typename KeyT >
176 struct pthread_key_traits< KeyT, true, false >
177 {
178     typedef KeyT pthread_key_type;
179 
180     static void allocate(void*& stg)
181     {
182         pthread_key_type key;
183         const int res = pthread_key_create(&key, NULL);
184         if (BOOST_UNLIKELY(res != 0))
185         {
186             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
187         }
188         std::memset(&stg, 0, sizeof(stg));
189         std::memcpy(&stg, &key, sizeof(pthread_key_type));
190     }
191 
192     static void deallocate(void* stg)
193     {
194         pthread_key_type key;
195         std::memcpy(&key, &stg, sizeof(pthread_key_type));
196         pthread_key_delete(key);
197     }
198 
199     static void set_value(void* stg, void* value)
200     {
201         pthread_key_type key;
202         std::memcpy(&key, &stg, sizeof(pthread_key_type));
203         const int res = pthread_setspecific(key, value);
204         if (BOOST_UNLIKELY(res != 0))
205         {
206             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
207         }
208     }
209 
210     static void* get_value(void* stg)
211     {
212         pthread_key_type key;
213         std::memcpy(&key, &stg, sizeof(pthread_key_type));
214         return pthread_getspecific(key);
215     }
216 };
217 
218 template< typename KeyT >
219 struct pthread_key_traits< KeyT*, true, false >
220 {
221     typedef KeyT* pthread_key_type;
222 
223     static void allocate(void*& stg)
224     {
225         pthread_key_type key = NULL;
226         const int res = pthread_key_create(&key, NULL);
227         if (BOOST_UNLIKELY(res != 0))
228         {
229             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
230         }
231         stg = static_cast< void* >(key);
232     }
233 
234     static void deallocate(void* stg)
235     {
236         pthread_key_delete(static_cast< pthread_key_type >(stg));
237     }
238 
239     static void set_value(void* stg, void* value)
240     {
241         const int res = pthread_setspecific(static_cast< pthread_key_type >(stg), value);
242         if (BOOST_UNLIKELY(res != 0))
243         {
244             BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
245         }
246     }
247 
248     static void* get_value(void* stg)
249     {
250         return pthread_getspecific(static_cast< pthread_key_type >(stg));
251     }
252 };
253 
254 } // namespace
255 
256 thread_specific_base::thread_specific_base()
257 {
258     typedef pthread_key_traits< pthread_key_t > traits_t;
259     traits_t::allocate(m_Key);
260 }
261 
~thread_specific_base()262 thread_specific_base::~thread_specific_base()
263 {
264     typedef pthread_key_traits< pthread_key_t > traits_t;
265     traits_t::deallocate(m_Key);
266 }
267 
get_content() const268 void* thread_specific_base::get_content() const
269 {
270     typedef pthread_key_traits< pthread_key_t > traits_t;
271     return traits_t::get_value(m_Key);
272 }
273 
set_content(void * value) const274 void thread_specific_base::set_content(void* value) const
275 {
276     typedef pthread_key_traits< pthread_key_t > traits_t;
277     traits_t::set_value(m_Key, value);
278 }
279 
280 } // namespace aux
281 
282 BOOST_LOG_CLOSE_NAMESPACE // namespace log
283 
284 } // namespace boost
285 
286 #else
287 #error Boost.Log: unsupported threading API
288 #endif
289 
290 #include <boost/log/detail/footer.hpp>
291 
292 #endif // !defined(BOOST_LOG_NO_THREADS)
293