You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

466 lines
9.2 KiB

// Module: Log4CPLUS
// File: global-init.cxx
// Created: 5/2003
// Author: Tad E. Smith
//
//
// Copyright 2003-2010 Tad E. Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <log4cplus/config.hxx>
#include <log4cplus/config/windowsh-inc.h>
#include <log4cplus/logger.h>
#include <log4cplus/ndc.h>
#include <log4cplus/mdc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/internal/internal.h>
#include <log4cplus/thread/impl/tls.h>
#include <log4cplus/thread/syncprims-pub-impl.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/hierarchy.h>
#include <cstdio>
#include <iostream>
#include <stdexcept>
// Forward Declarations
namespace log4cplus
{
#ifdef UNICODE
LOG4CPLUS_EXPORT tostream & tcout = std::wcout;
LOG4CPLUS_EXPORT tostream & tcerr = std::wcerr;
#else
LOG4CPLUS_EXPORT tostream & tcout = std::cout;
LOG4CPLUS_EXPORT tostream & tcerr = std::cerr;
#endif // UNICODE
namespace
{
//! Default context.
struct DefaultContext
{
log4cplus::thread::Mutex console_mutex;
helpers::LogLog loglog;
LogLevelManager log_level_manager;
helpers::Time TTCCLayout_time_base;
NDC ndc;
MDC mdc;
Hierarchy hierarchy;
spi::AppenderFactoryRegistry appender_factory_registry;
spi::LayoutFactoryRegistry layout_factory_registry;
spi::FilterFactoryRegistry filter_factory_registry;
spi::LocaleFactoryRegistry locale_factory_registry;
};
enum DCState
{
DC_UNINITIALIZED,
DC_INITIALIZED,
DC_DESTROYED
};
static DCState default_context_state;
static DefaultContext * default_context;
struct destroy_default_context
{
~destroy_default_context ()
{
delete default_context;
default_context = 0;
default_context_state = DC_DESTROYED;
}
} static destroy_default_context_;
static
void
alloc_dc ()
{
assert (! default_context);
assert (default_context_state == DC_UNINITIALIZED);
if (default_context)
throw std::logic_error (
"alloc_dc() called with non-NULL default_context.");
if (default_context_state == DC_INITIALIZED)
throw std::logic_error ("alloc_dc() called in DC_INITIALIZED state.");
default_context = new DefaultContext;
if (default_context_state == DC_DESTROYED)
default_context->loglog.error (
LOG4CPLUS_TEXT ("Re-initializing default context after it has")
LOG4CPLUS_TEXT (" already been destroyed.\n")
LOG4CPLUS_TEXT ("The memory will be leaked."));
default_context_state = DC_INITIALIZED;
}
static
DefaultContext *
get_dc (bool alloc = true)
{
if (LOG4CPLUS_UNLIKELY (! default_context && alloc))
alloc_dc ();
return default_context;
}
} // namespace
namespace helpers
{
log4cplus::thread::Mutex const &
getConsoleOutputMutex ()
{
return get_dc ()->console_mutex;
}
LogLog &
getLogLog ()
{
return get_dc ()->loglog;
}
} // namespace helpers
helpers::Time const &
getTTCCLayoutTimeBase ()
{
return get_dc ()->TTCCLayout_time_base;
}
LogLevelManager &
getLogLevelManager ()
{
return get_dc ()->log_level_manager;
}
Hierarchy &
getDefaultHierarchy ()
{
return get_dc ()->hierarchy;
}
NDC &
getNDC ()
{
return get_dc ()->ndc;
}
MDC &
getMDC ()
{
return get_dc ()->mdc;
}
namespace spi
{
AppenderFactoryRegistry &
getAppenderFactoryRegistry ()
{
return get_dc ()->appender_factory_registry;
}
LayoutFactoryRegistry &
getLayoutFactoryRegistry ()
{
return get_dc ()->layout_factory_registry;
}
FilterFactoryRegistry &
getFilterFactoryRegistry ()
{
return get_dc ()->filter_factory_registry;
}
LocaleFactoryRegistry &
getLocaleFactoryRegistry()
{
return get_dc ()->locale_factory_registry;
}
} // namespace spi
namespace internal
{
gft_scratch_pad::gft_scratch_pad ()
: uc_q_str_valid (false)
, q_str_valid (false)
, s_str_valid (false)
{ }
gft_scratch_pad::~gft_scratch_pad ()
{ }
appender_sratch_pad::appender_sratch_pad ()
{ }
appender_sratch_pad::~appender_sratch_pad ()
{ }
per_thread_data::per_thread_data ()
: fnull (0)
{ }
per_thread_data::~per_thread_data ()
{
if (fnull)
std::fclose (fnull);
}
log4cplus::thread::impl::tls_key_type tls_storage_key;
#if ! defined (LOG4CPLUS_SINGLE_THREADED) \
&& defined (LOG4CPLUS_THREAD_LOCAL_VAR)
LOG4CPLUS_THREAD_LOCAL_VAR per_thread_data * ptd = 0;
per_thread_data *
alloc_ptd ()
{
per_thread_data * tmp = new per_thread_data;
set_ptd (tmp);
// This is a special hack. We set the keys' value to non-NULL to
// get the ptd_cleanup_func to execute when this thread ends. The
// cast is safe; the associated value will never be used if read
// again using the key.
thread::impl::tls_set_value (tls_storage_key,
reinterpret_cast<void *>(1));
return tmp;
}
# else
per_thread_data *
alloc_ptd ()
{
per_thread_data * tmp = new per_thread_data;
set_ptd (tmp);
return tmp;
}
# endif
} // namespace internal
void initializeFactoryRegistry();
//! Thread local storage clean up function for POSIX threads.
static
void
ptd_cleanup_func (void * arg)
{
internal::per_thread_data * const arg_ptd
= static_cast<internal::per_thread_data *>(arg);
internal::per_thread_data * const ptd = internal::get_ptd (false);
(void) ptd;
// Either it is a dummy value or it should be the per thread data
// pointer we get from internal::get_ptd().
assert (arg == reinterpret_cast<void *>(1)
|| arg_ptd == ptd
|| (! ptd && arg_ptd));
if (arg == reinterpret_cast<void *>(1))
// Setting the value through the key here is necessary in case
// we are using TLS using __thread or __declspec(thread) or
// similar constructs with POSIX threads. Otherwise POSIX
// calls this cleanup routine more than once if the value
// stays non-NULL after it returns.
thread::impl::tls_set_value (internal::tls_storage_key, 0);
else if (arg)
{
// Instead of using internal::get_ptd(false) here we are using
// the value passed to this function directly. This is
// necessary because of the following (from SUSv4):
//
// A call to pthread_getspecific() for the thread-specific
// data key being destroyed shall return the value NULL,
// unless the value is changed (after the destructor starts)
// by a call to pthread_setspecific().
delete arg_ptd;
thread::impl::tls_set_value (internal::tls_storage_key, 0);
}
else
{
// In this case we fall through to threadCleanup() and it does
// all the necessary work itself.
;
}
threadCleanup ();
}
static
void
threadSetup ()
{
internal::get_ptd (true);
}
void initializeLog4cplus()
{
static bool initialized = false;
if (initialized)
return;
internal::tls_storage_key = thread::impl::tls_init (ptd_cleanup_func);
threadSetup ();
DefaultContext * dc = get_dc (true);
dc->TTCCLayout_time_base = helpers::Time::gettimeofday ();
Logger::getRoot();
initializeFactoryRegistry();
initialized = true;
}
void
threadCleanup ()
{
// Do thread-specific cleanup.
internal::per_thread_data * ptd = internal::get_ptd (false);
delete ptd;
internal::set_ptd (0);
}
} // namespace log4cplus
#if defined (_WIN32) && defined (LOG4CPLUS_BUILD_DLL)
extern "C"
BOOL
WINAPI
DllMain (LOG4CPLUS_DLLMAIN_HINSTANCE /*hinstDLL*/, DWORD fdwReason,
LPVOID /*lpReserved*/)
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
{
log4cplus::initializeLog4cplus();
// Do thread-specific initialization for the main thread.
log4cplus::threadSetup ();
break;
}
case DLL_THREAD_ATTACH:
{
// Do thread-specific initialization.
log4cplus::threadSetup ();
break;
}
case DLL_THREAD_DETACH:
{
// Do thread-specific cleanup.
log4cplus::threadCleanup ();
break;
}
case DLL_PROCESS_DETACH:
{
// Perform any necessary cleanup.
// Do thread-specific cleanup.
log4cplus::threadCleanup ();
#if ! defined (LOG4CPLUS_THREAD_LOCAL_VAR)
log4cplus::thread::impl::tls_cleanup (
log4cplus::internal::tls_storage_key);
#endif
break;
}
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
#else
namespace {
struct _static_log4cplus_initializer
{
_static_log4cplus_initializer ()
{
log4cplus::initializeLog4cplus();
}
~_static_log4cplus_initializer ()
{
// Last thread cleanup.
log4cplus::threadCleanup ();
}
} static initializer;
}
#endif