Coverage Report

Created: 2026-05-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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