• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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