/src/log4cplus/src/threads.cxx
Line | Count | Source |
1 | | // Module: Log4CPLUS |
2 | | // File: threads.cxx |
3 | | // Created: 6/2001 |
4 | | // Author: Tad E. Smith |
5 | | // |
6 | | // |
7 | | // Copyright 2001-2017 Tad E. Smith |
8 | | // |
9 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
10 | | // you may not use this file except in compliance with the License. |
11 | | // You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software |
16 | | // distributed under the License is distributed on an "AS IS" BASIS, |
17 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
18 | | // See the License for the specific language governing permissions and |
19 | | // limitations under the License. |
20 | | |
21 | | #include <log4cplus/config.hxx> |
22 | | |
23 | | #include <exception> |
24 | | #include <ostream> |
25 | | #include <cerrno> |
26 | | |
27 | | #ifdef LOG4CPLUS_HAVE_SYS_TYPES_H |
28 | | #include <sys/types.h> |
29 | | #endif |
30 | | |
31 | | #ifdef LOG4CPLUS_HAVE_SYS_SYSCALL_H |
32 | | #include <sys/syscall.h> |
33 | | #endif |
34 | | |
35 | | #ifdef LOG4CPLUS_HAVE_ERRNO_H |
36 | | #include <errno.h> |
37 | | #endif |
38 | | |
39 | | #ifdef LOG4CPLUS_HAVE_UNISTD_H |
40 | | #include <unistd.h> |
41 | | #endif |
42 | | |
43 | | #if defined(LOG4CPLUS_USE_PTHREADS) |
44 | | # include <pthread.h> |
45 | | # include <sched.h> |
46 | | # include <signal.h> |
47 | | #elif defined (LOG4CPLUS_USE_WIN32_THREADS) |
48 | | # include <process.h> |
49 | | #endif |
50 | | #include <log4cplus/config/windowsh-inc.h> |
51 | | #include <log4cplus/thread/syncprims-pub-impl.h> |
52 | | #include <log4cplus/tstring.h> |
53 | | #include <log4cplus/internal/cygwin-win32.h> |
54 | | #include <log4cplus/streams.h> |
55 | | |
56 | | #include <log4cplus/thread/threads.h> |
57 | | |
58 | | #ifndef LOG4CPLUS_SINGLE_THREADED |
59 | | |
60 | | #include <log4cplus/thread/impl/threads-impl.h> |
61 | | #include <log4cplus/thread/impl/tls.h> |
62 | | #include <log4cplus/ndc.h> |
63 | | #include <log4cplus/helpers/loglog.h> |
64 | | #include <log4cplus/helpers/stringhelper.h> |
65 | | #include <log4cplus/helpers/timehelper.h> |
66 | | #include <log4cplus/internal/internal.h> |
67 | | |
68 | | #endif // LOG4CPLUS_SINGLE_THREADED |
69 | | |
70 | | |
71 | | namespace log4cplus { namespace thread { |
72 | | |
73 | | LOG4CPLUS_EXPORT |
74 | | void |
75 | | blockAllSignals() |
76 | 0 | { |
77 | 0 | #if defined (LOG4CPLUS_USE_PTHREADS) |
78 | | // Block all signals. |
79 | 0 | sigset_t signal_set; |
80 | 0 | sigfillset (&signal_set); |
81 | 0 | pthread_sigmask (SIG_BLOCK, &signal_set, nullptr); |
82 | 0 | #endif |
83 | 0 | } |
84 | | |
85 | | |
86 | | LOG4CPLUS_EXPORT |
87 | | void |
88 | | yield() |
89 | 0 | { |
90 | 0 | #if defined(LOG4CPLUS_USE_PTHREADS) |
91 | 0 | sched_yield(); |
92 | | #elif defined(_WIN32) |
93 | | if (! SwitchToThread ()) |
94 | | Sleep (0); |
95 | | #endif |
96 | 0 | } |
97 | | |
98 | | #if defined(LOG4CPLUS_SINGLE_THREADED) |
99 | | static log4cplus::tstring thread_name |
100 | | LOG4CPLUS_INIT_PRIORITY (LOG4CPLUS_INIT_PRIORITY_BASE - 1) |
101 | | (LOG4CPLUS_TEXT("single")); |
102 | | static log4cplus::tstring thread_name2 |
103 | | LOG4CPLUS_INIT_PRIORITY (LOG4CPLUS_INIT_PRIORITY_BASE - 1) |
104 | | (thread_name); |
105 | | #endif |
106 | | |
107 | | LOG4CPLUS_EXPORT |
108 | | log4cplus::tstring const & |
109 | | getCurrentThreadName() |
110 | 604k | { |
111 | 604k | #if ! defined (LOG4CPLUS_SINGLE_THREADED) |
112 | 604k | log4cplus::tstring & name = log4cplus::internal::get_thread_name_str (); |
113 | 604k | if (LOG4CPLUS_UNLIKELY (name.empty ())) |
114 | 24 | { |
115 | 24 | log4cplus::tostringstream tmp; |
116 | 24 | tmp << impl::getCurrentThreadId (); |
117 | 24 | name = tmp.str (); |
118 | 24 | } |
119 | | #else |
120 | | log4cplus::tstring & name = thread_name; |
121 | | if (LOG4CPLUS_UNLIKELY(name.empty())) |
122 | | { |
123 | | name = LOG4CPLUS_TEXT("single"); |
124 | | } |
125 | | #endif |
126 | | |
127 | 604k | return name; |
128 | 604k | } |
129 | | |
130 | | |
131 | | namespace |
132 | | { |
133 | | |
134 | | |
135 | | static |
136 | | bool |
137 | | get_current_thread_name_alt (log4cplus::tostream * s) |
138 | 0 | { |
139 | 0 | log4cplus::tostream & os = *s; |
140 | |
|
141 | 0 | #if defined (LOG4CPLUS_USE_PTHREADS) && defined (__linux__) \ |
142 | 0 | && defined (LOG4CPLUS_HAVE_GETTID) |
143 | 0 | pid_t tid = syscall (SYS_gettid); |
144 | 0 | os << tid; |
145 | |
|
146 | | #elif defined (__CYGWIN__) |
147 | | unsigned long tid = cygwin::get_current_win32_thread_id (); |
148 | | os << tid; |
149 | | |
150 | | #else |
151 | | os << getCurrentThreadName (); |
152 | | |
153 | | #endif |
154 | |
|
155 | 0 | return true; |
156 | 0 | } |
157 | | |
158 | | |
159 | | } // namespace |
160 | | |
161 | | |
162 | | LOG4CPLUS_EXPORT |
163 | | log4cplus::tstring const & |
164 | | getCurrentThreadName2() |
165 | 0 | { |
166 | 0 | #if ! defined (LOG4CPLUS_SINGLE_THREADED) |
167 | 0 | log4cplus::tstring & name = log4cplus::internal::get_thread_name2_str (); |
168 | 0 | if (LOG4CPLUS_UNLIKELY (name.empty ())) |
169 | 0 | { |
170 | 0 | log4cplus::tostringstream tmp; |
171 | 0 | get_current_thread_name_alt (&tmp); |
172 | 0 | name = tmp.str (); |
173 | 0 | } |
174 | |
|
175 | | #else |
176 | | log4cplus::tstring & name = thread_name2; |
177 | | if (LOG4CPLUS_UNLIKELY(name.empty())) |
178 | | { |
179 | | name = getCurrentThreadName(); |
180 | | } |
181 | | |
182 | | #endif |
183 | |
|
184 | 0 | return name; |
185 | 0 | } |
186 | | |
187 | | LOG4CPLUS_EXPORT void setCurrentThreadName(const log4cplus::tstring & name) |
188 | 0 | { |
189 | 0 | #if ! defined (LOG4CPLUS_SINGLE_THREADED) |
190 | 0 | log4cplus::internal::get_thread_name_str() = name; |
191 | | #else |
192 | | thread_name = name; |
193 | | #endif |
194 | 0 | } |
195 | | |
196 | | LOG4CPLUS_EXPORT void setCurrentThreadName2(const log4cplus::tstring & name) |
197 | 0 | { |
198 | 0 | #if ! defined (LOG4CPLUS_SINGLE_THREADED) |
199 | 0 | log4cplus::internal::get_thread_name2_str() = name; |
200 | | #else |
201 | | thread_name2 = name; |
202 | | #endif |
203 | 0 | } |
204 | | |
205 | | |
206 | | // |
207 | | // |
208 | | // |
209 | | |
210 | | struct SignalsBlocker::SignalsBlockerImpl |
211 | | { |
212 | | #if defined (LOG4CPLUS_USE_PTHREADS) |
213 | | sigset_t signal_set; |
214 | | #endif |
215 | | }; |
216 | | |
217 | | |
218 | | SignalsBlocker::SignalsBlocker () |
219 | 36 | : impl (new SignalsBlocker::SignalsBlockerImpl) |
220 | 36 | { |
221 | 36 | #if defined (LOG4CPLUS_USE_PTHREADS) |
222 | 36 | sigset_t block_all_set; |
223 | 36 | sigfillset (&block_all_set); |
224 | 36 | (void) pthread_sigmask (SIG_BLOCK, &block_all_set, &impl->signal_set); |
225 | 36 | #endif |
226 | 36 | } |
227 | | |
228 | | |
229 | | SignalsBlocker::~SignalsBlocker() |
230 | 36 | { |
231 | 36 | #if defined (LOG4CPLUS_USE_PTHREADS) |
232 | 36 | (void) pthread_sigmask (SIG_SETMASK, &impl->signal_set, nullptr); |
233 | 36 | #endif |
234 | 36 | } |
235 | | |
236 | | |
237 | | #ifndef LOG4CPLUS_SINGLE_THREADED |
238 | | |
239 | | // |
240 | | // |
241 | | // |
242 | | |
243 | | AbstractThread::AbstractThread () |
244 | 0 | : flags (0) |
245 | 0 | { } |
246 | | |
247 | | |
248 | | bool |
249 | | AbstractThread::isRunning() const |
250 | 0 | { |
251 | 0 | return (flags & fRUNNING) != 0; |
252 | 0 | } |
253 | | |
254 | | |
255 | | void |
256 | | AbstractThread::start() |
257 | 0 | { |
258 | 0 | try |
259 | 0 | { |
260 | 0 | flags |= fRUNNING; |
261 | 0 | thread.reset ( |
262 | 0 | new std::thread ([this] (AbstractThreadPtr const & thread_ptr) { |
263 | 0 | (void) thread_ptr; |
264 | 0 | blockAllSignals (); |
265 | 0 | helpers::LogLog & loglog = helpers::getLogLog(); |
266 | 0 | try |
267 | 0 | { |
268 | 0 | this->run (); |
269 | 0 | } |
270 | 0 | catch (std::exception const & e) |
271 | 0 | { |
272 | 0 | tstring err (LOG4CPLUS_TEXT ("threadStartFunc()") |
273 | 0 | LOG4CPLUS_TEXT ("- run() terminated with an exception: ")); |
274 | 0 | err += LOG4CPLUS_C_STR_TO_TSTRING(e.what()); |
275 | 0 | loglog.warn(err); |
276 | 0 | } |
277 | 0 | catch(...) |
278 | 0 | { |
279 | 0 | loglog.warn(LOG4CPLUS_TEXT("threadStartFunc()") |
280 | 0 | LOG4CPLUS_TEXT ("- run() terminated with an exception.")); |
281 | 0 | } |
282 | 0 | this->flags &= ~fRUNNING; |
283 | 0 | threadCleanup (); |
284 | 0 | }, AbstractThreadPtr (this))); |
285 | 0 | } |
286 | 0 | catch (...) |
287 | 0 | { |
288 | 0 | flags &= ~fRUNNING; |
289 | 0 | throw; |
290 | 0 | } |
291 | 0 | } |
292 | | |
293 | | |
294 | | void |
295 | | AbstractThread::join () const |
296 | 0 | { |
297 | 0 | if (! thread |
298 | 0 | || (flags & fJOINED) == fJOINED) |
299 | 0 | throw std::logic_error ("this thread is not running"); |
300 | | |
301 | 0 | thread->join (); |
302 | 0 | flags |= +fJOINED; |
303 | 0 | } |
304 | | |
305 | | |
306 | | AbstractThread::~AbstractThread() |
307 | 0 | { |
308 | 0 | if ((flags & fJOINED) == 0) |
309 | 0 | thread->detach (); |
310 | 0 | } |
311 | | |
312 | | #endif // LOG4CPLUS_SINGLE_THREADED |
313 | | |
314 | | |
315 | | } } // namespace log4cplus { namespace thread { |