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