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