Coverage Report

Created: 2026-08-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oflog/libsrc/globinit.cc
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    global-init.cxx
3
// Created: 5/2003
4
// Author:  Tad E. Smith
5
//
6
//
7
// Copyright 2003-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
#include "dcmtk/oflog/config/windowsh.h"
23
#include "dcmtk/oflog/logger.h"
24
#include "dcmtk/oflog/ndc.h"
25
#include "dcmtk/oflog/mdc.h"
26
#include "dcmtk/oflog/helpers/loglog.h"
27
#include "dcmtk/oflog/internal/internal.h"
28
#include "dcmtk/oflog/thread/impl/tls.h"
29
#include "dcmtk/oflog/thread/syncpub.h"
30
#include "dcmtk/oflog/helpers/loglog.h"
31
#include "dcmtk/oflog/spi/factory.h"
32
#include "dcmtk/oflog/hierarchy.h"
33
#include "dcmtk/ofstd/ofconsol.h"
34
#include <cstdio>
35
#include <iostream>
36
#include <stdexcept>
37
38
39
// Forward Declarations
40
namespace dcmtk
41
{
42
namespace log4cplus
43
{
44
45
#ifdef DCMTK_OFLOG_UNICODE
46
DCMTK_LOG4CPLUS_EXPORT tostream & tcout = STD_NAMESPACE wcout;
47
DCMTK_LOG4CPLUS_EXPORT tostream & tcerr = STD_NAMESPACE wcerr;
48
49
#else
50
DCMTK_LOG4CPLUS_EXPORT tostream & tcout = COUT;
51
DCMTK_LOG4CPLUS_EXPORT tostream & tcerr = CERR;
52
53
#endif // UNICODE
54
55
56
namespace
57
{
58
59
60
//! Default context.
61
struct DefaultContext
62
{
63
    DefaultContext() :
64
6
        console_mutex(),
65
6
        loglog(),
66
6
        log_level_manager(),
67
6
        TTCCLayout_time_base(),
68
6
        ndc(),
69
6
        mdc(),
70
6
        hierarchy(),
71
6
        appender_factory_registry(),
72
6
        layout_factory_registry(),
73
6
        filter_factory_registry(),
74
6
        locale_factory_registry() {
75
6
    }
76
    log4cplus::thread::Mutex console_mutex;
77
    helpers::LogLog loglog;
78
    LogLevelManager log_level_manager;
79
    helpers::Time TTCCLayout_time_base;
80
    NDC ndc;
81
    MDC mdc;
82
    Hierarchy hierarchy;
83
    spi::AppenderFactoryRegistry appender_factory_registry;
84
    spi::LayoutFactoryRegistry layout_factory_registry;
85
    spi::FilterFactoryRegistry filter_factory_registry;
86
    spi::LocaleFactoryRegistry locale_factory_registry;
87
};
88
89
90
enum DCState
91
{
92
    DC_UNINITIALIZED,
93
    DC_INITIALIZED,
94
    DC_DESTROYED
95
};
96
97
98
static DCState default_context_state;
99
static DefaultContext * default_context;
100
101
102
struct destroy_default_context
103
{
104
    ~destroy_default_context ()
105
0
    {
106
0
        delete default_context;
107
0
        default_context = 0;
108
0
        default_context_state = DC_DESTROYED;
109
0
    }
110
} static destroy_default_context_;
111
112
113
static
114
void
115
alloc_dc ()
116
6
{
117
6
    assert (! default_context);
118
6
    assert (default_context_state == DC_UNINITIALIZED);
119
120
6
    if (default_context)
121
0
        throw STD_NAMESPACE logic_error (
122
0
            "alloc_dc() called with non-NULL default_context.");
123
124
6
    if (default_context_state == DC_INITIALIZED)
125
0
        throw STD_NAMESPACE logic_error ("alloc_dc() called in DC_INITIALIZED state.");
126
127
6
    default_context = new DefaultContext;
128
129
6
    if (default_context_state == DC_DESTROYED)
130
0
        default_context->loglog.error (
131
0
            DCMTK_LOG4CPLUS_TEXT ("Re-initializing default context after it has")
132
0
            DCMTK_LOG4CPLUS_TEXT (" already been destroyed.\n")
133
0
            DCMTK_LOG4CPLUS_TEXT ("The memory will be leaked."));
134
135
6
    default_context_state = DC_INITIALIZED;
136
6
}
137
138
139
static
140
DefaultContext *
141
get_dc (bool alloc = true)
142
374k
{
143
374k
    if (DCMTK_LOG4CPLUS_UNLIKELY (! default_context && alloc))
144
6
        alloc_dc ();
145
374k
    return default_context;
146
374k
}
147
148
149
} // namespace
150
151
152
namespace helpers
153
{
154
155
156
log4cplus::thread::Mutex const & getConsoleOutputMutex ();
157
158
log4cplus::thread::Mutex const &
159
getConsoleOutputMutex ()
160
374k
{
161
374k
    return get_dc ()->console_mutex;
162
374k
}
163
164
165
LogLog &
166
getLogLog ()
167
0
{
168
0
    return get_dc ()->loglog;
169
0
}
170
171
172
} // namespace helpers
173
174
175
helpers::Time const &
176
getTTCCLayoutTimeBase ()
177
0
{
178
0
    return get_dc ()->TTCCLayout_time_base;
179
0
}
180
181
182
LogLevelManager &
183
getLogLevelManager ()
184
30
{
185
30
    return get_dc ()->log_level_manager;
186
30
}
187
188
189
Hierarchy &
190
getDefaultHierarchy ()
191
26
{
192
26
    return get_dc ()->hierarchy;
193
26
}
194
195
196
NDC &
197
getNDC ()
198
0
{
199
0
    return get_dc ()->ndc;
200
0
}
201
202
203
MDC &
204
getMDC ()
205
0
{
206
0
    return get_dc ()->mdc;
207
0
}
208
209
210
namespace spi
211
{
212
213
214
AppenderFactoryRegistry &
215
getAppenderFactoryRegistry ()
216
6
{
217
6
    return get_dc ()->appender_factory_registry;
218
6
}
219
220
221
LayoutFactoryRegistry &
222
getLayoutFactoryRegistry ()
223
6
{
224
6
    return get_dc ()->layout_factory_registry;
225
6
}
226
227
228
FilterFactoryRegistry &
229
getFilterFactoryRegistry ()
230
6
{
231
6
    return get_dc ()->filter_factory_registry;
232
6
}
233
234
235
LocaleFactoryRegistry &
236
getLocaleFactoryRegistry()
237
6
{
238
6
    return get_dc ()->locale_factory_registry;
239
6
}
240
241
242
} // namespace spi
243
244
245
namespace internal
246
{
247
248
249
gft_scratch_pad::gft_scratch_pad ()
250
6
    : q_str()
251
6
    , uc_q_str()
252
6
    , s_str()
253
6
    , ret()
254
6
    , fmt()
255
6
    , tmp()
256
6
    , buffer()
257
6
    , uc_q_str_valid (false)
258
6
    , q_str_valid (false)
259
6
    , s_str_valid (false)
260
6
{ }
261
262
263
gft_scratch_pad::~gft_scratch_pad ()
264
0
{ }
265
266
267
appender_sratch_pad::appender_sratch_pad ()
268
6
    : oss()
269
6
    , str()
270
6
    , chstr()
271
6
{ }
272
273
274
appender_sratch_pad::~appender_sratch_pad ()
275
0
{ }
276
277
278
per_thread_data::per_thread_data ()
279
6
    : macros_oss ()
280
6
    , layout_oss ()
281
6
    , ndc_dcs ()
282
6
    , mdc_map ()
283
6
    , thread_name ()
284
6
    , thread_name2 ()
285
6
    , gft_sp ()
286
6
    , appender_sp ()
287
6
    , faa_str ()
288
6
    , ll_str ()
289
6
    , forced_log_ev ()
290
6
    , fnull (0)
291
6
    , snprintf_buf ()
292
6
{ }
293
294
295
per_thread_data::~per_thread_data ()
296
0
{
297
0
    if (fnull)
298
0
        fclose (fnull);
299
0
}
300
301
302
log4cplus::thread::impl::tls_key_type tls_storage_key;
303
304
305
#if ! defined (DCMTK_LOG4CPLUS_SINGLE_THREADED) \
306
    && defined (DCMTK_LOG4CPLUS_THREAD_LOCAL_VAR)
307
308
DCMTK_LOG4CPLUS_THREAD_LOCAL_VAR per_thread_data * ptd = 0;
309
310
311
per_thread_data *
312
alloc_ptd ()
313
{
314
    per_thread_data * tmp = new per_thread_data;
315
    set_ptd (tmp);
316
    // This is a special hack. We set the keys' value to non-NULL to
317
    // get the ptd_cleanup_func to execute when this thread ends. The
318
    // cast is safe; the associated value will never be used if read
319
    // again using the key.
320
    thread::impl::tls_set_value (tls_storage_key,
321
        OFreinterpret_cast(void *, 1));
322
323
    return tmp;
324
}
325
326
#  else
327
328
per_thread_data *
329
alloc_ptd ()
330
6
{
331
6
    per_thread_data * tmp = new per_thread_data;
332
6
    set_ptd (tmp);
333
6
    return tmp;
334
6
}
335
336
#  endif
337
338
339
} // namespace internal
340
341
342
void initializeFactoryRegistry();
343
344
345
#ifdef DCMTK_LOG4CPLUS_USE_WIN32_THREADS
346
347
//! Thread local storage clean up function for WIN32 threads.
348
static
349
void WINAPI
350
ptd_cleanup_func_win32(void * /* arg */ )
351
{
352
    threadCleanup();
353
}
354
355
#else
356
357
//! Thread local storage clean up function for POSIX threads.
358
static
359
void
360
ptd_cleanup_func (void * arg)
361
0
{
362
0
    internal::per_thread_data * const arg_ptd
363
0
        = OFstatic_cast(internal::per_thread_data *, arg);
364
0
    internal::per_thread_data * const ptd = internal::get_ptd (false);
365
0
    (void) ptd;
366
367
    // Either it is a dummy value or it should be the per thread data
368
    // pointer we get from internal::get_ptd().
369
0
    assert (arg == OFreinterpret_cast(void *, 1)
370
0
        || arg_ptd == ptd
371
0
        || (! ptd && arg_ptd));
372
373
0
    if (arg == OFreinterpret_cast(void *, 1))
374
        // Setting the value through the key here is necessary in case
375
        // we are using TLS using __thread or __declspec(thread) or
376
        // similar constructs with POSIX threads.  Otherwise POSIX
377
        // calls this cleanup routine more than once if the value
378
        // stays non-NULL after it returns.
379
0
        thread::impl::tls_set_value (internal::tls_storage_key, 0);
380
0
    else if (arg)
381
0
    {
382
        // Instead of using internal::get_ptd(false) here we are using
383
        // the value passed to this function directly.  This is
384
        // necessary because of the following (from SUSv4):
385
        //
386
        // A call to pthread_getspecific() for the thread-specific
387
        // data key being destroyed shall return the value NULL,
388
        // unless the value is changed (after the destructor starts)
389
        // by a call to pthread_setspecific().
390
0
        delete arg_ptd;
391
0
        thread::impl::tls_set_value (internal::tls_storage_key, 0);
392
0
    }
393
0
    else
394
0
    {
395
        // In this case we fall through to threadCleanup() and it does
396
        // all the necessary work itself.
397
0
        ;
398
0
    }
399
400
0
    threadCleanup ();
401
0
}
402
403
#endif
404
405
406
static
407
void
408
threadSetup ()
409
6
{
410
6
    internal::get_ptd (true);
411
6
}
412
413
414
void initializeLog4cplus();
415
416
void initializeLog4cplus()
417
6
{
418
6
    static bool initialized = false;
419
6
    if (initialized)
420
0
        return;
421
422
#ifdef DCMTK_LOG4CPLUS_USE_WIN32_THREADS
423
    internal::tls_storage_key = thread::impl::tls_init(ptd_cleanup_func_win32);
424
#else
425
6
    internal::tls_storage_key = thread::impl::tls_init(ptd_cleanup_func);
426
6
#endif
427
6
    threadSetup ();
428
429
6
    DefaultContext * dc = get_dc (true);
430
6
    dc->TTCCLayout_time_base = helpers::Time::gettimeofday ();
431
6
    Logger::getRoot();
432
6
    initializeFactoryRegistry();
433
434
6
    initialized = true;
435
6
}
436
437
438
void
439
threadCleanup ()
440
0
{
441
    // Do thread-specific cleanup.
442
0
    internal::per_thread_data * ptd = internal::get_ptd (false);
443
0
    delete ptd;
444
0
    internal::set_ptd (0);
445
0
}
446
447
448
} // namespace log4cplus
449
} // end namespace dcmtk
450
451
452
#if defined (_WIN32) && defined (DCMTK_LOG4CPLUS_BUILD_DLL)
453
454
extern "C"
455
BOOL
456
WINAPI
457
DllMain (DCMTK_LOG4CPLUS_DLLMAIN_HINSTANCE /*hinstDLL*/, DWORD fdwReason,
458
    LPVOID /*lpReserved*/)
459
{
460
    // Perform actions based on the reason for calling.
461
    switch( fdwReason )
462
    {
463
    case DLL_PROCESS_ATTACH:
464
    {
465
        log4cplus::initializeLog4cplus();
466
467
        // Do thread-specific initialization for the main thread.
468
        log4cplus::threadSetup ();
469
470
        break;
471
    }
472
473
    case DLL_THREAD_ATTACH:
474
    {
475
        // Do thread-specific initialization.
476
        log4cplus::threadSetup ();
477
478
        break;
479
    }
480
481
    case DLL_THREAD_DETACH:
482
    {
483
        // Do thread-specific cleanup.
484
        log4cplus::threadCleanup ();
485
486
        break;
487
    }
488
489
    case DLL_PROCESS_DETACH:
490
    {
491
        // Perform any necessary cleanup.
492
493
        // Do thread-specific cleanup.
494
        log4cplus::threadCleanup ();
495
#if ! defined (DCMTK_LOG4CPLUS_THREAD_LOCAL_VAR)
496
        log4cplus::thread::impl::tls_cleanup (
497
            log4cplus::internal::tls_storage_key);
498
#endif
499
        break;
500
    }
501
502
    }
503
504
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
505
}
506
507
#else
508
509
namespace {
510
511
    struct _static_log4cplus_initializer
512
    {
513
        _static_log4cplus_initializer ()
514
6
        {
515
6
            dcmtk::log4cplus::initializeLog4cplus();
516
6
        }
517
518
        ~_static_log4cplus_initializer ()
519
0
        {
520
            // Last thread cleanup.
521
0
            dcmtk::log4cplus::threadCleanup ();
522
523
0
            dcmtk::log4cplus::thread::impl::tls_cleanup (
524
0
                dcmtk::log4cplus::internal::tls_storage_key);
525
0
        }
526
    } static initializer;
527
}
528
529
530
#endif