diff options
Diffstat (limited to 'ACE/ace/Log_Msg.cpp')
-rw-r--r-- | ACE/ace/Log_Msg.cpp | 2510 |
1 files changed, 2510 insertions, 0 deletions
diff --git a/ACE/ace/Log_Msg.cpp b/ACE/ace/Log_Msg.cpp new file mode 100644 index 00000000000..0f2bf798c25 --- /dev/null +++ b/ACE/ace/Log_Msg.cpp @@ -0,0 +1,2510 @@ +// $Id$ + +// We need this to get the status of ACE_NTRACE... +#include "ace/config-all.h" + +// Turn off tracing for the duration of this file. +#if defined (ACE_NTRACE) +# undef ACE_NTRACE +#endif /* ACE_NTRACE */ +#define ACE_NTRACE 1 + +#include "ace/ACE.h" +#include "ace/Thread_Manager.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_wchar.h" +#include "ace/OS_NS_signal.h" + +#if !defined (ACE_MT_SAFE) || (ACE_MT_SAFE != 0) +# include "ace/Object_Manager_Base.h" +#endif /* ! ACE_MT_SAFE */ + +#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) +// FUZZ: disable check_for_streams_include +# include "ace/streams.h" +#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */ + +#if defined (ACE_HAS_TRACE) +# include "ace/Trace.h" +#endif /* ACE_HAS_TRACE */ + +#include "ace/Log_Msg.h" +#include "ace/Log_Msg_Callback.h" +#include "ace/Log_Msg_IPC.h" +#include "ace/Log_Msg_NT_Event_Log.h" +#include "ace/Log_Msg_UNIX_Syslog.h" +#include "ace/Log_Record.h" +#include "ace/Recursive_Thread_Mutex.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Log_Msg.inl" +#endif /* __ACE_INLINE__ */ + +ACE_RCSID(ace, Log_Msg, "$Id$") + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Log_Msg) + +// only used here... dhinton +#if defined (ACE_HAS_SYS_SIGLIST) +# if !defined (_sys_siglist) +# define _sys_siglist sys_siglist +# endif /* !defined (sys_siglist) */ +//extern char **_sys_siglist; +#endif /* ACE_HAS_SYS_SIGLIST */ + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + int ACE_Log_Msg::key_created_ = 0; +# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \ + defined (ACE_HAS_TSS_EMULATION) + +#if defined (ACE_MVS) + static ACE_thread_key_t the_log_msg_tss_key = + #if !defined(_LP64) + { '\0','\0','\0','\0' }; + #else + { '\0','\0','\0','\0','\0','\0','\0','\0' }; + #endif +#else + static ACE_thread_key_t the_log_msg_tss_key = 0; +#endif /* defined (ACE_MVS) */ + +ACE_thread_key_t *log_msg_tss_key (void) +{ + return &the_log_msg_tss_key; +} + +# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ +#else +static ACE_Cleanup_Adapter<ACE_Log_Msg>* log_msg_cleanup = 0; +class ACE_Msg_Log_Cleanup: public ACE_Cleanup_Adapter<ACE_Log_Msg> +{ +public: + virtual ~ACE_Msg_Log_Cleanup (void) { + if (this == log_msg_cleanup) + log_msg_cleanup = 0; + } +}; +#endif /* ACE_MT_SAFE */ + +#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) && !defined (ACE_HAS_PHARLAP) +# define ACE_LOG_MSG_SYSLOG_BACKEND ACE_Log_Msg_NT_Event_Log +#elif !defined (ACE_LACKS_UNIX_SYSLOG) && !defined (ACE_HAS_WINCE) +# define ACE_LOG_MSG_SYSLOG_BACKEND ACE_Log_Msg_UNIX_Syslog +#else +# define ACE_LOG_MSG_SYSLOG_BACKEND ACE_Log_Msg_IPC +#endif /* ! ACE_WIN32 */ + +// When doing ACE_OS::s[n]printf() calls in log(), we need to update +// the space remaining in the output buffer based on what's returned from +// the output function. If we could rely on more modern compilers, this +// would be in an unnamed namespace, but it's a macro instead. +// count is a size_t, len is an int and assumed to be non-negative. +#define ACE_UPDATE_COUNT(COUNT, LEN) \ + do { if (static_cast<size_t> (LEN) > COUNT) COUNT = 0; \ + else COUNT -= static_cast<size_t> (LEN); \ + } while (0) + +/// Instance count for Log_Msg - used to know when dynamically +/// allocated storage (program name and host name) can be safely +/// deleted. +int ACE_Log_Msg::instance_count_ = 0; + +/** + * @class ACE_Log_Msg_Manager + * + * @brief Synchronize output operations. + * + * Provides global point of contact for all ACE_Log_Msg instances + * in a process. + * + * For internal use by ACE, only! + */ +class ACE_Log_Msg_Manager +{ +public: + static ACE_Log_Msg_Backend *log_backend_; + static ACE_Log_Msg_Backend *custom_backend_; + + static u_long log_backend_flags_; + + static int init_backend (const u_long *flags = 0); + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + //FUZZ: disable check_for_lack_ACE_OS + static void close (void); + //FUZZ: enable check_for_lack_ACE_OS + + static ACE_Recursive_Thread_Mutex *get_lock (void); + +private: + static ACE_Recursive_Thread_Mutex *lock_; +#endif /* ! ACE_MT_SAFE */ +}; + +ACE_Log_Msg_Backend *ACE_Log_Msg_Manager::log_backend_ = 0; +ACE_Log_Msg_Backend *ACE_Log_Msg_Manager::custom_backend_ = 0; + +u_long ACE_Log_Msg_Manager::log_backend_flags_ = 0; + +int ACE_Log_Msg_Manager::init_backend (const u_long *flags) +{ + // If flags have been supplied, and they are different from the flags + // we had last time, then we may have to re-create the backend as a + // different type. + if (flags) + { + // Sanity check for custom backend. + if (ACE_BIT_ENABLED (*flags, ACE_Log_Msg::CUSTOM) && + ACE_Log_Msg_Manager::custom_backend_ == 0) + { + return -1; + } + + if ((ACE_BIT_ENABLED (*flags, ACE_Log_Msg::SYSLOG) + && ACE_BIT_DISABLED (ACE_Log_Msg_Manager::log_backend_flags_, ACE_Log_Msg::SYSLOG)) + || (ACE_BIT_DISABLED (*flags, ACE_Log_Msg::SYSLOG) + && ACE_BIT_ENABLED (ACE_Log_Msg_Manager::log_backend_flags_, ACE_Log_Msg::SYSLOG))) + { + delete ACE_Log_Msg_Manager::log_backend_; + ACE_Log_Msg_Manager::log_backend_ = 0; + } + + ACE_Log_Msg_Manager::log_backend_flags_ = *flags; + } + + if (ACE_Log_Msg_Manager::log_backend_ == 0) + { + ACE_NO_HEAP_CHECK; + +#if (defined (WIN32) || !defined (ACE_LACKS_UNIX_SYSLOG)) && !defined (ACE_HAS_WINCE) && !defined (ACE_HAS_PHARLAP) + // Allocate the ACE_Log_Msg_Backend instance. + if (ACE_BIT_ENABLED (ACE_Log_Msg_Manager::log_backend_flags_, ACE_Log_Msg::SYSLOG)) + ACE_NEW_RETURN (ACE_Log_Msg_Manager::log_backend_, + ACE_LOG_MSG_SYSLOG_BACKEND, + -1); + else +#endif /* defined (WIN32) && !defined (ACE_HAS_WINCE) && !defined (ACE_HAS_PHARLAP) */ + ACE_NEW_RETURN (ACE_Log_Msg_Manager::log_backend_, + ACE_Log_Msg_IPC, + -1); + } + + return 0; +} + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +ACE_Recursive_Thread_Mutex *ACE_Log_Msg_Manager::lock_ = 0; + +ACE_Recursive_Thread_Mutex * +ACE_Log_Msg_Manager::get_lock (void) +{ + // This function is called by the first thread to create an ACE_Log_Msg + // instance. It makes the call while holding a mutex, so we don't have + // to grab another one here. + + if (ACE_Log_Msg_Manager::lock_ == 0) + { + ACE_NO_HEAP_CHECK; + + ACE_NEW_RETURN (ACE_Log_Msg_Manager::lock_, + ACE_Recursive_Thread_Mutex, + 0); + } + + if (init_backend () == -1) + return 0; + + return ACE_Log_Msg_Manager::lock_; +} + +void +ACE_Log_Msg_Manager::close (void) +{ +#if defined (ACE_HAS_STHREADS) && ! defined (ACE_HAS_TSS_EMULATION) && ! defined (ACE_HAS_EXCEPTIONS) + // Delete the (main thread's) Log_Msg instance. I think that this + // is only "necessary" if exception handling is not enabled. + // Without exception handling, main thread TSS destructors don't + // seem to be called. It's not really necessary anyways, because + // this one leak is harmless on Solaris. + delete ACE_Log_Msg::instance (); +#endif /* ACE_HAS_STHREADS && ! TSS_EMULATION && ! ACE_HAS_EXCEPTIONS */ + + // Ugly, ugly, but don't know a better way. + delete ACE_Log_Msg_Manager::lock_; + ACE_Log_Msg_Manager::lock_ = 0; + + delete ACE_Log_Msg_Manager::log_backend_; + ACE_Log_Msg_Manager::log_backend_ = 0; + + // we are never responsible for custom backend + ACE_Log_Msg_Manager::custom_backend_ = 0; +} + +# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \ + defined (ACE_HAS_TSS_EMULATION) +/* static */ +# if defined (ACE_HAS_THR_C_DEST) +# define LOCAL_EXTERN_PREFIX extern "C" +# else +# define LOCAL_EXTERN_PREFIX +# endif /* ACE_HAS_THR_C_DEST */ +LOCAL_EXTERN_PREFIX +void +ACE_TSS_CLEANUP_NAME (void *ptr) +{ + // Delegate to thr_desc if this not has terminated + ACE_Log_Msg* log_msg = (ACE_Log_Msg*) ptr; + if (log_msg->thr_desc()!=0) + log_msg->thr_desc()->log_msg_cleanup(log_msg); + else + delete (ACE_Log_Msg *) ptr; +} +# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ +#endif /* ! ACE_MT_SAFE */ + +/* static */ +int +ACE_Log_Msg::exists (void) +{ +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \ + defined (ACE_HAS_TSS_EMULATION) + void *tss_log_msg = 0; // The actual type is ACE_Log_Msg*, but we need this + // void to keep G++ from complaining. + + // Get the tss_log_msg from thread-specific storage. + return key_created_ + && ACE_Thread::getspecific (*(log_msg_tss_key ()), &tss_log_msg) != -1 + && tss_log_msg != 0; +# else +# error "Platform must support thread-specific storage if threads are used." +# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ +#else /* ! ACE_MT_SAFE */ + return 1; +#endif /* ! ACE_MT_SAFE */ +} + +ACE_Log_Msg * +ACE_Log_Msg::instance (void) +{ +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \ + defined (ACE_HAS_TSS_EMULATION) + // TSS Singleton implementation. + + if (key_created_ == 0) + { + ACE_thread_mutex_t *lock = + reinterpret_cast<ACE_thread_mutex_t *> ( + ACE_OS_Object_Manager::preallocated_object + [ACE_OS_Object_Manager::ACE_LOG_MSG_INSTANCE_LOCK]); + + if (1 == ACE_OS_Object_Manager::starting_up()) + //This function is called before ACE_OS_Object_Manager is + //initialized. So the lock might not be valid. Assume it's + //single threaded and so don't need the lock. + ; + else + ACE_OS::thread_mutex_lock (lock); + + if (key_created_ == 0) + { + // Allocate the Singleton lock. + ACE_Log_Msg_Manager::get_lock (); + + { + ACE_NO_HEAP_CHECK; + if (ACE_Thread::keycreate (log_msg_tss_key (), + &ACE_TSS_CLEANUP_NAME) != 0) + { + if (1 == ACE_OS_Object_Manager::starting_up()) + //This function is called before ACE_OS_Object_Manager is + //initialized. So the lock might not be valid. Assume it's + //single threaded and so don't need the lock. + ; + else + ACE_OS::thread_mutex_unlock (lock); + return 0; // Major problems, this should *never* happen! + } + } + + key_created_ = 1; + } + + if (1 == ACE_OS_Object_Manager::starting_up()) + //This function is called before ACE_OS_Object_Manager is + //initialized. So the lock might not be valid. Assume it's + //single threaded and so don't need the lock. + ; + else + ACE_OS::thread_mutex_unlock (lock); + } + + ACE_Log_Msg *tss_log_msg = 0; + void *temp = 0; + + // Get the tss_log_msg from thread-specific storage. + if (ACE_Thread::getspecific (*(log_msg_tss_key ()), &temp) == -1) + return 0; // This should not happen! + + tss_log_msg = static_cast <ACE_Log_Msg *> (temp); + + // Check to see if this is the first time in for this thread. + if (tss_log_msg == 0) + { + // Allocate memory off the heap and store it in a pointer in + // thread-specific storage (on the stack...). Stop heap + // checking, the memory will always be freed by the thread + // rundown because of the TSS callback set up when the key was + // created. This prevents from getting these blocks reported as + // memory leaks. + { + ACE_NO_HEAP_CHECK; + + ACE_NEW_RETURN (tss_log_msg, + ACE_Log_Msg, + 0); + // Store the dynamically allocated pointer in thread-specific + // storage. It gets deleted via the ACE_TSS_cleanup function + // when the thread terminates. + + if (ACE_Thread::setspecific (*(log_msg_tss_key()), + reinterpret_cast<void *> (tss_log_msg)) + != 0) + return 0; // Major problems, this should *never* happen! + } + } + + return tss_log_msg; +# else +# error "Platform must support thread-specific storage if threads are used." +# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ +#else /* ! ACE_MT_SAFE */ + // We don't have threads, we cannot call + // ACE_Log_Msg_Manager::get_lock () to initialize the logger + // callback, so instead we do it here. + if (ACE_Log_Msg_Manager::init_backend () == -1) + return 0; + + // Singleton implementation. + + if (log_msg_cleanup == 0) + { + ACE_NEW_RETURN (log_msg_cleanup, ACE_Msg_Log_Cleanup, 0); + // Register the instance for destruction at program termination. + ACE_Object_Manager::at_exit (log_msg_cleanup); + } + + return &log_msg_cleanup->object (); +#endif /* ! ACE_MT_SAFE */ +} + +// Not inlined to help prevent having to include OS.h just to +// get ACE_DEBUG, et al, macros. +int +ACE_Log_Msg::last_error_adapter (void) +{ + return ACE_OS::last_error (); +} + +// Sets the flag in the default priority mask used to initialize +// ACE_Log_Msg instances, as well as the current per-thread instance. + +void +ACE_Log_Msg::enable_debug_messages (ACE_Log_Priority priority) +{ + ACE_SET_BITS (ACE_Log_Msg::default_priority_mask_, priority); + ACE_Log_Msg *i = ACE_Log_Msg::instance (); + i->priority_mask (i->priority_mask () | priority); +} + +// Clears the flag in the default priority mask used to initialize +// ACE_Log_Msg instances, as well as the current per-thread instance. + +void +ACE_Log_Msg::disable_debug_messages (ACE_Log_Priority priority) +{ + ACE_CLR_BITS (ACE_Log_Msg::default_priority_mask_, priority); + ACE_Log_Msg *i = ACE_Log_Msg::instance (); + i->priority_mask (i->priority_mask () & ~priority); +} + +const ACE_TCHAR * +ACE_Log_Msg::program_name (void) +{ + return ACE_Log_Msg::program_name_; +} + +/// Name of the local host. +const ACE_TCHAR *ACE_Log_Msg::local_host_ = 0; + +/// Records the program name. +const ACE_TCHAR *ACE_Log_Msg::program_name_ = 0; + +/// Default is to use stderr. +u_long ACE_Log_Msg::flags_ = ACE_Log_Msg::STDERR; + +/// Process id of the current process. +pid_t ACE_Log_Msg::pid_ = -2; + +/// Current offset of msg_[]. +ptrdiff_t ACE_Log_Msg::msg_off_ = 0; + +/// Default per-thread priority mask +/// By default, no priorities are enabled. +u_long ACE_Log_Msg::default_priority_mask_ = 0; + +/// Default per-process priority mask +/// By default, all priorities are enabled. +u_long ACE_Log_Msg::process_priority_mask_ = LM_SHUTDOWN + | LM_TRACE + | LM_DEBUG + | LM_INFO + | LM_NOTICE + | LM_WARNING + | LM_STARTUP + | LM_ERROR + | LM_CRITICAL + | LM_ALERT + | LM_EMERGENCY; + +void +ACE_Log_Msg::close (void) +{ + // This call needs to go here to avoid memory leaks. + ACE_MT (ACE_Log_Msg_Manager::close ()); + + // Please note that this will be called by a statement that is + // harded coded into the ACE_Object_Manager's shutdown sequence, in + // its destructor. + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) && \ + (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \ + defined (ACE_HAS_TSS_EMULATION)) + + if (key_created_ == 1) + { + ACE_thread_mutex_t *lock = + reinterpret_cast<ACE_thread_mutex_t *> ( + ACE_OS_Object_Manager::preallocated_object + [ACE_OS_Object_Manager::ACE_LOG_MSG_INSTANCE_LOCK]); + ACE_OS::thread_mutex_lock (lock); + + if (key_created_ == 1) + { + // The same as the ACE_TSS_Cleanup's own key doesn't get + // detached, the log_msg_tss_key_ won't get detached + // until ACE_TSS_Cleanup::free_all_keys_left, so it will + // be in the ACE_TSS_Cleanup::table_. However, there's + // no resource associated with it, so we don't need to + // keyfree it. The dynamic memory associated with it was + // already deleted by ACE_TSS_Cleanup::exit (), so we + // don't want to access it again. + key_created_ = 0; +#ifdef ACE_HAS_BROKEN_THREAD_KEYFREE + // for some systems, e.g. LynxOS, we need to ensure that + // any registered thread destructor action for this thread + // is disabled. Otherwise in the event of a dynamic library + // unload of libACE, by a program not linked with libACE, + // ACE_TSS_cleanup will be invoked after libACE has been unloaded. + ACE_Log_Msg *tss_log_msg = 0; + void *temp = 0; + + // Get the tss_log_msg from thread-specific storage. + if (ACE_Thread::getspecific (*(log_msg_tss_key ()), &temp) != -1 + && temp) + { + tss_log_msg = static_cast <ACE_Log_Msg *> (temp); + // we haven't been cleaned up + ACE_TSS_CLEANUP_NAME(tss_log_msg); + if (ACE_Thread::setspecific(*(log_msg_tss_key()), + reinterpret_cast <void *>(0)) != 0) + { + ACE_OS::printf ("ACE_Log_Msg::close failed to ACE_Thread::setspecific to 0\n"); + } + } +#endif /* ACE_HAS_BROKEN_THREAD_KEYFREE */ + } + + ACE_OS::thread_mutex_unlock (lock); + } +#endif /* (ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION) && ACE_MT_SAFE */ +} + +void +ACE_Log_Msg::sync_hook (const ACE_TCHAR *prg_name) +{ + ACE_LOG_MSG->sync (prg_name); +} + +ACE_OS_Thread_Descriptor * +ACE_Log_Msg::thr_desc_hook (void) +{ + return ACE_LOG_MSG->thr_desc (); +} + +// Call after a fork to resynchronize the PID and PROGRAM_NAME +// variables. +void +ACE_Log_Msg::sync (const ACE_TCHAR *prog_name) +{ + ACE_TRACE ("ACE_Log_Msg::sync"); + + if (prog_name) + { + // Must free if already allocated!!! + ACE_OS::free ((void *) ACE_Log_Msg::program_name_); + + // Stop heap checking, block will be freed by the destructor when + // the last ACE_Log_Msg instance is deleted. + // Heap checking state will be restored when the block is left. + { + ACE_NO_HEAP_CHECK; + + ACE_Log_Msg::program_name_ = ACE_OS::strdup (prog_name); + } + } + + ACE_Log_Msg::pid_ = ACE_OS::getpid (); + ACE_Log_Msg::msg_off_ = 0; +} + +u_long +ACE_Log_Msg::flags (void) +{ + ACE_TRACE ("ACE_Log_Msg::flags"); + u_long result; + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock (), 0)); + + result = ACE_Log_Msg::flags_; + return result; +} + +void +ACE_Log_Msg::set_flags (u_long flgs) +{ + ACE_TRACE ("ACE_Log_Msg::set_flags"); + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock ())); + + ACE_SET_BITS (ACE_Log_Msg::flags_, flgs); +} + +void +ACE_Log_Msg::clr_flags (u_long flgs) +{ + ACE_TRACE ("ACE_Log_Msg::clr_flags"); + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock ())); + + ACE_CLR_BITS (ACE_Log_Msg::flags_, flgs); +} + +int +ACE_Log_Msg::acquire (void) +{ + ACE_TRACE ("ACE_Log_Msg::acquire"); +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + return ACE_Log_Msg_Manager::get_lock ()->acquire (); +#else /* ! ACE_MT_SAFE */ + return 0; +#endif /* ! ACE_MT_SAFE */ +} + +u_long +ACE_Log_Msg::priority_mask (u_long n_mask, MASK_TYPE mask_type) +{ + u_long o_mask; + + if (mask_type == THREAD) + { + o_mask = this->priority_mask_; + this->priority_mask_ = n_mask; + } + else + { + o_mask = ACE_Log_Msg::process_priority_mask_; + ACE_Log_Msg::process_priority_mask_ = n_mask; + } + + return o_mask; +} + +int +ACE_Log_Msg::release (void) +{ + ACE_TRACE ("ACE_Log_Msg::release"); + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + return ACE_Log_Msg_Manager::get_lock ()->release (); +#else /* ! ACE_MT_SAFE */ + return 0; +#endif /* ! ACE_MT_SAFE */ +} + +ACE_Log_Msg::ACE_Log_Msg (void) + : status_ (0), + errnum_ (0), + linenum_ (0), + msg_ (0), + restart_ (1), // Restart by default... + ostream_ (0), + msg_callback_ (0), + trace_depth_ (0), + trace_active_ (false), + tracing_enabled_ (true), // On by default? + delete_ostream_(false), + thr_desc_ (0), + priority_mask_ (default_priority_mask_), + timestamp_ (0) +{ + // ACE_TRACE ("ACE_Log_Msg::ACE_Log_Msg"); + + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock ())); + ++instance_count_; + + if (this->instance_count_ == 1) + ACE_Base_Thread_Adapter::set_log_msg_hooks (ACE_Log_Msg::init_hook, + ACE_Log_Msg::inherit_hook, + ACE_Log_Msg::close, + ACE_Log_Msg::sync_hook, + ACE_Log_Msg::thr_desc_hook); + + this->conditional_values_.is_set_ = false; + + char *timestamp = ACE_OS::getenv ("ACE_LOG_TIMESTAMP"); + if (timestamp != 0) + { + // If variable is set or is set to date tag so we print date and time. + if (ACE_OS::strcmp (timestamp, "TIME") == 0) + { + this->timestamp_ = 1; + } + else if (ACE_OS::strcmp (timestamp, "DATE") == 0) + { + this->timestamp_ = 2; + } + } + + ACE_NEW_NORETURN (this->msg_, ACE_TCHAR[ACE_MAXLOGMSGLEN+1]); +} + +ACE_Log_Msg::~ACE_Log_Msg (void) +{ +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + + int instance_count = 0; + + // Only hold the guard while updating the instance_count_. + // If ACE_Log_Msg_Manager::close () is called, the lock will + // be deleted. + { + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock ())); + instance_count = --instance_count_; + } + // Release the guard. + +#else /* ! ACE_MT_SAFE */ + int instance_count = --instance_count_; +#endif /* ! ACE_MT_SAFE */ + + // If this is the last instance then cleanup. Only the last + // thread to destroy its ACE_Log_Msg instance should execute + // this block. + if (instance_count == 0) + { + // Destroy the message queue instance. + if (ACE_Log_Msg_Manager::log_backend_ != 0) + ACE_Log_Msg_Manager::log_backend_->close (); + + // Close down custom backend + if (ACE_Log_Msg_Manager::custom_backend_ != 0) + ACE_Log_Msg_Manager::custom_backend_->close (); + +# if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +# if defined (ACE_HAS_TSS_EMULATION) + ACE_Log_Msg_Manager::close (); +# endif /* ACE_HAS_TSS_EMULATION */ +# endif /* ACE_MT_SAFE */ + + if (ACE_Log_Msg::program_name_) + { + ACE_OS::free ((void *) ACE_Log_Msg::program_name_); + ACE_Log_Msg::program_name_ = 0; + } + + if (ACE_Log_Msg::local_host_) + { + ACE_OS::free ((void *) ACE_Log_Msg::local_host_); + ACE_Log_Msg::local_host_ = 0; + } + } + + // + // do we need to close and clean up? + // + if (this->delete_ostream_) +#if defined (ACE_LACKS_IOSTREAM_TOTALLY) + { + ACE_OS::fclose (this->ostream_); + } +#else + { + delete ostream_; + ostream_ = 0; + } +#endif + + delete[] this->msg_; +} + +// Open the sender-side of the message queue. + +int +ACE_Log_Msg::open (const ACE_TCHAR *prog_name, + u_long flags, + const ACE_TCHAR *logger_key) +{ + ACE_TRACE ("ACE_Log_Msg::open"); + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock (), -1)); + + if (prog_name) + { + ACE_OS::free ((void *) ACE_Log_Msg::program_name_); + + // Stop heap checking, block will be freed by the destructor. + { + ACE_NO_HEAP_CHECK; + + ACE_ALLOCATOR_RETURN (ACE_Log_Msg::program_name_, + ACE_OS::strdup (prog_name), + -1); + } + } + else if (ACE_Log_Msg::program_name_ == 0) + { + // Stop heap checking, block will be freed by the destructor. + ACE_NO_HEAP_CHECK; + ACE_ALLOCATOR_RETURN (ACE_Log_Msg::program_name_, + ACE_OS::strdup (ACE_TEXT ("<unknown>")), + -1); + } + + int status = 0; + + // Be sure that there is a message_queue_, with multiple threads. + ACE_MT (ACE_Log_Msg_Manager::init_backend (&flags)); + + // Always close the current handle before doing anything else. + if (ACE_Log_Msg_Manager::log_backend_ != 0) + ACE_Log_Msg_Manager::log_backend_->reset (); + + if (ACE_Log_Msg_Manager::custom_backend_ != 0) + ACE_Log_Msg_Manager::custom_backend_->reset (); + + // Note that if we fail to open the message queue the default action + // is to use stderr (set via static initialization in the + // Log_Msg.cpp file). + + if (ACE_BIT_ENABLED (flags, ACE_Log_Msg::LOGGER) + || ACE_BIT_ENABLED (flags, ACE_Log_Msg::SYSLOG)) + { + // The SYSLOG backends (both NT and UNIX) can get along fine + // without the logger_key - they will default to prog_name if + // logger key is 0. + if (logger_key == 0 && ACE_BIT_ENABLED (flags, ACE_Log_Msg::LOGGER)) + status = -1; + else + status = ACE_Log_Msg_Manager::log_backend_->open (logger_key); + + if (status == -1) + ACE_SET_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::STDERR); + else + { + if (ACE_BIT_ENABLED (flags, ACE_Log_Msg::LOGGER)) + ACE_SET_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::LOGGER); + if (ACE_BIT_ENABLED (flags, ACE_Log_Msg::SYSLOG)) + ACE_SET_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::SYSLOG); + } + } + else if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::LOGGER) + || ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::SYSLOG)) + { + // If we are closing down logger, redirect logging to stderr. + ACE_CLR_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::LOGGER); + ACE_CLR_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::SYSLOG); + ACE_SET_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::STDERR); + } + + if (ACE_BIT_ENABLED (flags, ACE_Log_Msg::CUSTOM)) + { + status = + ACE_Log_Msg_Manager::custom_backend_->open (logger_key); + + if (status != -1) + ACE_SET_BITS (ACE_Log_Msg::flags_, ACE_Log_Msg::CUSTOM); + } + + // Remember, ACE_Log_Msg::STDERR bit is on by default... + if (status != -1 + && ACE_BIT_ENABLED (flags, + ACE_Log_Msg::STDERR) == 0) + ACE_CLR_BITS (ACE_Log_Msg::flags_, + ACE_Log_Msg::STDERR); + + // VERBOSE takes precedence over VERBOSE_LITE... + if (ACE_BIT_ENABLED (flags, + ACE_Log_Msg::VERBOSE_LITE)) + ACE_SET_BITS (ACE_Log_Msg::flags_, + ACE_Log_Msg::VERBOSE_LITE); + else if (ACE_BIT_ENABLED (flags, + ACE_Log_Msg::VERBOSE)) + ACE_SET_BITS (ACE_Log_Msg::flags_, + ACE_Log_Msg::VERBOSE); + + if (ACE_BIT_ENABLED (flags, + ACE_Log_Msg::OSTREAM)) + { + ACE_SET_BITS (ACE_Log_Msg::flags_, + ACE_Log_Msg::OSTREAM); + // Only set this to cerr if it hasn't already been set. + if (this->msg_ostream () == 0) + this->msg_ostream (ACE_DEFAULT_LOG_STREAM); + } + + if (ACE_BIT_ENABLED (flags, + ACE_Log_Msg::MSG_CALLBACK)) + ACE_SET_BITS (ACE_Log_Msg::flags_, + ACE_Log_Msg::MSG_CALLBACK); + + if (ACE_BIT_ENABLED (flags, + ACE_Log_Msg::SILENT)) + ACE_SET_BITS (ACE_Log_Msg::flags_, + ACE_Log_Msg::SILENT); + + return status; +} + +/** + * Valid Options (prefixed by '%', as in printf format strings) include: + * 'A': print an ACE_timer_t value + * 'a': exit the program at this point (var-argument is the exit status!) + * 'b': print a ssize_t value + * 'B': print a size_t value + * 'c': print a character + * 'C': print a character string + * 'i', 'd': print a decimal number + * 'I', indent according to nesting depth + * 'e', 'E', 'f', 'F', 'g', 'G': print a double + * 'l', print line number where an error occurred. + * 'M': print the name of the priority of the message. + * 'm': Return the message corresponding to errno value, e.g., as done by <strerror> + * 'N': print file name where the error occurred. + * 'n': print the name of the program (or "<unknown>" if not set) + * 'o': print as an octal number + * 'P': format the current process id + * 'p': format the appropriate errno message from sys_errlist, e.g., as done by <perror> + * 'Q': print out the uint64 number + * 'q': print out the int64 number + * '@': print a void* pointer (in hexadecimal) + * 'r': call the function pointed to by the corresponding argument + * 'R': print return status + * 'S': format the appropriate _sys_siglist entry corresponding to var-argument. + * 's': format a character string + * 'T': print timestamp in hour:minute:sec:usec format. + * 'D': print timestamp in month/day/year hour:minute:sec:usec format. + * 't': print thread id (1 if single-threaded) + * 'u': print as unsigned int + * 'x': print as a hex number + * 'X': print as a hex number + * 'w': print a wide character + * 'W': print out a wide character string. + * 'z': print an ACE_OS::WChar character + * 'Z': print an ACE_OS::WChar character string + * ':': print a time_t value as an integral number + * '%': format a single percent sign, '%' + */ +ssize_t +ACE_Log_Msg::log (ACE_Log_Priority log_priority, + const ACE_TCHAR *format_str, ...) +{ + ACE_TRACE ("ACE_Log_Msg::log"); + + // Start of variable args section. + va_list argp; + + va_start (argp, format_str); + + ssize_t const result = this->log (format_str, + log_priority, + argp); + va_end (argp); + + return result; +} + +#if defined (ACE_HAS_WCHAR) +/** + * Since this is the ANTI_TCHAR version, we need to convert + * the format string over. + */ +ssize_t +ACE_Log_Msg::log (ACE_Log_Priority log_priority, + const ACE_ANTI_TCHAR *format_str, ...) +{ + ACE_TRACE ("ACE_Log_Msg::log"); + + // Start of variable args section. + va_list argp; + + va_start (argp, format_str); + + ssize_t const result = this->log (ACE_TEXT_ANTI_TO_TCHAR (format_str), + log_priority, + argp); + va_end (argp); + + return result; +} +#endif /* ACE_HAS_WCHAR */ + +ssize_t +ACE_Log_Msg::log (const ACE_TCHAR *format_str, + ACE_Log_Priority log_priority, + va_list argp) +{ + ACE_TRACE ("ACE_Log_Msg::log"); + // External decls. + + typedef void (*PTF)(...); + + // Check if there were any conditional values set. + bool const conditional_values = this->conditional_values_.is_set_; + + // Reset conditional values. + this->conditional_values_.is_set_ = false; + + // Only print the message if <priority_mask_> hasn't been reset to + // exclude this logging priority. + if (this->log_priority_enabled (log_priority) == 0) + return 0; + + // If conditional values were set and the log priority is correct, + // then the values are actually set. + if (conditional_values) + this->set (this->conditional_values_.file_, + this->conditional_values_.line_, + this->conditional_values_.op_status_, + this->conditional_values_.errnum_, + this->restart (), + this->msg_ostream (), + this->msg_callback ()); + + // Logging is supposed to be a benign activity (i.e., not interfer + // with normal application operations), so don't inadvertently smash + // errno! + ACE_Errno_Guard guard (errno); + + ACE_Log_Record log_record (log_priority, + ACE_OS::gettimeofday (), + this->getpid ()); + + // bp is pointer to where to put next part of logged message. + // bspace is the number of characters remaining in msg_. + ACE_TCHAR *bp = const_cast<ACE_TCHAR *> (this->msg ()); + size_t bspace = ACE_Log_Record::MAXLOGMSGLEN; // Leave room for Nul term. + if (this->msg_off_ <= ACE_Log_Record::MAXLOGMSGLEN) + bspace -= static_cast<size_t> (this->msg_off_); + + // If this platform has snprintf() capability to prevent overrunning the + // output buffer, use it. To avoid adding a maintenance-hassle compile- + // time couple between here and OS.cpp, don't try to figure this out at + // compile time. Instead, do a quick check now; if we get a -1 return, + // the platform doesn't support the length-limiting capability. + ACE_TCHAR test[2]; + bool can_check = ACE_OS::snprintf (test, 1, ACE_TEXT ("x")) != -1; + + bool abort_prog = false; + int exit_value = 0; + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::VERBOSE)) + { + // Prepend the program name onto this message + + if (ACE_Log_Msg::program_name_ != 0) + { + for (const ACE_TCHAR *s = ACE_Log_Msg::program_name_; + bspace > 1 && (*bp = *s) != '\0'; + ++s, --bspace) + bp++; + + *bp++ = '|'; + --bspace; + } + } + + if (timestamp_ > 0) + { + ACE_TCHAR day_and_time[35]; + const ACE_TCHAR *s; + if (timestamp_ == 1) + { + // Print just the time + s = ACE::timestamp (day_and_time, sizeof day_and_time, 1); + } + else + { + // Print time and date + ACE::timestamp (day_and_time, sizeof day_and_time); + s = day_and_time; + } + + for (; bspace > 1 && (*bp = *s) != '\0'; ++s, --bspace) + ++bp; + + *bp++ = '|'; + --bspace; + } + + while (*format_str != '\0' && bspace > 0) + { + // Copy input to output until we encounter a %, however a + // % followed by another % is not a format specification. + + if (*format_str != '%') + { + *bp++ = *format_str++; + --bspace; + } + else if (format_str[1] == '%') // An "escaped" '%' (just print one '%'). + { + *bp++ = *format_str++; // Store first % + ++format_str; // but skip second % + --bspace; + } + else + { + // This is most likely a format specification that ends with + // one of the valid options described previously. To enable full + // use of all sprintf capabilities, save the format specifier + // from the '%' up to the format letter in a new char array. + // This allows the full sprintf capability for padding, field + // widths, alignment, etc. Any width/precision requiring a + // caller-supplied argument is extracted and placed as text + // into the format array. Lastly, we convert the caller-supplied + // format specifier from the ACE_Log_Msg-supported list to the + // equivalent sprintf specifier, and run the new format spec + // through sprintf, adding it to the bp string. + + const ACE_TCHAR *abort_str = ACE_TEXT ("Aborting..."); + const ACE_TCHAR *start_format = format_str; + ACE_TCHAR format[128]; // Converted format string + ACE_TCHAR *fp; // Current format pointer + int wp = 0; // Width/precision extracted from args + bool done = false; + bool skip_nul_locate = false; + int this_len = 0; // How many chars s[n]printf wrote + + fp = format; + *fp++ = *format_str++; // Copy in the % + + // Initialization to satisfy VC6 + int tmp_indent = 0; + // Work through the format string to copy in the format + // from the caller. While it's going across, extract ints + // for '*' width/precision values from the argument list. + // When the real format specifier is located, change it to + // one recognized by sprintf, if needed, and do the sprintf + // call. + + while (!done) + { + done = true; // Unless a conversion spec changes it + + switch (*format_str) + { + // The initial set of cases are the conversion + // specifiers. Copy them in to the format array. + // Note we don't use 'l', a normal conversion spec, + // as a conversion because it is a ACE_Log_Msg format + // specifier. + case '-': + case '+': + case '0': + case ' ': + case '#': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + case 'L': + case 'h': + *fp++ = *format_str; + done = false; + break; + + case '*': + wp = va_arg (argp, int); + ACE_OS::sprintf (fp, ACE_TEXT ("%d"), wp); + fp += ACE_OS::strlen (fp); + done = false; + break; + + case 'A': // ACE_timer_t + { + ACE_OS::strcpy (fp, ACE_TEXT ("f")); + double value = va_arg (argp, double); + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, format, value); + else + this_len = ACE_OS::sprintf (bp, format, value); + ACE_UPDATE_COUNT (bspace, this_len); + } + break; + + case 'a': // Abort program after handling all of format string. + abort_prog = true; + exit_value = va_arg (argp, int); + ACE_OS::strsncpy (bp, abort_str, bspace); + if (bspace > ACE_OS::strlen (abort_str)) + bspace -= ACE_OS::strlen (abort_str); + else + bspace = 0; + break; + + case 'l': // Source file line number + ACE_OS::strcpy (fp, ACE_TEXT ("d")); + if (can_check) + this_len = ACE_OS::snprintf (bp, + bspace, + format, + this->linenum ()); + else + this_len = ACE_OS::sprintf (bp, format, this->linenum ()); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'N': // Source file name +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +#else + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, format, + this->file () ? + ACE_TEXT_CHAR_TO_TCHAR (this->file ()) + : ACE_TEXT ("<unknown file>")); + else + this_len = ACE_OS::sprintf (bp, format, + this->file () ? + ACE_TEXT_CHAR_TO_TCHAR (this->file ()) + : ACE_TEXT ("<unknown file>")); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'n': // Program name +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +#else /* ACE_WIN32 && ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, format, + ACE_Log_Msg::program_name_ ? + ACE_Log_Msg::program_name_ : + ACE_TEXT ("<unknown>")); + else + this_len = ACE_OS::sprintf (bp, format, + ACE_Log_Msg::program_name_ ? + ACE_Log_Msg::program_name_ : + ACE_TEXT ("<unknown>")); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'P': // Process ID +#if defined (ACE_OPENVMS) + // Print the process id in hex on OpenVMS. + ACE_OS::strcpy (fp, ACE_TEXT ("x")); +#else + ACE_OS::strcpy (fp, ACE_TEXT ("d")); +#endif + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, + static_cast<int> (this->getpid ())); + else + this_len = ACE_OS::sprintf + (bp, format, static_cast<int> (this->getpid ())); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'p': // <errno> string, ala perror() + { + errno = 0; + char *msg = ACE_OS::strerror (ACE::map_errno (this->errnum ())); + // Windows can try to translate the errnum using + // system calls if strerror() doesn't get anything useful. +#if defined (ACE_WIN32) + if (errno == 0) + { +#endif + +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("ls: %ls")); +#else + ACE_OS::strcpy (fp, ACE_TEXT ("s: %s")); +#endif + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, ACE_TCHAR *), + ACE_TEXT_CHAR_TO_TCHAR (msg)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, ACE_TCHAR *), + ACE_TEXT_CHAR_TO_TCHAR (msg)); +#if defined (ACE_WIN32) + } + else + { + errno = ACE::map_errno (this->errnum ()); + ACE_TCHAR *lpMsgBuf = 0; + + // PharLap can't do FormatMessage, so try for socket + // error. +# if !defined (ACE_HAS_PHARLAP) + ACE_TEXT_FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_MAX_WIDTH_MASK + | FORMAT_MESSAGE_FROM_SYSTEM, + 0, + errno, + MAKELANGID (LANG_NEUTRAL, + SUBLANG_DEFAULT), + // Default language + (ACE_TCHAR *) &lpMsgBuf, + 0, + 0); +# endif /* ACE_HAS_PHARLAP */ + + // If we don't get a valid response from + // <FormatMessage>, we'll assume this is a + // WinSock error and so we'll try to convert + // it into a string. If this doesn't work it + // returns "unknown error" which is fine for + // our purposes. + if (lpMsgBuf == 0) + { + const ACE_TCHAR *message = + ACE::sock_error (errno); + ACE_OS::strcpy (fp, ACE_TEXT ("s: %s")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, + va_arg (argp, const ACE_TCHAR *), + message); + else + this_len = ACE_OS::sprintf + (bp, format, + va_arg (argp, const ACE_TCHAR *), + message); + } + else + { + ACE_OS::strcpy (fp, ACE_TEXT ("s: %s")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, + va_arg (argp, ACE_TCHAR *), + lpMsgBuf); + else + this_len = ACE_OS::sprintf + (bp, format, + va_arg (argp, ACE_TCHAR *), + lpMsgBuf); + // Free the buffer. + ::LocalFree (lpMsgBuf); + } + } +#endif /* ACE_WIN32 */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 'M': // Print the name of the priority of the message. +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +#else + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, + ACE_Log_Record::priority_name (log_priority)); + else + this_len = ACE_OS::sprintf + (bp, format, + ACE_Log_Record::priority_name (log_priority)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'm': // Format the string assocated with the errno value. + { + errno = 0; + char *msg = 0; + msg = ACE_OS::strerror (ACE::map_errno (this->errnum ())); + // Windows can try to translate the errnum using + // system calls if strerror() doesn't get anything useful. +#if defined (ACE_WIN32) + if (errno == 0) + { +#endif + +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +#else /* ACE_WIN32 && ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, ACE_TEXT_CHAR_TO_TCHAR (msg)); + else + this_len = ACE_OS::sprintf + (bp, format, ACE_TEXT_CHAR_TO_TCHAR (msg)); +#if defined (ACE_WIN32) + } + else + { + errno = ACE::map_errno (this->errnum ()); + ACE_TCHAR *lpMsgBuf = 0; + + // PharLap can't do FormatMessage, so try for socket + // error. +# if !defined (ACE_HAS_PHARLAP) + ACE_TEXT_FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_MAX_WIDTH_MASK + | FORMAT_MESSAGE_FROM_SYSTEM, + 0, + errno, + MAKELANGID (LANG_NEUTRAL, + SUBLANG_DEFAULT), + // Default language + (ACE_TCHAR *) &lpMsgBuf, + 0, + 0); +# endif /* ACE_HAS_PHARLAP */ + + // If we don't get a valid response from + // <FormatMessage>, we'll assume this is a + // WinSock error and so we'll try to convert + // it into a string. If this doesn't work it + // returns "unknown error" which is fine for + // our purposes. + if (lpMsgBuf == 0) + { + const ACE_TCHAR *message = + ACE::sock_error (errno); + ACE_OS::strcpy (fp, ACE_TEXT ("s")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, message); + else + this_len = ACE_OS::sprintf (bp, format, message); + } + else + { + ACE_OS::strcpy (fp, ACE_TEXT ("s")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, lpMsgBuf); + else + this_len = ACE_OS::sprintf + (bp, format, lpMsgBuf); + // Free the buffer. + ::LocalFree (lpMsgBuf); + } + } +#endif /* ACE_WIN32 */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 'R': // Format the return status of the operation. + this->op_status (va_arg (argp, int)); + ACE_OS::strcpy (fp, ACE_TEXT ("d")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, this->op_status ()); + else + this_len = ACE_OS::sprintf + (bp, format, this->op_status ()); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case '{': // Increment the trace_depth, then indent + skip_nul_locate = true; + (void) this->inc (); + break; + + case '}': // indent, then decrement trace_depth + skip_nul_locate = true; + (void) this->dec (); + break; + + case '$': // insert a newline, then indent the next line + // according to %I + *bp++ = '\n'; + --bspace; + /* fallthrough */ + + case 'I': // Indent with nesting_depth*width spaces + // Caller can do %*I to override nesting indent, and + // if %*I was done, wp has the extracted width. +#if defined (ACE_HAS_TRACE) + if (0 == wp) + wp = ACE_Trace::get_nesting_indent (); +#else + if (0 == wp) + wp = 4; +#endif /* ACE_HAS_TRACE */ + wp *= this->trace_depth_; + if (static_cast<size_t> (wp) > bspace) + wp = static_cast<int> (bspace); + for (tmp_indent = wp; + tmp_indent; + --tmp_indent) + *bp++ = ' '; + + *bp = '\0'; + bspace -= static_cast<size_t> (wp); + skip_nul_locate = true; + break; + + case 'r': // Run (invoke) this subroutine. + { + ptrdiff_t const osave = ACE_Log_Msg::msg_off_; + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, + ACE_Log_Msg::SILENT) && + bspace > 1) + { + *bp++ = '{'; + --bspace; + } + ACE_Log_Msg::msg_off_ = bp - this->msg_; + + (*va_arg (argp, PTF))(); + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, + ACE_Log_Msg::SILENT) && + bspace > (1 + ACE_OS::strlen (bp))) + { + bspace -= (ACE_OS::strlen (bp) + 1); + bp += ACE_OS::strlen (bp); + *bp++ = '}'; + } + *bp = '\0'; + skip_nul_locate = true; + ACE_Log_Msg::msg_off_ = osave; + break; + } + + case 'S': // format the string for with this signal number. + { + int sig = va_arg (argp, int); +#if defined (ACE_HAS_SYS_SIGLIST) + if (sig >= 0 && sig < ACE_NSIG) + { + ACE_OS::strcpy (fp, ACE_TEXT ("s")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, _sys_siglist[sig]); + else + this_len = ACE_OS::sprintf + (bp, format, _sys_siglist[sig]); + } + else + { + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, + ACE_TEXT("<unknown signal> %d"), sig); + else + this_len = ACE_OS::sprintf + (bp, ACE_TEXT ("<unknown signal> %d"), sig); + } +#else + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, ACE_TEXT ("signal %d"), sig); + else + this_len = ACE_OS::sprintf + (bp, ACE_TEXT ("signal %d"), sig); +#endif /* ACE_HAS_SYS_SIGLIST */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 'D': // Format the timestamp in format: + // Weekday Month day year hour:minute:sec.usec + { + ACE_TCHAR day_and_time[35]; + ACE::timestamp (day_and_time, + sizeof day_and_time); +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +#else + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, day_and_time); + else + this_len = ACE_OS::sprintf (bp, format, day_and_time); + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 'T': // Format the timestamp in + // hour:minute:sec:usec format. + { + ACE_TCHAR day_and_time[35]; + ACE_OS::strcpy (fp, ACE_TEXT ("s")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, + ACE::timestamp (day_and_time, sizeof day_and_time)); + else + this_len = ACE_OS::sprintf + (bp, format, ACE::timestamp (day_and_time, + sizeof day_and_time)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 't': // Format thread id. +#if defined (ACE_WIN32) + ACE_OS::strcpy (fp, ACE_TEXT ("u")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, + static_cast<unsigned> (ACE_Thread::self ())); + else + this_len = + ACE_OS::sprintf (bp, + format, + static_cast <unsigned> (ACE_Thread::self ())); +#elif defined (DIGITAL_UNIX) + ACE_OS::strcpy (fp, ACE_TEXT ("u")); + { + int id = +# if defined (ACE_HAS_THREADS) + pthread_getselfseq_np (); +# else + ACE_Thread::self (); +# endif /* ACE_HAS_THREADS */ + + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, format, id); + else + this_len = ACE_OS::sprintf (bp, format, id); + } +#else + ACE_hthread_t t_id; + ACE_Thread::self (t_id); + +# if defined (ACE_MVS) || defined (ACE_TANDEM_T1248_PTHREADS) + // MVS's pthread_t is a struct... yuck. So use the ACE 5.0 + // code for it. + ACE_OS::strcpy (fp, ACE_TEXT ("u")); + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, format, t_id); + else + this_len = ACE_OS::sprintf (bp, format, t_id); +# else + // Yes, this is an ugly C-style cast, but the correct + // C++ cast is different depending on whether the t_id + // is an integral type or a pointer type. FreeBSD uses + // a pointer type, but doesn't have a _np function to + // get an integral type, like the OSes above. + ACE_OS::strcpy (fp, ACE_TEXT ("lu")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, (unsigned long)t_id); + else + this_len = ACE_OS::sprintf + (bp, format, (unsigned long)t_id); +# endif /* ACE_MWS || ACE_TANDEM_T1248_PTHREADS */ + +#endif /* ACE_WIN32 */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 's': // String + { +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + wchar_t *str = va_arg (argp, wchar_t *); + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +#else /* ACE_WIN32 && ACE_USES_WCHAR */ + ACE_TCHAR *str = va_arg (argp, ACE_TCHAR *); + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif /* ACE_WIN32 && ACE_USES_WCHAR */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, str ? str : ACE_TEXT ("(null)")); + else + this_len = ACE_OS::sprintf + (bp, format, str ? str : ACE_TEXT ("(null)")); + ACE_UPDATE_COUNT (bspace, this_len); + } + break; + + case 'C': // Char string, Unicode for Win32/WCHAR + { + ACE_TCHAR *cstr = va_arg (argp, ACE_TCHAR *); +#if defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("S")); +#else /* ACE_WIN32 && ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +#endif /* ACE_WIN32 && ACE_USES_WCHAR */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, cstr ? cstr : ACE_TEXT ("(null)")); + else + this_len = ACE_OS::sprintf + (bp, format, cstr ? cstr : ACE_TEXT ("(null)")); + ACE_UPDATE_COUNT (bspace, this_len); + } + break; + + case 'W': + { +#if defined (ACE_HAS_WCHAR) + wchar_t *wchar_str = va_arg (argp, wchar_t *); +# if defined (HPUX) + ACE_OS::strcpy (fp, ACE_TEXT ("S")); +# elif defined (ACE_WIN32) +# if defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +# else /* ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("S")); +# endif /* ACE_USES_WCHAR */ +# else + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +# endif /* HPUX */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, wchar_str ? wchar_str : ACE_TEXT_WIDE("(null)")); + else + this_len = ACE_OS::sprintf + (bp, format, wchar_str ? wchar_str : ACE_TEXT_WIDE("(null)")); +#endif /* ACE_HAS_WCHAR */ + ACE_UPDATE_COUNT (bspace, this_len); + } + break; + + case 'w': // Wide character +#if defined (ACE_WIN32) +# if defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("c")); +# else /* ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("C")); +# endif /* ACE_USES_WCHAR */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, int)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, int)); +#elif defined (ACE_USES_WCHAR) +# if defined (HPUX) + ACE_OS::strcpy (fp, ACE_TEXT ("C")); +# else + ACE_OS::strcpy (fp, ACE_TEXT ("lc")); +# endif /* HPUX */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, wint_t)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, wint_t)); +#else /* ACE_WIN32 */ + ACE_OS::strcpy (fp, ACE_TEXT ("u")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, int)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, int)); +#endif /* ACE_WIN32 */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'z': // ACE_OS::WChar character + { + // On some platforms sizeof (wchar_t) can be 2 + // on the others 4 ... + wchar_t wtchar = + static_cast<wchar_t> (va_arg (argp, int)); +#if defined (ACE_WIN32) +# if defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("c")); +# else /* ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("C")); +# endif /* ACE_USES_WCHAR */ +#elif defined (ACE_USES_WCHAR) +# if defined (HPUX) + ACE_OS::strcpy (fp, ACE_TEXT ("C")); +# else + ACE_OS::strcpy (fp, ACE_TEXT ("lc")); +# endif /* HPUX */ +#else /* ACE_WIN32 */ + ACE_OS::strcpy (fp, ACE_TEXT ("u")); +#endif /* ACE_WIN32 */ + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, format, wtchar); + else + this_len = ACE_OS::sprintf (bp, format, wtchar); + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 'Z': // ACE_OS::WChar character string + { + ACE_OS::WChar *wchar_str = va_arg (argp, ACE_OS::WChar*); + if (wchar_str == 0) + break; + + wchar_t *wchar_t_str = 0; + if (sizeof (ACE_OS::WChar) != sizeof (wchar_t)) + { + size_t len = ACE_OS::wslen (wchar_str) + 1; + ACE_NEW_NORETURN(wchar_t_str, wchar_t[len]); + if (wchar_t_str == 0) + break; + + for (size_t i = 0; i < len; ++i) + { + wchar_t_str[i] = wchar_str[i]; + } + } + + if (wchar_t_str == 0) + { + wchar_t_str = reinterpret_cast<wchar_t*> (wchar_str); + } +#if defined (ACE_WIN32) +# if defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("s")); +# else /* ACE_USES_WCHAR */ + ACE_OS::strcpy (fp, ACE_TEXT ("S")); +# endif /* ACE_USES_WCHAR */ +#elif defined (ACE_HAS_WCHAR) +# if defined (HPUX) + ACE_OS::strcpy (fp, ACE_TEXT ("S")); +# else + ACE_OS::strcpy (fp, ACE_TEXT ("ls")); +# endif /* HPUX */ +#endif /* ACE_WIN32 / ACE_HAS_WCHAR */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, wchar_t_str); + else + this_len = ACE_OS::sprintf (bp, format, wchar_t_str); + if(sizeof(ACE_OS::WChar) != sizeof(wchar_t)) + { + delete [] wchar_t_str; + } + ACE_UPDATE_COUNT (bspace, this_len); + break; + } + + case 'c': +#if defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_OS::strcpy (fp, ACE_TEXT ("C")); +#else + ACE_OS::strcpy (fp, ACE_TEXT ("c")); +#endif /* ACE_WIN32 && ACE_USES_WCHAR */ + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, int)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, int)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'd': case 'i': case 'o': + case 'u': case 'x': case 'X': + fp[0] = *format_str; + fp[1] = '\0'; + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, int)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, int)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'F': case 'f': case 'e': case 'E': + case 'g': case 'G': + fp[0] = *format_str; + fp[1] = '\0'; + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, double)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, double)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'Q': +#if defined (ACE_LACKS_LONGLONG_T) || defined (ACE_LACKS_UNSIGNEDLONGLONG_T) + { + // This relies on the ACE_U_LongLong storage layout. + ACE_UINT32 hi = va_arg (argp, ACE_UINT32); + ACE_UINT32 lo = va_arg (argp, ACE_UINT32); + if (hi > 0) + this_len = ACE_OS::sprintf (bp, + "0x%lx%0*lx", + hi, + 2 * sizeof lo, + lo); + else + this_len = ACE_OS::sprintf (bp, "0x%lx", lo); + } +#else /* ! ACE_LACKS_LONGLONG_T */ + { + const ACE_TCHAR *fmt = ACE_UINT64_FORMAT_SPECIFIER; + ACE_OS::strcpy (fp, &fmt[1]); // Skip leading % + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, + format, + va_arg (argp, ACE_UINT64)); + else + this_len = ACE_OS::sprintf (bp, + format, + va_arg (argp, ACE_UINT64)); + } +#endif /* ! ACE_LACKS_LONGLONG_T || ACE_LACKS_UNSIGNEDLONGLONG_T */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'q': + #if defined (ACE_LACKS_LONGLONG_T) + // No implementation available yet, no ACE_INT64 emulation + // available yet + #else /* ! ACE_LACKS_LONGLONG_T */ + { + const ACE_TCHAR *fmt = ACE_INT64_FORMAT_SPECIFIER; + ACE_OS::strcpy (fp, &fmt[1]); // Skip leading % + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, + format, + va_arg (argp, ACE_INT64)); + else + this_len = ACE_OS::sprintf (bp, + format, + va_arg (argp, ACE_INT64)); + } + #endif /* ! ACE_LACKS_LONGLONG_T */ + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'b': + { + const ACE_TCHAR *fmt = ACE_SSIZE_T_FORMAT_SPECIFIER; + ACE_OS::strcpy (fp, &fmt[1]); // Skip leading % + } + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, + format, + va_arg (argp, ssize_t)); + else + this_len = ACE_OS::sprintf (bp, + format, + va_arg (argp, ssize_t)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case 'B': + { + const ACE_TCHAR *fmt = ACE_SIZE_T_FORMAT_SPECIFIER; + ACE_OS::strcpy (fp, &fmt[1]); // Skip leading % + } + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, + format, + va_arg (argp, size_t)); + else + this_len = ACE_OS::sprintf (bp, + format, + va_arg (argp, size_t)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case ':': + { + // Assume a 32 bit time_t and change if needed. + const ACE_TCHAR *fmt = ACE_TEXT ("%d"); + if (sizeof (time_t) == 8) + fmt = ACE_INT64_FORMAT_SPECIFIER; + + ACE_OS::strcpy (fp, &fmt[1]); // Skip leading % + } + if (can_check) + this_len = ACE_OS::snprintf (bp, bspace, + format, + va_arg (argp, time_t)); + else + this_len = ACE_OS::sprintf (bp, + format, + va_arg (argp, time_t)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + case '@': + ACE_OS::strcpy (fp, ACE_TEXT ("p")); + if (can_check) + this_len = ACE_OS::snprintf + (bp, bspace, format, va_arg (argp, void*)); + else + this_len = ACE_OS::sprintf + (bp, format, va_arg (argp, void*)); + ACE_UPDATE_COUNT (bspace, this_len); + break; + + default: + // So, it's not a legit format specifier after all... + // Copy from the original % to where we are now, then + // continue with whatever comes next. + while (start_format != format_str && bspace > 0) + { + *bp++ = *start_format++; + --bspace; + } + if (bspace > 0) + { + *bp++ = *format_str; + --bspace; + } + break; + } + + // Bump to the next char in the caller's format_str + ++format_str; + } + + if (!skip_nul_locate) + while (*bp != '\0') // Locate end of bp. + ++bp; + } + } + + *bp = '\0'; // Terminate bp, but don't auto-increment this! + + ssize_t result = 0; + + // Check that memory was not corrupted, if it corrupted we can't log anything + // anymore because all our members could be corrupted. + if (bp >= (this->msg_ + ACE_MAXLOGMSGLEN+1)) + { + abort_prog = true; + ACE_OS::fprintf (stderr, + "The following logged message is too long!\n"); + } + else + { + // Copy the message from thread-specific storage into the transfer + // buffer (this can be optimized away by changing other code...). + log_record.msg_data (this->msg ()); + + // Write the <log_record> to the appropriate location. + result = this->log (log_record, + abort_prog); + } + + if (abort_prog) + { + // Since we are now calling abort instead of exit, this value is + // not used. + ACE_UNUSED_ARG (exit_value); + + // *Always* print a message to stderr if we're aborting. We + // don't use verbose, however, to avoid recursive aborts if + // something is hosed. + log_record.print (ACE_Log_Msg::local_host_, 0, stderr); + ACE_OS::abort (); + } + + return result; +} + +#if !defined (ACE_WIN32) +/** + * @class ACE_Log_Msg_Sig_Guard + * + * @brief For use only by ACE_Log_Msg. + * + * Doesn't require the use of global variables or global + * functions in an application). + */ +class ACE_Log_Msg_Sig_Guard +{ +private: + ACE_Log_Msg_Sig_Guard (void); + ~ACE_Log_Msg_Sig_Guard (void); + + /// Original signal mask. + sigset_t omask_; + + friend ssize_t ACE_Log_Msg::log (ACE_Log_Record &log_record, + int suppress_stderr); +}; + +ACE_Log_Msg_Sig_Guard::ACE_Log_Msg_Sig_Guard (void) +{ +#if !defined (ACE_LACKS_UNIX_SIGNALS) + ACE_OS::sigemptyset (&this->omask_); + +# if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK) + ACE_OS::sigprocmask (SIG_BLOCK, + ACE_OS_Object_Manager::default_mask (), + &this->omask_); +# else + ACE_OS::thr_sigsetmask (SIG_BLOCK, + ACE_OS_Object_Manager::default_mask (), + &this->omask_); +# endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */ +#endif /* ACE_LACKS_UNIX_SIGNALS */ +} + +ACE_Log_Msg_Sig_Guard::~ACE_Log_Msg_Sig_Guard (void) +{ +#if !defined (ACE_LACKS_UNIX_SIGNALS) +# if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK) + ACE_OS::sigprocmask (SIG_SETMASK, + &this->omask_, + 0); +# else + ACE_OS::thr_sigsetmask (SIG_SETMASK, + &this->omask_, + 0); +# endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */ +#endif /* ! ACE_LACKS_UNIX_SIGNALS */ +} +#endif /* ! ACE_WIN32 */ + +ssize_t +ACE_Log_Msg::log (ACE_Log_Record &log_record, + int suppress_stderr) +{ + ssize_t result = 0; + + // Format the message and print it to stderr and/or ship it off to + // the log_client daemon, and/or print it to the ostream. Of + // course, only print the message if "SILENT" mode is disabled. + if (ACE_BIT_DISABLED (ACE_Log_Msg::flags_, + ACE_Log_Msg::SILENT)) + { + bool tracing = this->tracing_enabled (); + this->stop_tracing (); + +#if !defined (ACE_WIN32) + // Make this block signal-safe. + ACE_Log_Msg_Sig_Guard sb; +#endif /* !ACE_WIN32 */ + + // Do the callback, if needed, before acquiring the lock + // to avoid holding the lock during the callback so we don't + // have deadlock if the callback uses the logger. + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, + ACE_Log_Msg::MSG_CALLBACK) + && this->msg_callback () != 0) + this->msg_callback ()->log (log_record); + + // Make sure that the lock is held during all this. + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock (), + -1)); + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, + ACE_Log_Msg::STDERR) + && !suppress_stderr) // This is taken care of by our caller. + log_record.print (ACE_Log_Msg::local_host_, + ACE_Log_Msg::flags_, + stderr); + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::CUSTOM) || + ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::SYSLOG) || + ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::LOGGER)) + { + // Be sure that there is a message_queue_, with multiple threads. + ACE_MT (ACE_Log_Msg_Manager::init_backend ()); + } + + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::LOGGER) || + ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::SYSLOG)) + { + result = + ACE_Log_Msg_Manager::log_backend_->log (log_record); + } + + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, ACE_Log_Msg::CUSTOM) && + ACE_Log_Msg_Manager::custom_backend_ != 0) + { + result = + ACE_Log_Msg_Manager::custom_backend_->log (log_record); + } + + + // This must come last, after the other two print operations + // (see the <ACE_Log_Record::print> method for details). + if (ACE_BIT_ENABLED (ACE_Log_Msg::flags_, + ACE_Log_Msg::OSTREAM) + && this->msg_ostream () != 0) + log_record.print (ACE_Log_Msg::local_host_, + ACE_Log_Msg::flags_, +#if defined (ACE_LACKS_IOSTREAM_TOTALLY) + static_cast<FILE *> (this->msg_ostream ()) +#else /* ! ACE_LACKS_IOSTREAM_TOTALLY */ + *this->msg_ostream () +#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */ + ); + + if (tracing) + this->start_tracing (); + } + + return result; +} + +// Calls log to do the actual print, but formats first. + +int +ACE_Log_Msg::log_hexdump (ACE_Log_Priority log_priority, + const char *buffer, + size_t size, + const ACE_TCHAR *text) +{ + // Only print the message if <priority_mask_> hasn't been reset to + // exclude this logging priority. + if (this->log_priority_enabled (log_priority) == 0) + return 0; + + ACE_TCHAR* buf = 0; + const size_t buf_sz = + ACE_Log_Record::MAXLOGMSGLEN - ACE_Log_Record::VERBOSE_LEN - 58; + ACE_NEW_RETURN (buf, ACE_TCHAR[buf_sz], -1); + + ACE_TCHAR *msg_buf = 0; + const size_t text_sz = text ? ACE_OS::strlen(text) : 0; + ACE_NEW_RETURN (msg_buf, + ACE_TCHAR[text_sz + 58], + -1); + + buf[0] = 0; // in case size = 0 + + const size_t len = ACE::format_hexdump + (buffer, size, buf, buf_sz / sizeof (ACE_TCHAR) - text_sz); + + int sz = 0; + + if (text) + sz = ACE_OS::sprintf (msg_buf, + ACE_TEXT ("%s - "), + text); + + sz += ACE_OS::sprintf (msg_buf + sz, + ACE_TEXT ("HEXDUMP ") + ACE_SIZE_T_FORMAT_SPECIFIER + ACE_TEXT (" bytes"), + size); + + if (len < size) + ACE_OS::sprintf (msg_buf + sz, + ACE_TEXT (" (showing first ") + ACE_SIZE_T_FORMAT_SPECIFIER + ACE_TEXT (" bytes)"), + len); + + // Now print out the formatted buffer. + this->log (log_priority, + ACE_TEXT ("%s\n%s"), + msg_buf, + buf); + + delete [] msg_buf; + delete [] buf; + return 0; +} + +void +ACE_Log_Msg::set (const char *filename, + int line, + int status, + int err, + int rs, + ACE_OSTREAM_TYPE *os, + ACE_Log_Msg_Callback *c) +{ + ACE_TRACE ("ACE_Log_Msg::set"); + this->file (filename); + this->linenum (line); + this->op_status (status); + this->errnum (err); + this->restart (rs); + this->msg_ostream (os); + this->msg_callback (c); +} + +void +ACE_Log_Msg::conditional_set (const char *filename, + int line, + int status, + int err) +{ + this->conditional_values_.is_set_ = true; + this->conditional_values_.file_ = filename; + this->conditional_values_.line_ = line; + this->conditional_values_.op_status_ = status; + this->conditional_values_.errnum_ = err; +} + +void +ACE_Log_Msg::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Log_Msg::dump"); + + ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("status_ = %d\n"), this->status_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nerrnum_ = %d\n"), this->errnum_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nlinenum_ = %d\n"), this->linenum_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nfile_ = %C\n"), this->file_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmsg_ = %s\n"), this->msg_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nrestart_ = %d\n"), this->restart_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nostream_ = %@\n"), this->ostream_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmsg_callback_ = %@\n"), + this->msg_callback_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nprogram_name_ = %s\n"), + this->program_name_ ? this->program_name_ + : ACE_TEXT ("<unknown>"))); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nlocal_host_ = %s\n"), + this->local_host_ ? this->local_host_ + : ACE_TEXT ("<unknown>"))); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\npid_ = %d\n"), this->getpid ())); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nflags_ = 0x%x\n"), this->flags_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntrace_depth_ = %d\n"), + this->trace_depth_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntrace_active_ = %d\n"), + this->trace_active_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntracing_enabled_ = %d\n"), + this->tracing_enabled_)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\npriority_mask_ = 0x%x\n"), + this->priority_mask_)); + if (this->thr_desc_ != 0 && this->thr_desc_->state () != 0) + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_state_ = %d\n"), + this->thr_desc_->state ())); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmsg_off_ = %d\n"), this->msg_off_)); + + // Be sure that there is a message_queue_, with multiple threads. + ACE_MT (ACE_Log_Msg_Manager::init_backend ()); + + ACE_MT (ACE_Log_Msg_Manager::get_lock ()->dump ()); + // Synchronize output operations. + + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +void +ACE_Log_Msg::thr_desc (ACE_Thread_Descriptor *td) +{ + this->thr_desc_ = td; + + if (td != 0) + td->acquire_release (); +} + +#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) && defined(ACE_LEGACY_MODE) +ACE_SEH_EXCEPT_HANDLER +ACE_Log_Msg::seh_except_selector (void) +{ + return ACE_OS_Object_Manager::seh_except_selector (); +} + +ACE_SEH_EXCEPT_HANDLER +ACE_Log_Msg::seh_except_selector (ACE_SEH_EXCEPT_HANDLER n) +{ + return ACE_OS_Object_Manager::seh_except_selector (n); +} + +ACE_SEH_EXCEPT_HANDLER +ACE_Log_Msg::seh_except_handler (void) +{ + return ACE_OS_Object_Manager::seh_except_handler (); +} + +ACE_SEH_EXCEPT_HANDLER +ACE_Log_Msg::seh_except_handler (ACE_SEH_EXCEPT_HANDLER n) +{ + return ACE_OS_Object_Manager::seh_except_handler (n); +} +#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS && ACE_LEGACY_MODE */ + +ACE_Log_Msg_Backend * +ACE_Log_Msg::msg_backend (ACE_Log_Msg_Backend *b) +{ + ACE_TRACE ("ACE_Log_Msg::msg_backend"); + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock (), 0)); + + ACE_Log_Msg_Backend *tmp = ACE_Log_Msg_Manager::custom_backend_; + ACE_Log_Msg_Manager::custom_backend_ = b; + return tmp; +} + +ACE_Log_Msg_Backend * +ACE_Log_Msg::msg_backend (void) +{ + ACE_TRACE ("ACE_Log_Msg::msg_backend"); + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Log_Msg_Manager::get_lock (), 0)); + + return ACE_Log_Msg_Manager::custom_backend_; +} + +void +ACE_Log_Msg::msg_ostream (ACE_OSTREAM_TYPE *m, bool delete_ostream) +{ + if (this->ostream_ == m) + return; + + if (this->delete_ostream_) + { +#if defined (ACE_LACKS_IOSTREAM_TOTALLY) + ACE_OS::fclose (this->ostream_); +#else + delete this->ostream_; +#endif + } + + this->delete_ostream_ = delete_ostream; + this->ostream_ = m; +} + +void +ACE_Log_Msg::local_host (const ACE_TCHAR *s) +{ + if (s) + { + ACE_OS::free ((void *) ACE_Log_Msg::local_host_); + { + ACE_NO_HEAP_CHECK; + + ACE_ALLOCATOR (ACE_Log_Msg::local_host_, ACE_OS::strdup (s)); + } + } +} + +int +ACE_Log_Msg::log_priority_enabled (ACE_Log_Priority log_priority, + const char *, + ...) +{ + return this->log_priority_enabled (log_priority); +} + +#if defined (ACE_USES_WCHAR) +int +ACE_Log_Msg::log_priority_enabled (ACE_Log_Priority log_priority, + const wchar_t *, + ...) +{ + return this->log_priority_enabled (log_priority); +} +#endif /* ACE_USES_WCHAR */ + +// **************************************************************** + +void +ACE_Log_Msg::init_hook (ACE_OS_Log_Msg_Attributes &attributes +# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , ACE_SEH_EXCEPT_HANDLER selector + , ACE_SEH_EXCEPT_HANDLER handler +# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + ) +{ +# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + attributes.seh_except_selector_ = selector; + attributes.seh_except_handler_ = handler; +# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + if (ACE_Log_Msg::exists ()) + { + ACE_Log_Msg *inherit_log = ACE_LOG_MSG; + attributes.ostream_ = inherit_log->msg_ostream (); + attributes.priority_mask_ = inherit_log->priority_mask (); + attributes.tracing_enabled_ = inherit_log->tracing_enabled (); + attributes.restart_ = inherit_log->restart (); + attributes.trace_depth_ = inherit_log->trace_depth (); + } +} + +void +ACE_Log_Msg::inherit_hook (ACE_OS_Thread_Descriptor *thr_desc, + ACE_OS_Log_Msg_Attributes &attributes) +{ +#if !defined (ACE_THREADS_DONT_INHERIT_LOG_MSG) && \ + !defined (ACE_HAS_MINIMAL_ACE_OS) + // Inherit the logging features if the parent thread has an + // <ACE_Log_Msg>. Note that all of the following operations occur + // within thread-specific storage. + ACE_Log_Msg *new_log = ACE_LOG_MSG; + + // Note that we do not inherit the callback because this might have + // been allocated off of the stack of the original thread, in which + // case all hell would break loose... + + if (attributes.ostream_) + { + new_log->msg_ostream (attributes.ostream_); + new_log->priority_mask (attributes.priority_mask_); + + if (attributes.tracing_enabled_) + new_log->start_tracing (); + + new_log->restart (attributes.restart_); + new_log->trace_depth (attributes.trace_depth_); + } + + // @@ Now the TSS Log_Msg has been created, cache my thread + // descriptor in. + + if (thr_desc != 0) + // This downcast is safe. We do it to avoid having to #include + // ace/Thread_Manager.h. + new_log->thr_desc (static_cast<ACE_Thread_Descriptor *> (thr_desc)); + // Block the thread from proceeding until + // thread manager has thread descriptor ready. +#endif /* ! ACE_THREADS_DONT_INHERIT_LOG_MSG && ! ACE_HAS_MINIMAL_ACE_OS */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL |