/src/dcmtk/oflog/libsrc/threads.cc
Line | Count | Source |
1 | | // Module: Log4CPLUS |
2 | | // File: threads.cxx |
3 | | // Created: 6/2001 |
4 | | // Author: Tad E. Smith |
5 | | // |
6 | | // |
7 | | // Copyright 2001-2010 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 "dcmtk/oflog/config.h" |
22 | | |
23 | | #include <exception> |
24 | | #include <ostream> |
25 | | #include <cerrno> |
26 | | |
27 | | #ifdef DCMTK_LOG4CPLUS_HAVE_SYS_TYPES_H |
28 | | #include <sys/types.h> |
29 | | #endif |
30 | | |
31 | | #ifdef DCMTK_LOG4CPLUS_HAVE_SYS_SYSCALL_H |
32 | | #include <sys/syscall.h> |
33 | | #endif |
34 | | |
35 | | #ifdef DCMTK_LOG4CPLUS_HAVE_ERRNO_H |
36 | | #include <errno.h> |
37 | | #endif |
38 | | |
39 | | #ifdef DCMTK_LOG4CPLUS_HAVE_UNISTD_H |
40 | | #include <unistd.h> |
41 | | #endif |
42 | | |
43 | | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
44 | | # include <pthread.h> |
45 | | # include <sched.h> |
46 | | # include <signal.h> |
47 | | #elif defined (DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
48 | | # include <process.h> |
49 | | #endif |
50 | | #include "dcmtk/oflog/config/windowsh.h" |
51 | | #include "dcmtk/oflog/thread/syncpub.h" |
52 | | #include "dcmtk/oflog/tstring.h" |
53 | | #include "dcmtk/oflog/internal/cygwin32.h" |
54 | | #include "dcmtk/oflog/streams.h" |
55 | | |
56 | | #ifndef DCMTK_LOG4CPLUS_SINGLE_THREADED |
57 | | |
58 | | #include "dcmtk/oflog/thread/threads.h" |
59 | | #include "dcmtk/oflog/thread/impl/thredimp.h" |
60 | | #include "dcmtk/oflog/thread/impl/tls.h" |
61 | | #include "dcmtk/oflog/ndc.h" |
62 | | #include "dcmtk/oflog/helpers/loglog.h" |
63 | | #include "dcmtk/oflog/helpers/strhelp.h" |
64 | | #include "dcmtk/oflog/helpers/timehelp.h" |
65 | | #include "dcmtk/oflog/internal/internal.h" |
66 | | |
67 | | #endif // DCMTK_LOG4CPLUS_SINGLE_THREADED |
68 | | |
69 | | |
70 | | namespace dcmtk { |
71 | | namespace log4cplus { namespace thread { |
72 | | |
73 | | DCMTK_LOG4CPLUS_EXPORT |
74 | | void |
75 | | blockAllSignals() |
76 | 0 | { |
77 | 0 | #if defined (DCMTK_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, 0); |
82 | 0 | #endif |
83 | 0 | } |
84 | | |
85 | | |
86 | | DCMTK_LOG4CPLUS_EXPORT |
87 | | void |
88 | | yield() |
89 | 0 | { |
90 | 0 | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
91 | 0 | sched_yield(); |
92 | | #elif defined(_WIN32) |
93 | | if (! SwitchToThread ()) |
94 | | Sleep (0); |
95 | | #endif |
96 | 0 | } |
97 | | |
98 | | |
99 | | DCMTK_LOG4CPLUS_EXPORT |
100 | | log4cplus::tstring const & |
101 | | getCurrentThreadName() |
102 | 0 | { |
103 | 0 | #if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED) |
104 | 0 | log4cplus::tstring & name = log4cplus::internal::get_thread_name_str (); |
105 | 0 | if (name.empty ()) |
106 | 0 | { |
107 | 0 | log4cplus::tostringstream tmp; |
108 | 0 | tmp << impl::getCurrentThreadId (); |
109 | | // tmp.str ().swap (name); |
110 | 0 | name = OFString(tmp.str().c_str(), tmp.str().length()); |
111 | 0 | } |
112 | | #else |
113 | | static log4cplus::tstring const name (DCMTK_LOG4CPLUS_TEXT ("single")); |
114 | | #endif |
115 | |
|
116 | 0 | return name; |
117 | 0 | } |
118 | | |
119 | | |
120 | | #ifndef DCMTK_LOG4CPLUS_SINGLE_THREADED |
121 | | |
122 | | namespace |
123 | | { |
124 | | |
125 | | static |
126 | | bool |
127 | | get_current_thread_name_alt (log4cplus::tostream * s) |
128 | 0 | { |
129 | 0 | log4cplus::tostream & os = *s; |
130 | |
|
131 | 0 | #if defined (DCMTK_LOG4CPLUS_USE_PTHREADS) && defined (__linux__) \ |
132 | 0 | && defined (DCMTK_LOG4CPLUS_HAVE_GETTID) |
133 | 0 | pid_t tid = OFstatic_cast(pid_t, syscall (SYS_gettid)); |
134 | 0 | os << tid; |
135 | |
|
136 | | #elif defined (__CYGWIN__) |
137 | | unsigned long tid = cygwin::get_current_win32_thread_id (); |
138 | | os << tid; |
139 | | |
140 | | #else |
141 | | os << getCurrentThreadName (); |
142 | | |
143 | | #endif |
144 | |
|
145 | 0 | return true; |
146 | 0 | } |
147 | | |
148 | | |
149 | | } // namespace |
150 | | |
151 | | #endif // DCMTK_LOG4CPLUS_SINGLE_THREADED |
152 | | |
153 | | |
154 | | DCMTK_LOG4CPLUS_EXPORT |
155 | | log4cplus::tstring const & |
156 | | getCurrentThreadName2() |
157 | 0 | { |
158 | 0 | #if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED) |
159 | 0 | log4cplus::tstring & name = log4cplus::internal::get_thread_name2_str (); |
160 | 0 | if (name.empty ()) |
161 | 0 | { |
162 | 0 | log4cplus::tostringstream tmp; |
163 | 0 | get_current_thread_name_alt (&tmp); |
164 | 0 | name = OFString(tmp.str().c_str(), tmp.str().length()); |
165 | 0 | } |
166 | |
|
167 | | #else |
168 | | static log4cplus::tstring const name (getCurrentThreadName ()); |
169 | | |
170 | | #endif |
171 | |
|
172 | 0 | return name; |
173 | 0 | } |
174 | | |
175 | | |
176 | | } } // namespace log4cplus { namespace thread { |
177 | | } // end namespace dcmtk |
178 | | |
179 | | |
180 | | #ifndef DCMTK_LOG4CPLUS_SINGLE_THREADED |
181 | | |
182 | | namespace |
183 | | { |
184 | | |
185 | | # ifdef DCMTK_LOG4CPLUS_USE_PTHREADS |
186 | | extern "C" void* threadStartFunc(void * param) |
187 | | # elif defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
188 | | static unsigned WINAPI threadStartFunc(void * param) |
189 | | # endif |
190 | 0 | { |
191 | 0 | return dcmtk::log4cplus::thread::impl::ThreadStart::threadStartFuncWorker (param); |
192 | 0 | } |
193 | | |
194 | | } // namespace |
195 | | |
196 | | |
197 | | namespace dcmtk { |
198 | | namespace log4cplus { namespace thread { namespace impl { |
199 | | |
200 | | |
201 | | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
202 | | void* |
203 | | ThreadStart::threadStartFuncWorker(void * arg) |
204 | | #elif defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
205 | | unsigned |
206 | | ThreadStart::threadStartFuncWorker(void * arg) |
207 | | #endif |
208 | 0 | { |
209 | 0 | blockAllSignals (); |
210 | 0 | helpers::LogLog * loglog = helpers::LogLog::getLogLog(); |
211 | 0 | if (! arg) |
212 | 0 | loglog->error(DCMTK_LOG4CPLUS_TEXT("threadStartFunc()- arg is NULL")); |
213 | 0 | else |
214 | 0 | { |
215 | 0 | Thread * ptr = OFstatic_cast(Thread *, arg); |
216 | 0 | ThreadPtr thread(ptr); |
217 | | |
218 | | // Decrease reference count increased by Thread::start(). |
219 | 0 | ptr->removeReference (); |
220 | |
|
221 | 0 | try |
222 | 0 | { |
223 | 0 | thread->run(); |
224 | 0 | } |
225 | 0 | catch(STD_NAMESPACE exception const & e) |
226 | 0 | { |
227 | 0 | tstring err = DCMTK_LOG4CPLUS_TEXT("threadStartFunc()- run() terminated with an exception: "); |
228 | 0 | err += DCMTK_LOG4CPLUS_C_STR_TO_TSTRING(e.what()); |
229 | 0 | loglog->warn(err); |
230 | 0 | } |
231 | 0 | catch(...) |
232 | 0 | { |
233 | 0 | loglog->warn(DCMTK_LOG4CPLUS_TEXT("threadStartFunc()- run() terminated with an exception.")); |
234 | 0 | } |
235 | |
|
236 | 0 | thread::MutexGuard guard (thread->access_mutex); |
237 | 0 | thread->flags &= ~Thread::fRUNNING; |
238 | 0 | } |
239 | |
|
240 | 0 | threadCleanup (); |
241 | |
|
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | |
246 | | Thread::Thread() |
247 | 0 | : flags (0) |
248 | | #if defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
249 | | , handle (INVALID_HANDLE_VALUE) |
250 | | , thread_id (0) |
251 | | #else |
252 | | , handle () |
253 | | #endif |
254 | 0 | { |
255 | 0 | } |
256 | | |
257 | | |
258 | | Thread::~Thread() |
259 | 0 | { |
260 | 0 | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
261 | 0 | if ((flags & fJOINED) == 0) |
262 | 0 | pthread_detach (handle); |
263 | |
|
264 | | #elif defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
265 | | if (handle != INVALID_HANDLE_VALUE) |
266 | | ::CloseHandle (handle); |
267 | | |
268 | | #endif |
269 | 0 | } |
270 | | |
271 | | |
272 | | void |
273 | | Thread::start() |
274 | 0 | { |
275 | 0 | flags |= fRUNNING; |
276 | | |
277 | | // Increase reference count here. It will be lowered by the running |
278 | | // thread itself. |
279 | 0 | addReference (); |
280 | |
|
281 | 0 | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
282 | 0 | if (pthread_create(&handle, NULL, threadStartFunc, this) ) |
283 | 0 | { |
284 | 0 | removeReference (); |
285 | 0 | flags &= ~fRUNNING; |
286 | 0 | log4cplus::helpers::LogLog::getLogLog ()->error ( |
287 | 0 | DCMTK_LOG4CPLUS_TEXT ("Thread creation was not successful"), true); |
288 | 0 | } |
289 | | #elif defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
290 | | HANDLE h = handle; |
291 | | handle = INVALID_HANDLE_VALUE; |
292 | | if (h != INVALID_HANDLE_VALUE) |
293 | | ::CloseHandle (h); |
294 | | |
295 | | h = OFreinterpret_cast(HANDLE, |
296 | | ::_beginthreadex (0, 0, threadStartFunc, this, 0, &thread_id)); |
297 | | handle = h; |
298 | | if (! h) |
299 | | { |
300 | | removeReference (); |
301 | | flags &= ~fRUNNING; |
302 | | log4cplus::helpers::LogLog::getLogLog ()->error ( |
303 | | DCMTK_LOG4CPLUS_TEXT ("Thread creation was not successful"), true); |
304 | | } |
305 | | #endif |
306 | 0 | } |
307 | | |
308 | | |
309 | | bool |
310 | | Thread::isRunning() const |
311 | 0 | { |
312 | 0 | thread::MutexGuard guard (access_mutex); |
313 | 0 | return (flags & fRUNNING) != 0; |
314 | 0 | } |
315 | | |
316 | | |
317 | | os_id_type |
318 | | Thread::getThreadId () const |
319 | 0 | { |
320 | 0 | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
321 | 0 | return handle; |
322 | | #elif defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
323 | | return thread_id; |
324 | | #endif |
325 | 0 | } |
326 | | |
327 | | |
328 | | os_handle_type |
329 | | Thread::getThreadHandle () const |
330 | 0 | { |
331 | 0 | return handle; |
332 | 0 | } |
333 | | |
334 | | |
335 | | void |
336 | | Thread::join () |
337 | 0 | { |
338 | 0 | #if defined(DCMTK_LOG4CPLUS_USE_PTHREADS) |
339 | 0 | pthread_join (handle, 0); |
340 | | #elif defined(DCMTK_LOG4CPLUS_USE_WIN32_THREADS) |
341 | | ::WaitForSingleObject (handle, INFINITE); |
342 | | #endif |
343 | 0 | flags |= fJOINED; |
344 | 0 | } |
345 | | |
346 | | |
347 | | } // namespace impl { |
348 | | |
349 | | |
350 | | // |
351 | | // |
352 | | // |
353 | | |
354 | | ThreadImplBase::~ThreadImplBase () |
355 | 0 | { } |
356 | | |
357 | | |
358 | | // |
359 | | // |
360 | | // |
361 | | |
362 | | |
363 | | namespace |
364 | | { |
365 | | |
366 | | |
367 | | class ThreadImpl |
368 | | : public impl::Thread |
369 | | { |
370 | | public: |
371 | | ThreadImpl () |
372 | 0 | : abs_thread (0) |
373 | 0 | { } |
374 | | |
375 | | virtual ~ThreadImpl () |
376 | 0 | { } |
377 | | |
378 | | virtual |
379 | | void |
380 | | run () |
381 | 0 | { |
382 | 0 | abs_thread->run (); |
383 | 0 | } |
384 | | |
385 | | void |
386 | | set_abs_thread (AbstractThread * at) |
387 | 0 | { |
388 | 0 | abs_thread = at; |
389 | 0 | } |
390 | | |
391 | | protected: |
392 | | AbstractThread * abs_thread; |
393 | | |
394 | | private: |
395 | | ThreadImpl(const ThreadImpl&); |
396 | | ThreadImpl& operator=(const ThreadImpl&); |
397 | | }; |
398 | | |
399 | | |
400 | | } // namespace |
401 | | |
402 | | |
403 | | // |
404 | | // |
405 | | // |
406 | | |
407 | | AbstractThread::AbstractThread () |
408 | 0 | : thread (new ThreadImpl) |
409 | 0 | { |
410 | 0 | OFstatic_cast(ThreadImpl *, thread.get ())->set_abs_thread (this); |
411 | 0 | } |
412 | | |
413 | | |
414 | | bool |
415 | | AbstractThread::isRunning() const |
416 | 0 | { |
417 | 0 | return OFstatic_cast(ThreadImpl *, thread.get ())->isRunning (); |
418 | 0 | } |
419 | | |
420 | | |
421 | | void |
422 | | AbstractThread::start() |
423 | 0 | { |
424 | 0 | OFstatic_cast(ThreadImpl *, thread.get ())->start (); |
425 | 0 | } |
426 | | |
427 | | |
428 | | void |
429 | | AbstractThread::join () const |
430 | 0 | { |
431 | 0 | OFstatic_cast(ThreadImpl *, thread.get ())->join (); |
432 | 0 | } |
433 | | |
434 | | |
435 | | AbstractThread::~AbstractThread() |
436 | 0 | { } |
437 | | |
438 | | |
439 | | } } // namespace log4cplus { namespace thread { |
440 | | } // end namespace dcmtk |
441 | | |
442 | | |
443 | | #endif // DCMTK_LOG4CPLUS_SINGLE_THREADED |