diff options
author | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:30 +0000 |
---|---|---|
committer | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:30 +0000 |
commit | 7a52d43a162b23d9e85e7b955e9b2c8e9caf550e (patch) | |
tree | 66a84b20d47f2269d8bdc6e0323f338763424d3a /ACE/ace/Sig_Handler.cpp | |
parent | 0e49389337be86641451a5c36c24bf742fe97523 (diff) | |
download | ATCD-7a52d43a162b23d9e85e7b955e9b2c8e9caf550e.tar.gz |
Repo restructuring
Diffstat (limited to 'ACE/ace/Sig_Handler.cpp')
-rw-r--r-- | ACE/ace/Sig_Handler.cpp | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/ACE/ace/Sig_Handler.cpp b/ACE/ace/Sig_Handler.cpp new file mode 100644 index 00000000000..c66a43c7517 --- /dev/null +++ b/ACE/ace/Sig_Handler.cpp @@ -0,0 +1,620 @@ +// $Id$ + +#include "ace/Sig_Handler.h" +#include "ace/Sig_Adapter.h" +#include "ace/Signal.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Managed_Object.h" +#include "ace/Containers.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Sig_Handler.inl" +#endif /* __ACE_INLINE__ */ + +ACE_RCSID(ace, Sig_Handler, "$Id$") + +#if defined (ACE_HAS_SIG_C_FUNC) + +extern "C" void +ace_sig_handler_dispatch (int signum, siginfo_t *info, ucontext_t *context) +{ + ACE_TRACE ("ace_sig_handler_dispatch"); + ACE_Sig_Handler::dispatch (signum, info, context); +} + +#define ace_signal_handler_dispatcher ACE_SignalHandler(ace_sig_handler_dispatch) + +#if !defined (ACE_HAS_BROKEN_HPUX_TEMPLATES) +extern "C" void +ace_sig_handlers_dispatch (int signum, siginfo_t *info, ucontext_t *context) +{ + ACE_TRACE ("ace_sig_handlers_dispatch"); + ACE_Sig_Handlers::dispatch (signum, info, context); +} + +#define ace_signal_handlers_dispatcher ACE_SignalHandler(ace_sig_handlers_dispatch) +#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */ + +#else +#define ace_signal_handler_dispatcher ACE_SignalHandler(ACE_Sig_Handler::dispatch) + +#if !defined (ACE_HAS_BROKEN_HPUX_TEMPLATES) +#define ace_signal_handlers_dispatcher ACE_SignalHandler(ACE_Sig_Handlers::dispatch) +#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */ +#endif /* ACE_HAS_SIG_C_FUNC */ + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Array of Event_Handlers that will handle the signals. +ACE_Event_Handler *ACE_Sig_Handler::signal_handlers_[ACE_NSIG]; + +// Remembers if a signal has occurred. +sig_atomic_t ACE_Sig_Handler::sig_pending_ = 0; + + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Handler) + +ACE_Sig_Handler::~ACE_Sig_Handler (void) +{ +} + +void +ACE_Sig_Handler::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Handler::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Sig_Handler::sig_pending (void) +{ + ACE_TRACE ("ACE_Sig_Handler::sig_pending"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + return ACE_Sig_Handler::sig_pending_ != 0; +} + +void +ACE_Sig_Handler::sig_pending (int pending) +{ + ACE_TRACE ("ACE_Sig_Handler::sig_pending"); + + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + ACE_Sig_Handler::sig_pending_ = pending; +} + +ACE_Event_Handler * +ACE_Sig_Handler::handler (int signum) +{ + ACE_TRACE ("ACE_Sig_Handler::handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + + if (ACE_Sig_Handler::in_range (signum)) + return ACE_Sig_Handler::signal_handlers_[signum]; + else + return 0; +} + +ACE_Event_Handler * +ACE_Sig_Handler::handler_i (int signum, + ACE_Event_Handler *new_sh) +{ + ACE_TRACE ("ACE_Sig_Handler::handler_i"); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Event_Handler *sh = ACE_Sig_Handler::signal_handlers_[signum]; + + ACE_Sig_Handler::signal_handlers_[signum] = new_sh; + return sh; + } + else + return 0; +} + +ACE_Event_Handler * +ACE_Sig_Handler::handler (int signum, + ACE_Event_Handler *new_sh) +{ + ACE_TRACE ("ACE_Sig_Handler::handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + + return ACE_Sig_Handler::handler_i (signum, new_sh); +} + +// Register an ACE_Event_Handler along with the corresponding SIGNUM. +// This method does NOT acquire any locks, so it can be called from a +// signal handler. + +int +ACE_Sig_Handler::register_handler_i (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **old_sh, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Sig_Handler::register_handler_i"); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Sig_Action sa; // Define a "null" action. + ACE_Event_Handler *sh = ACE_Sig_Handler::handler_i (signum, + new_sh); + + // Return a pointer to the old <ACE_Sig_Handler> if the user + // asks for this. + if (old_sh != 0) + *old_sh = sh; + + // Make sure that <new_disp> points to a valid location if the + // user doesn't care... + if (new_disp == 0) + new_disp = &sa; + + new_disp->handler (ace_signal_handler_dispatcher); +#if !defined (ACE_HAS_LYNXOS_SIGNALS) + new_disp->flags (new_disp->flags () | SA_SIGINFO); +#endif /* ACE_HAS_LYNXOS_SIGNALS */ + return new_disp->register_action (signum, old_disp); + } + else + return -1; +} + +// Register an ACE_Event_Handler along with the corresponding SIGNUM. +// This method acquires a lock, so it can't be called from a signal +// handler, e.g., <dispatch>. + +int +ACE_Sig_Handler::register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **old_sh, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Sig_Handler::register_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + + return ACE_Sig_Handler::register_handler_i (signum, + new_sh, + new_disp, + old_sh, + old_disp); +} + +// Remove an ACE_Event_Handler. + +int +ACE_Sig_Handler::remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int) +{ + ACE_TRACE ("ACE_Sig_Handler::remove_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Sig_Action sa (SIG_DFL, (sigset_t *) 0); // Define the default disposition. + + if (new_disp == 0) + new_disp = &sa; + + ACE_Sig_Handler::signal_handlers_[signum] = 0; + + // Register either the new disposition or restore the default. + return new_disp->register_action (signum, old_disp); + } + + return -1; +} + +// Master dispatcher function that gets called by a signal handler and +// dispatches one handler... + +void +ACE_Sig_Handler::dispatch (int signum, + siginfo_t *siginfo, + ucontext_t *ucontext) +{ + ACE_TRACE ("ACE_Sig_Handler::dispatch"); + + // Save/restore errno. + ACE_Errno_Guard error (errno); + + // We can't use the <sig_pending> call here because that acquires + // the lock, which is non-portable... + ACE_Sig_Handler::sig_pending_ = 1; + + // Darn well better be in range since the OS dispatched this... + ACE_ASSERT (ACE_Sig_Handler::in_range (signum)); + + ACE_Event_Handler *eh = ACE_Sig_Handler::signal_handlers_[signum]; + + if (eh != 0) + { + if (eh->handle_signal (signum, siginfo, ucontext) == -1) + { + // Define the default disposition. + ACE_Sig_Action sa ((ACE_SignalHandler) SIG_DFL, (sigset_t *) 0); + + ACE_Sig_Handler::signal_handlers_[signum] = 0; + + // Remove the current disposition by registering the default + // disposition. + sa.register_action (signum); + + // Allow the event handler to close down if necessary. + eh->handle_close (ACE_INVALID_HANDLE, + ACE_Event_Handler::SIGNAL_MASK); + } +#if defined (ACE_WIN32) + else + // Win32 is weird in the sense that it resets the signal + // disposition to SIG_DFL after a signal handler is + // dispatched. Therefore, to workaround this "feature" we + // must re-register the <ACE_Event_Handler> with <signum> + // explicitly. + ACE_Sig_Handler::register_handler_i (signum, + eh); +#endif /* ACE_WIN32*/ + } +} + +// ---------------------------------------- +// The following classes are local to this file. + +// There are bugs with HP/UX's C++ compiler that prevents this stuff +// from compiling... +#if !defined (ACE_HAS_BROKEN_HPUX_TEMPLATES) +#define ACE_MAX_SIGNAL_HANDLERS ((size_t) 20) + +// Keeps track of the id that uniquely identifies each registered +// signal handler. This id can be used to cancel a timer via the +// <remove_handler> method. +int ACE_Sig_Handlers::sigkey_ = 0; + +// If this is > 0 then a 3rd party library has registered a +// handler... +int ACE_Sig_Handlers::third_party_sig_handler_ = 0; + +// Make life easier by defining typedefs... +typedef ACE_Fixed_Set <ACE_Event_Handler *, ACE_MAX_SIGNAL_HANDLERS> ACE_SIG_HANDLERS_SET; +typedef ACE_Fixed_Set_Iterator <ACE_Event_Handler *, ACE_MAX_SIGNAL_HANDLERS> ACE_SIG_HANDLERS_ITERATOR; + +class ACE_Sig_Handlers_Set +{ +public: + static ACE_SIG_HANDLERS_SET *instance (int signum); + +private: + static ACE_SIG_HANDLERS_SET *sig_handlers_[ACE_NSIG]; +}; + +/* static */ +ACE_SIG_HANDLERS_SET *ACE_Sig_Handlers_Set::sig_handlers_[ACE_NSIG]; + +/* static */ +ACE_SIG_HANDLERS_SET * +ACE_Sig_Handlers_Set::instance (int signum) +{ + if (signum <= 0 || signum >= ACE_NSIG) + return 0; // This will cause problems... + else if (ACE_Sig_Handlers_Set::sig_handlers_[signum] == 0) + ACE_NEW_RETURN (ACE_Sig_Handlers_Set::sig_handlers_[signum], + ACE_SIG_HANDLERS_SET, + 0); + return ACE_Sig_Handlers_Set::sig_handlers_[signum]; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Handlers) + +void +ACE_Sig_Handlers::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Handlers::dump"); +#endif /* ACE_HAS_DUMP */ +} + +// This is the method that does all the dirty work... The basic +// structure of this method was devised by Detlef Becker. + +int +ACE_Sig_Handlers::register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Sig_Handlers::register_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Sig_Adapter *ace_sig_adapter = 0; // Our signal handler. + ACE_Sig_Adapter *extern_sh = 0; // An external signal handler. + ACE_Sig_Action sa; + + // Get current signal disposition. + sa.retrieve_action (signum); + + // Check whether we are already in control of the signal + // handling disposition... + + if (!(sa.handler () == ace_signal_handlers_dispatcher + || sa.handler () == ACE_SignalHandler (SIG_IGN) + || sa.handler () == ACE_SignalHandler (SIG_DFL))) + { + // Drat, a 3rd party library has already installed a signal ;-( + + // Upto here we never disabled RESTART_MODE. Thus, + // RESTART_MODE can only be changed by 3rd party libraries. + + if (ACE_BIT_DISABLED (sa.flags (), SA_RESTART) + && ACE_Sig_Handlers::third_party_sig_handler_) + // Toggling is disallowed since we might break 3rd party + // code. + return -1; + + // Note that we've seen a 3rd party handler... + ACE_Sig_Handlers::third_party_sig_handler_ = 1; + + // Create a new 3rd party disposition, remembering its + // preferred signal blocking etc...; + ACE_NEW_RETURN (extern_sh, + ACE_Sig_Adapter (sa, + ++ACE_Sig_Handlers::sigkey_), + -1); + // Add the external signal handler to the set of handlers + // for this signal. + if (ACE_Sig_Handlers_Set::instance (signum)->insert (extern_sh) == -1) + { + delete extern_sh; + return -1; + } + } + // Add our new handler at this point. + ACE_NEW_RETURN (ace_sig_adapter, + ACE_Sig_Adapter (new_sh, + ++ACE_Sig_Handlers::sigkey_), + -1); + // Add the ACE signal handler to the set of handlers for this + // signal (make sure it goes before the external one if there is + // one of these). + if (ACE_Sig_Handlers_Set::instance (signum)->insert (ace_sig_adapter) == -1) + { + // We couldn't reinstall our handler, so let's pretend like + // none of this happened... + if (extern_sh) + { + ACE_Sig_Handlers_Set::instance (signum)->remove (extern_sh); + delete extern_sh; + } + delete ace_sig_adapter; + return -1; + } + // If ACE_Sig_Handlers::dispatch() was set we're done. + else if (sa.handler () == ace_signal_handlers_dispatcher) + return ace_sig_adapter->sigkey (); + + // Otherwise, we need to register our handler function so that + // all signals will be dispatched through ACE. + else + { + // Make sure that new_disp points to a valid location if the + // user doesn't care... + if (new_disp == 0) + new_disp = &sa; + + new_disp->handler (ace_signal_handlers_dispatcher); + + // Default is to restart signal handlers. + new_disp->flags (new_disp->flags () | SA_RESTART); + new_disp->flags (new_disp->flags () | SA_SIGINFO); + + // Finally install (possibly reinstall) the ACE signal + // handler disposition with the SA_RESTART mode enabled. + if (new_disp->register_action (signum, old_disp) == -1) + { + // Yikes, lots of roll back at this point... + ACE_Sig_Handlers_Set::instance (signum)->remove (ace_sig_adapter); + delete ace_sig_adapter; + + if (extern_sh) + { + ACE_Sig_Handlers_Set::instance (signum)->remove (extern_sh); + delete extern_sh; + } + return -1; + } + else // Return the signal key so that programs can cancel this + // handler if they want! + return ace_sig_adapter->sigkey (); + } + } + + return -1; +} + +// Remove the ACE_Event_Handler currently associated with <signum>. +// Install the new disposition (if given) and return the previous +// disposition (if desired by the caller). Returns 0 on success and +// -1 if <signum> is invalid. + +int +ACE_Sig_Handlers::remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int sigkey) +{ + ACE_TRACE ("ACE_Sig_Handlers::remove_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + + // Iterate through the set of handlers for this signal. + + for (ACE_Event_Handler **eh; + handler_iterator.next (eh) != 0; + handler_iterator.advance ()) + { + // Type-safe downcast would be nice here... + ACE_Sig_Adapter *sh = (ACE_Sig_Adapter *) *eh; + + // Remove the handler if (1) its key matches the key we've + // been told to remove or (2) if we've been told to remove + // *all* handlers (i.e., <sigkey> == -1). + + if (sh->sigkey () == sigkey || sigkey == -1) + { + handler_set->remove (*eh); + delete *eh; + } + } + + if (handler_set->size () == 0) + { + // If there are no more handlers left for a signal then + // register the new disposition or restore the default + // disposition. + + ACE_Sig_Action sa (SIG_DFL, (sigset_t *) 0); + + if (new_disp == 0) + new_disp = &sa; + + return new_disp->register_action (signum, old_disp); + } + return 0; + } + else + return -1; +} + +// Master dispatcher function that gets called by a signal handler and +// dispatches *all* the handlers... + +void +ACE_Sig_Handlers::dispatch (int signum, + siginfo_t *siginfo, + ucontext_t *ucontext) +{ + ACE_TRACE ("ACE_Sig_Handlers::dispatch"); + // The following is #ifdef'd out because it's entirely non-portable + // to acquire a mutex in a signal handler... +#if 0 + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_TSS_Guard<ACE_Recursive_Thread_Mutex> m (*lock)); +#endif /* 0 */ + + // Save/restore errno. + ACE_Errno_Guard error (errno); + + ACE_Sig_Handler::sig_pending_ = 1; + + // Darn well better be in range since the OS dispatched this... + ACE_ASSERT (ACE_Sig_Handler::in_range (signum)); + + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + + for (ACE_Event_Handler **eh = 0; + handler_iterator.next (eh) != 0; + handler_iterator.advance ()) + { + if ((*eh)->handle_signal (signum, siginfo, ucontext) == -1) + { + handler_set->remove (*eh); + delete *eh; + } + } +} + +// Return the first item in the list of handlers. Note that this will +// trivially provide the same behavior as the ACE_Sig_Handler +// version if there is only 1 handler registered! + +ACE_Event_Handler * +ACE_Sig_Handlers::handler (int signum) +{ + ACE_TRACE ("ACE_Sig_Handlers::handler"); + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + ACE_Event_Handler **eh = 0; + handler_iterator.next (eh); + return *eh; +} + +// The following is a strange bit of logic that tries to give the same +// semantics as what happens in ACE_Sig_Handler when we replace the +// current signal handler with a new one. Note that if there is only +// one signal handler the behavior will be identical. If there is +// more than one handler then things get weird... + +ACE_Event_Handler * +ACE_Sig_Handlers::handler (int signum, ACE_Event_Handler *new_sh) +{ + ACE_TRACE ("ACE_Sig_Handlers::handler"); + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + ACE_Event_Handler **eh = 0; + + // Find the first handler... + handler_iterator.next (eh); + + // ... then remove it from the set ... + handler_set->remove (*eh); + + // ... and then insert the new signal handler into the beginning of + // the set (note, this is a bit too tied up in the implementation of + // ACE_Unbounded_Set...). + ACE_Sig_Adapter *temp; + + ACE_NEW_RETURN (temp, + ACE_Sig_Adapter (new_sh, + ++ACE_Sig_Handlers::sigkey_), + 0); + handler_set->insert (temp); + return *eh; +} + +#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */ + +ACE_END_VERSIONED_NAMESPACE_DECL |