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
30namespace boost {
31
32BOOST_LOG_OPEN_NAMESPACE
33
34namespace aux {
35
36thread_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
45thread_specific_base::~thread_specific_base()
46{
47 TlsFree(m_Key);
48}
49
50void* thread_specific_base::get_content() const
51{
52 return TlsGetValue(m_Key);
53}
54
55void thread_specific_base::set_content(void* value) const
56{
57 TlsSetValue(m_Key, value);
58}
59
60} // namespace aux
61
62BOOST_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
77namespace boost {
78
79BOOST_LOG_OPEN_NAMESPACE
80
81namespace aux {
82
83BOOST_LOG_ANONYMOUS_NAMESPACE {
84
85//! Some portability magic to detect how to store the TLS key
86template< typename KeyT, bool IsStoreableV = sizeof(KeyT) <= sizeof(void*), bool IsIntegralV = boost::is_integral< KeyT >::value >
87struct 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
125template< typename KeyT >
126struct 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
175template< typename KeyT >
176struct 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(s: &stg, c: 0, n: sizeof(stg));
189 std::memcpy(dest: &stg, src: &key, n: sizeof(pthread_key_type));
190 }
191
192 static void deallocate(void* stg)
193 {
194 pthread_key_type key;
195 std::memcpy(dest: &key, src: &stg, n: 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(dest: &key, src: &stg, n: 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(dest: &key, src: &stg, n: sizeof(pthread_key_type));
214 return pthread_getspecific(key);
215 }
216};
217
218template< typename KeyT >
219struct 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
256thread_specific_base::thread_specific_base()
257{
258 typedef pthread_key_traits< pthread_key_t > traits_t;
259 traits_t::allocate(stg&: m_Key);
260}
261
262thread_specific_base::~thread_specific_base()
263{
264 typedef pthread_key_traits< pthread_key_t > traits_t;
265 traits_t::deallocate(stg: m_Key);
266}
267
268void* thread_specific_base::get_content() const
269{
270 typedef pthread_key_traits< pthread_key_t > traits_t;
271 return traits_t::get_value(stg: m_Key);
272}
273
274void thread_specific_base::set_content(void* value) const
275{
276 typedef pthread_key_traits< pthread_key_t > traits_t;
277 traits_t::set_value(stg: m_Key, value);
278}
279
280} // namespace aux
281
282BOOST_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

source code of boost/libs/log/src/thread_specific.cpp