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_id.cpp
9 * \author Andrey Semashev
10 * \date 08.1.2012
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
18#if !defined(BOOST_LOG_NO_THREADS)
19
20#include <new>
21#include <iostream>
22#include <boost/throw_exception.hpp>
23#if !defined(BOOST_WINDOWS)
24#include <cstring>
25#include <boost/predef/other/endian.h>
26#endif
27#include <boost/log/detail/thread_id.hpp>
28#if defined(BOOST_LOG_USE_COMPILER_TLS)
29#include <boost/aligned_storage.hpp>
30#include <boost/type_traits/alignment_of.hpp>
31#elif defined(BOOST_WINDOWS)
32#include <boost/thread/thread.hpp>
33#include <boost/log/detail/thread_specific.hpp>
34#else
35#include <boost/log/exceptions.hpp>
36#include <boost/log/utility/once_block.hpp>
37#endif
38#if !defined(BOOST_LOG_USE_COMPILER_TLS)
39#include <boost/log/detail/singleton.hpp>
40#endif
41#include "id_formatting.hpp"
42#include <boost/log/detail/header.hpp>
43
44#if defined(BOOST_WINDOWS)
45
46#include <windows.h>
47
48namespace boost {
49
50BOOST_LOG_OPEN_NAMESPACE
51
52namespace aux {
53
54enum { tid_size = sizeof(GetCurrentThreadId()) };
55
56BOOST_LOG_ANONYMOUS_NAMESPACE {
57
58 //! The function returns current process identifier
59 inline thread::id get_id_impl()
60 {
61 return thread::id(GetCurrentThreadId());
62 }
63
64} // namespace
65
66} // namespace aux
67
68BOOST_LOG_CLOSE_NAMESPACE // namespace log
69
70} // namespace boost
71
72#else // defined(BOOST_WINDOWS)
73
74#include <pthread.h>
75
76namespace boost {
77
78BOOST_LOG_OPEN_NAMESPACE
79
80namespace aux {
81
82enum
83{
84 headroom_size = sizeof(pthread_t) > sizeof(uintmax_t) ? 0u : (sizeof(uintmax_t) - sizeof(pthread_t)),
85 tid_size = sizeof(uintmax_t) - headroom_size
86};
87
88BOOST_LOG_ANONYMOUS_NAMESPACE {
89
90 //! The function returns current thread identifier
91 inline thread::id get_id_impl()
92 {
93 // According to POSIX, pthread_t may not be an integer type:
94 // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
95 // For now we use the hackish cast to get some opaque number that hopefully correlates with system thread identification.
96 thread::id::native_type int_id = 0;
97 pthread_t pthread_id = pthread_self();
98#if BOOST_ENDIAN_BIG_BYTE || BOOST_ENDIAN_BIG_WORD
99 std::memcpy(reinterpret_cast< unsigned char* >(&int_id) + headroom_size, &pthread_id, tid_size);
100#else
101 std::memcpy(dest: &int_id, src: &pthread_id, n: tid_size);
102#endif
103 return thread::id(int_id);
104 }
105
106} // namespace
107
108} // namespace aux
109
110BOOST_LOG_CLOSE_NAMESPACE // namespace log
111
112} // namespace boost
113
114#endif // defined(BOOST_WINDOWS)
115
116
117namespace boost {
118
119BOOST_LOG_OPEN_NAMESPACE
120
121namespace aux {
122
123namespace this_thread {
124
125#if defined(BOOST_LOG_USE_COMPILER_TLS)
126
127BOOST_LOG_ANONYMOUS_NAMESPACE {
128
129struct id_storage
130{
131 aligned_storage< sizeof(thread::id), alignment_of< thread::id >::value >::type m_storage;
132 bool m_initialized;
133};
134
135BOOST_LOG_TLS id_storage g_id_storage = {};
136
137} // namespace
138
139//! The function returns current thread identifier
140BOOST_LOG_API thread::id const& get_id()
141{
142 id_storage& s = g_id_storage;
143 if (BOOST_UNLIKELY(!s.m_initialized))
144 {
145 new (s.m_storage.address()) thread::id(get_id_impl());
146 s.m_initialized = true;
147 }
148
149 return *static_cast< thread::id const* >(s.m_storage.address());
150}
151
152#elif defined(BOOST_WINDOWS)
153
154BOOST_LOG_ANONYMOUS_NAMESPACE {
155
156struct id_storage :
157 lazy_singleton< id_storage >
158{
159 struct deleter
160 {
161 typedef void result_type;
162
163 explicit deleter(thread::id const* p) : m_p(p) {}
164
165 result_type operator() () const
166 {
167 delete m_p;
168 }
169
170 private:
171 thread::id const* m_p;
172 };
173
174 thread_specific< thread::id const* > m_id;
175};
176
177} // namespace
178
179//! The function returns current thread identifier
180BOOST_LOG_API thread::id const& get_id()
181{
182 id_storage& s = id_storage::get();
183 thread::id const* p = s.m_id.get();
184 if (BOOST_UNLIKELY(!p))
185 {
186 p = new thread::id(get_id_impl());
187 s.m_id.set(p);
188 boost::this_thread::at_thread_exit(id_storage::deleter(p));
189 }
190
191 return *p;
192}
193
194#else
195
196BOOST_LOG_ANONYMOUS_NAMESPACE {
197
198pthread_key_t g_key;
199
200void deleter(void* p)
201{
202 delete static_cast< thread::id* >(p);
203}
204
205} // namespace
206
207//! The function returns current thread identifier
208BOOST_LOG_API thread::id const& get_id()
209{
210 BOOST_LOG_ONCE_BLOCK()
211 {
212 if (int err = pthread_key_create(key: &g_key, destr_function: &deleter))
213 {
214 BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create a thread-specific storage for thread id", (err));
215 }
216 }
217
218 thread::id* p = static_cast< thread::id* >(pthread_getspecific(key: g_key));
219 if (BOOST_UNLIKELY(!p))
220 {
221 p = new thread::id(get_id_impl());
222 pthread_setspecific(key: g_key, pointer: p);
223 }
224
225 return *p;
226}
227
228#endif
229
230} // namespace this_thread
231
232// Used in default_sink.cpp
233void format_thread_id(char* buf, std::size_t size, thread::id tid)
234{
235 format_id< tid_size >(buf, size, id: tid.native_id(), uppercase: false);
236}
237
238template< typename CharT, typename TraitsT >
239BOOST_LOG_API std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, thread::id const& tid)
240{
241 if (strm.good())
242 {
243 CharT buf[tid_size * 2 + 3]; // 2 chars per byte + 3 chars for the leading 0x and terminating zero
244 format_id< tid_size >(buf, sizeof(buf) / sizeof(*buf), tid.native_id(), (strm.flags() & std::ios_base::uppercase) != 0);
245
246 strm << buf;
247 }
248
249 return strm;
250}
251
252#if defined(BOOST_LOG_USE_CHAR)
253template BOOST_LOG_API
254std::basic_ostream< char, std::char_traits< char > >&
255operator<< (std::basic_ostream< char, std::char_traits< char > >& strm, thread::id const& tid);
256#endif // defined(BOOST_LOG_USE_CHAR)
257
258#if defined(BOOST_LOG_USE_WCHAR_T)
259template BOOST_LOG_API
260std::basic_ostream< wchar_t, std::char_traits< wchar_t > >&
261operator<< (std::basic_ostream< wchar_t, std::char_traits< wchar_t > >& strm, thread::id const& tid);
262#endif // defined(BOOST_LOG_USE_WCHAR_T)
263
264} // namespace aux
265
266BOOST_LOG_CLOSE_NAMESPACE // namespace log
267
268} // namespace boost
269
270#include <boost/log/detail/footer.hpp>
271
272#endif // !defined(BOOST_LOG_NO_THREADS)
273

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