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 {
DefaultContextdcmtk::log4cplus::__anona9de91f60111::DefaultContext63 DefaultContext() :
64 console_mutex(),
65 loglog(),
66 log_level_manager(),
67 TTCCLayout_time_base(),
68 ndc(),
69 mdc(),
70 hierarchy(),
71 appender_factory_registry(),
72 layout_factory_registry(),
73 filter_factory_registry(),
74 locale_factory_registry() {
75 }
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 {
~destroy_default_contextdcmtk::log4cplus::__anona9de91f60111::destroy_default_context104 ~destroy_default_context ()
105 {
106 delete default_context;
107 default_context = 0;
108 default_context_state = DC_DESTROYED;
109 }
110 } static destroy_default_context_;
111
112
113 static
114 void
alloc_dc()115 alloc_dc ()
116 {
117 assert (! default_context);
118 assert (default_context_state == DC_UNINITIALIZED);
119
120 if (default_context)
121 throw STD_NAMESPACE logic_error (
122 "alloc_dc() called with non-NULL default_context.");
123
124 if (default_context_state == DC_INITIALIZED)
125 throw STD_NAMESPACE logic_error ("alloc_dc() called in DC_INITIALIZED state.");
126
127 default_context = new DefaultContext;
128
129 if (default_context_state == DC_DESTROYED)
130 default_context->loglog.error (
131 DCMTK_LOG4CPLUS_TEXT ("Re-initializing default context after it has")
132 DCMTK_LOG4CPLUS_TEXT (" already been destroyed.\n")
133 DCMTK_LOG4CPLUS_TEXT ("The memory will be leaked."));
134
135 default_context_state = DC_INITIALIZED;
136 }
137
138
139 static
140 DefaultContext *
get_dc(bool alloc=true)141 get_dc (bool alloc = true)
142 {
143 if (DCMTK_LOG4CPLUS_UNLIKELY (! default_context && alloc))
144 alloc_dc ();
145 return default_context;
146 }
147
148
149 } // namespace
150
151
152 namespace helpers
153 {
154
155
156 log4cplus::thread::Mutex const & getConsoleOutputMutex ();
157
158 log4cplus::thread::Mutex const &
getConsoleOutputMutex()159 getConsoleOutputMutex ()
160 {
161 return get_dc ()->console_mutex;
162 }
163
164
165 LogLog &
getLogLog()166 getLogLog ()
167 {
168 return get_dc ()->loglog;
169 }
170
171
172 } // namespace helpers
173
174
175 helpers::Time const &
getTTCCLayoutTimeBase()176 getTTCCLayoutTimeBase ()
177 {
178 return get_dc ()->TTCCLayout_time_base;
179 }
180
181
182 LogLevelManager &
getLogLevelManager()183 getLogLevelManager ()
184 {
185 return get_dc ()->log_level_manager;
186 }
187
188
189 Hierarchy &
getDefaultHierarchy()190 getDefaultHierarchy ()
191 {
192 return get_dc ()->hierarchy;
193 }
194
195
196 NDC &
getNDC()197 getNDC ()
198 {
199 return get_dc ()->ndc;
200 }
201
202
203 MDC &
getMDC()204 getMDC ()
205 {
206 return get_dc ()->mdc;
207 }
208
209
210 namespace spi
211 {
212
213
214 AppenderFactoryRegistry &
getAppenderFactoryRegistry()215 getAppenderFactoryRegistry ()
216 {
217 return get_dc ()->appender_factory_registry;
218 }
219
220
221 LayoutFactoryRegistry &
getLayoutFactoryRegistry()222 getLayoutFactoryRegistry ()
223 {
224 return get_dc ()->layout_factory_registry;
225 }
226
227
228 FilterFactoryRegistry &
getFilterFactoryRegistry()229 getFilterFactoryRegistry ()
230 {
231 return get_dc ()->filter_factory_registry;
232 }
233
234
235 LocaleFactoryRegistry &
getLocaleFactoryRegistry()236 getLocaleFactoryRegistry()
237 {
238 return get_dc ()->locale_factory_registry;
239 }
240
241
242 } // namespace spi
243
244
245 namespace internal
246 {
247
248
gft_scratch_pad()249 gft_scratch_pad::gft_scratch_pad ()
250 : q_str()
251 , uc_q_str()
252 , s_str()
253 , ret()
254 , fmt()
255 , tmp()
256 , buffer()
257 , uc_q_str_valid (false)
258 , q_str_valid (false)
259 , s_str_valid (false)
260 { }
261
262
~gft_scratch_pad()263 gft_scratch_pad::~gft_scratch_pad ()
264 { }
265
266
appender_sratch_pad()267 appender_sratch_pad::appender_sratch_pad ()
268 : oss()
269 , str()
270 , chstr()
271 { }
272
273
~appender_sratch_pad()274 appender_sratch_pad::~appender_sratch_pad ()
275 { }
276
277
per_thread_data()278 per_thread_data::per_thread_data ()
279 : macros_oss ()
280 , layout_oss ()
281 , ndc_dcs ()
282 , mdc_map ()
283 , thread_name ()
284 , thread_name2 ()
285 , gft_sp ()
286 , appender_sp ()
287 , faa_str ()
288 , ll_str ()
289 , forced_log_ev ()
290 , fnull (0)
291 , snprintf_buf ()
292 { }
293
294
~per_thread_data()295 per_thread_data::~per_thread_data ()
296 {
297 if (fnull)
298 fclose (fnull);
299 }
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 *
alloc_ptd()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 *
alloc_ptd()329 alloc_ptd ()
330 {
331 per_thread_data * tmp = new per_thread_data;
332 set_ptd (tmp);
333 return tmp;
334 }
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
ptd_cleanup_func_win32(void *)350 ptd_cleanup_func_win32(void * /* arg */ )
351 {
352 threadCleanup();
353 }
354
355 #endif
356
357
358 //! Thread local storage clean up function for POSIX threads.
359 static
360 void
ptd_cleanup_func(void * arg)361 ptd_cleanup_func (void * arg)
362 {
363 internal::per_thread_data * const arg_ptd
364 = OFstatic_cast(internal::per_thread_data *, arg);
365 internal::per_thread_data * const ptd = internal::get_ptd (false);
366 (void) ptd;
367
368 // Either it is a dummy value or it should be the per thread data
369 // pointer we get from internal::get_ptd().
370 assert (arg == OFreinterpret_cast(void *, 1)
371 || arg_ptd == ptd
372 || (! ptd && arg_ptd));
373
374 if (arg == OFreinterpret_cast(void *, 1))
375 // Setting the value through the key here is necessary in case
376 // we are using TLS using __thread or __declspec(thread) or
377 // similar constructs with POSIX threads. Otherwise POSIX
378 // calls this cleanup routine more than once if the value
379 // stays non-NULL after it returns.
380 thread::impl::tls_set_value (internal::tls_storage_key, 0);
381 else if (arg)
382 {
383 // Instead of using internal::get_ptd(false) here we are using
384 // the value passed to this function directly. This is
385 // necessary because of the following (from SUSv4):
386 //
387 // A call to pthread_getspecific() for the thread-specific
388 // data key being destroyed shall return the value NULL,
389 // unless the value is changed (after the destructor starts)
390 // by a call to pthread_setspecific().
391 delete arg_ptd;
392 thread::impl::tls_set_value (internal::tls_storage_key, 0);
393 }
394 else
395 {
396 // In this case we fall through to threadCleanup() and it does
397 // all the necessary work itself.
398 ;
399 }
400
401 threadCleanup ();
402 }
403
404
405 static
406 void
threadSetup()407 threadSetup ()
408 {
409 internal::get_ptd (true);
410 }
411
412
413 void initializeLog4cplus();
414
initializeLog4cplus()415 void initializeLog4cplus()
416 {
417 static bool initialized = false;
418 if (initialized)
419 return;
420
421 #ifdef DCMTK_LOG4CPLUS_USE_WIN32_THREADS
422 internal::tls_storage_key = thread::impl::tls_init(ptd_cleanup_func_win32);
423 #else
424 internal::tls_storage_key = thread::impl::tls_init(ptd_cleanup_func);
425 #endif
426 threadSetup ();
427
428 DefaultContext * dc = get_dc (true);
429 dc->TTCCLayout_time_base = helpers::Time::gettimeofday ();
430 Logger::getRoot();
431 initializeFactoryRegistry();
432
433 initialized = true;
434 }
435
436
437 void
threadCleanup()438 threadCleanup ()
439 {
440 // Do thread-specific cleanup.
441 internal::per_thread_data * ptd = internal::get_ptd (false);
442 delete ptd;
443 internal::set_ptd (0);
444 }
445
446
447 } // namespace log4cplus
448 } // end namespace dcmtk
449
450
451 #if defined (_WIN32) && defined (DCMTK_LOG4CPLUS_BUILD_DLL)
452
453 extern "C"
454 BOOL
455 WINAPI
DllMain(DCMTK_LOG4CPLUS_DLLMAIN_HINSTANCE,DWORD fdwReason,LPVOID)456 DllMain (DCMTK_LOG4CPLUS_DLLMAIN_HINSTANCE /*hinstDLL*/, DWORD fdwReason,
457 LPVOID /*lpReserved*/)
458 {
459 // Perform actions based on the reason for calling.
460 switch( fdwReason )
461 {
462 case DLL_PROCESS_ATTACH:
463 {
464 log4cplus::initializeLog4cplus();
465
466 // Do thread-specific initialization for the main thread.
467 log4cplus::threadSetup ();
468
469 break;
470 }
471
472 case DLL_THREAD_ATTACH:
473 {
474 // Do thread-specific initialization.
475 log4cplus::threadSetup ();
476
477 break;
478 }
479
480 case DLL_THREAD_DETACH:
481 {
482 // Do thread-specific cleanup.
483 log4cplus::threadCleanup ();
484
485 break;
486 }
487
488 case DLL_PROCESS_DETACH:
489 {
490 // Perform any necessary cleanup.
491
492 // Do thread-specific cleanup.
493 log4cplus::threadCleanup ();
494 #if ! defined (DCMTK_LOG4CPLUS_THREAD_LOCAL_VAR)
495 log4cplus::thread::impl::tls_cleanup (
496 log4cplus::internal::tls_storage_key);
497 #endif
498 break;
499 }
500
501 }
502
503 return TRUE; // Successful DLL_PROCESS_ATTACH.
504 }
505
506 #else
507
508 namespace {
509
510 struct _static_log4cplus_initializer
511 {
_static_log4cplus_initializer__anona9de91f60211::_static_log4cplus_initializer512 _static_log4cplus_initializer ()
513 {
514 dcmtk::log4cplus::initializeLog4cplus();
515 }
516
~_static_log4cplus_initializer__anona9de91f60211::_static_log4cplus_initializer517 ~_static_log4cplus_initializer ()
518 {
519 // Last thread cleanup.
520 dcmtk::log4cplus::threadCleanup ();
521
522 dcmtk::log4cplus::thread::impl::tls_cleanup (
523 dcmtk::log4cplus::internal::tls_storage_key);
524 }
525 } static initializer;
526 }
527
528
529 #endif
530