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
48 namespace boost {
49
50 BOOST_LOG_OPEN_NAMESPACE
51
52 namespace aux {
53
54 enum { tid_size = sizeof(GetCurrentThreadId()) };
55
56 BOOST_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
68 BOOST_LOG_CLOSE_NAMESPACE // namespace log
69
70 } // namespace boost
71
72 #else // defined(BOOST_WINDOWS)
73
74 #include <pthread.h>
75
76 namespace boost {
77
78 BOOST_LOG_OPEN_NAMESPACE
79
80 namespace aux {
81
82 enum
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
88 BOOST_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(&int_id, &pthread_id, tid_size);
102 #endif
103 return thread::id(int_id);
104 }
105
106 } // namespace
107
108 } // namespace aux
109
110 BOOST_LOG_CLOSE_NAMESPACE // namespace log
111
112 } // namespace boost
113
114 #endif // defined(BOOST_WINDOWS)
115
116
117 namespace boost {
118
119 BOOST_LOG_OPEN_NAMESPACE
120
121 namespace aux {
122
123 namespace this_thread {
124
125 #if defined(BOOST_LOG_USE_COMPILER_TLS)
126
127 BOOST_LOG_ANONYMOUS_NAMESPACE {
128
129 struct id_storage
130 {
131 aligned_storage< sizeof(thread::id), alignment_of< thread::id >::value >::type m_storage;
132 bool m_initialized;
133 };
134
135 BOOST_LOG_TLS id_storage g_id_storage = {};
136
137 } // namespace
138
139 //! The function returns current thread identifier
140 BOOST_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
154 BOOST_LOG_ANONYMOUS_NAMESPACE {
155
156 struct 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
180 BOOST_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
196 BOOST_LOG_ANONYMOUS_NAMESPACE {
197
198 pthread_key_t g_key;
199
200 void deleter(void* p)
201 {
202 delete static_cast< thread::id* >(p);
203 }
204
205 } // namespace
206
207 //! The function returns current thread identifier
208 BOOST_LOG_API thread::id const& get_id()
209 {
210 BOOST_LOG_ONCE_BLOCK()
211 {
212 if (int err = pthread_key_create(&g_key, &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(g_key));
219 if (BOOST_UNLIKELY(!p))
220 {
221 p = new thread::id(get_id_impl());
222 pthread_setspecific(g_key, p);
223 }
224
225 return *p;
226 }
227
228 #endif
229
230 } // namespace this_thread
231
232 // Used in default_sink.cpp
format_thread_id(char * buf,std::size_t size,thread::id tid)233 void format_thread_id(char* buf, std::size_t size, thread::id tid)
234 {
235 format_id< tid_size >(buf, size, tid.native_id(), false);
236 }
237
238 template< typename CharT, typename TraitsT >
operator <<(std::basic_ostream<CharT,TraitsT> & strm,thread::id const & tid)239 BOOST_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)
253 template BOOST_LOG_API
254 std::basic_ostream< char, std::char_traits< char > >&
255 operator<< (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)
259 template BOOST_LOG_API
260 std::basic_ostream< wchar_t, std::char_traits< wchar_t > >&
261 operator<< (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
266 BOOST_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