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 | |
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 | |
45 | thread_specific_base::~thread_specific_base() |
46 | { |
47 | TlsFree(m_Key); |
48 | } |
49 | |
50 | void* thread_specific_base::get_content() const |
51 | { |
52 | return TlsGetValue(m_Key); |
53 | } |
54 | |
55 | 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(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 | |
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(stg&: m_Key); |
260 | } |
261 | |
262 | thread_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 | |
268 | void* 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 | |
274 | 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(stg: 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 | |