#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" #include "ace/Guard_T.h" #if !defined (__ACE_INLINE__) #include "ace/Sig_Handler.inl" #endif /* __ACE_INLINE__ */ #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) 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) #else #define ace_signal_handler_dispatcher reinterpret_cast (reinterpret_cast ((ACE_Sig_Handler_Ex)ACE_Sig_Handler::dispatch)) #define ace_signal_handlers_dispatcher reinterpret_cast (reinterpret_cast ((ACE_Sig_Handler_Ex)ACE_Sig_Handlers::dispatch)) #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 () { for (int s = 1; s < ACE_NSIG; ++s) if (ACE_Sig_Handler::signal_handlers_[s]) ACE_Sig_Handler::remove_handler_i (s); } void ACE_Sig_Handler::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Sig_Handler::dump"); #endif /* ACE_HAS_DUMP */ } int ACE_Sig_Handler::sig_pending () { ACE_TRACE ("ACE_Sig_Handler::sig_pending"); ACE_MT (ACE_Recursive_Thread_Mutex *lock = ACE_Managed_Object::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, 0)); 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::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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, 0)); 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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, 0)); 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_Event_Handler if the user // asks for this. if (old_sh != 0) *old_sh = sh; // Make sure that @a 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); new_disp->flags (new_disp->flags () | SA_SIGINFO); 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., . 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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); return ACE_Sig_Handler::register_handler_i (signum, new_sh, new_disp, old_sh, old_disp); } int ACE_Sig_Handler::remove_handler_i (int signum, ACE_Sig_Action *new_disp, ACE_Sig_Action *old_disp, int) { ACE_TRACE ("ACE_Sig_Handler::remove_handler_i"); ACE_Sig_Action sa (SIG_DFL, (sigset_t *) 0); // Reset to default disposition. if (new_disp == 0) new_disp = &sa; ACE_Event_Handler *eh = ACE_Sig_Handler::signal_handlers_[signum]; ACE_Sig_Handler::signal_handlers_[signum] = 0; // Allow the event handler to close down if necessary. if (eh) { eh->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::SIGNAL_MASK); } // Register either the new disposition or restore the default. return new_disp->register_action (signum, 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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); if (ACE_Sig_Handler::in_range (signum)) return ACE_Sig_Handler::remove_handler_i (signum, new_disp, 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 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) ACE_Sig_Handler::remove_handler_i (signum); #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 with // 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... #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 /// method. int ACE_Sig_Handlers::sigkey_ = 0; /// If this is true then a 3rd party library has registered a /// handler... bool ACE_Sig_Handlers::third_party_sig_handler_ = false; // Make life easier by defining typedefs... using ACE_SIG_HANDLERS_SET = ACE_Fixed_Set; using ACE_SIG_HANDLERS_ITERATOR = ACE_Fixed_Set_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) ACE_Sig_Handlers::ACE_Sig_Handlers () { } void ACE_Sig_Handlers::dump () 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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); if (ACE_Sig_Handler::in_range (signum)) { ACE_Sig_Adapter *ace_sig_adapter = nullptr; // Our signal handler. ACE_Sig_Adapter *extern_sh = nullptr; // 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_ = true; // 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). int const result = ACE_Sig_Handlers_Set::instance (signum)->insert (ace_sig_adapter); if (result == -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 @a signum. /// Install the new disposition (if given) and return the previous /// disposition (if desired by the caller). Returns 0 on success and // -1 if @a 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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); 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; ) { // 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., == -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::get_preallocated_object (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); ACE_TSS_Guard 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; ) 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 = nullptr; // 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 = nullptr; ACE_NEW_RETURN (temp, ACE_Sig_Adapter (new_sh, ++ACE_Sig_Handlers::sigkey_), nullptr); handler_set->insert (temp); return *eh; } ACE_END_VERSIONED_NAMESPACE_DECL