/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 |