Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:50

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2022-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file corecel/sys/ScopedSignalHandler.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <initializer_list>
0011 #include <utility>
0012 #include <vector>
0013 
0014 namespace celeritas
0015 {
0016 //---------------------------------------------------------------------------//
0017 /*!
0018  * Catch the given signal type within the scope of the handler.
0019  *
0020  * On instantiation with a non-empty argument, this class registers a signal
0021  * handler for the given signal. A class instance is true if and only if the
0022  * class is handling a signal. The instance's "call" operator will check and
0023  * return whether the assigned signal has been caught. The move-assign operator
0024  * can be used to unregister the handle.
0025  *
0026  * When the class exits scope, the signal for the active type will be cleared.
0027  *
0028  * Signal handling can be disabled by setting the environment variable \c
0029  * CELER_DISABLE_SIGNALS to a
0030  * non-empty value, but hopefully this will not be necessary because signal
0031  * handling should be used sparingly.
0032  *
0033  * \code
0034    #include <csignal>
0035 
0036    int main()
0037    {
0038       ScopedSignalHandler interrupted(SIGINT);
0039 
0040       while (true)
0041       {
0042           if (interrupted())
0043           {
0044               CELER_LOG(error) << "Interrupted";
0045               break;
0046           }
0047 
0048           if (stop_handling_for_whatever_reason())
0049           {
0050               // Clear handler
0051               interrupted = {};
0052           }
0053       }
0054       return interrupted() ? 1 : 0;
0055    }
0056    \endcode
0057  */
0058 class ScopedSignalHandler
0059 {
0060   public:
0061     //!@{
0062     //! \name Type aliases
0063     using signal_type = int;
0064     //!@}
0065 
0066   public:
0067     // Whether signals are enabled
0068     static bool allow_signals();
0069 
0070     // Raise a signal visible only to ScopedSignalHandler (for testing)
0071     static int raise(signal_type sig);
0072 
0073     //! Default to not handling any signals.
0074     ScopedSignalHandler() = default;
0075 
0076     // Handle the given signal type, asserting if it's already been raised
0077     explicit ScopedSignalHandler(signal_type);
0078 
0079     // Handle the given signal types
0080     explicit ScopedSignalHandler(std::initializer_list<signal_type>);
0081 
0082     // Release the given signal
0083     ~ScopedSignalHandler();
0084 
0085     // Check if signal was intercepted
0086     inline bool operator()() const;
0087 
0088     //! True if handling a signal
0089     explicit operator bool() const { return mask_ != 0; }
0090 
0091     // Move construct and assign to capture/release signal handling
0092     ScopedSignalHandler(ScopedSignalHandler const&) = delete;
0093     ScopedSignalHandler& operator=(ScopedSignalHandler const&) = delete;
0094     ScopedSignalHandler(ScopedSignalHandler&&) noexcept;
0095     ScopedSignalHandler& operator=(ScopedSignalHandler&&) noexcept;
0096     void swap(ScopedSignalHandler& other) noexcept;
0097 
0098   private:
0099     using HandlerPtr = void (*)(int);
0100     using PairSigHandle = std::pair<signal_type, HandlerPtr>;
0101     using VecSH = std::vector<PairSigHandle>;
0102 
0103     signal_type mask_{0};
0104     VecSH handles_;
0105 
0106     bool check_signal() const;
0107 };
0108 
0109 //---------------------------------------------------------------------------//
0110 // INLINE DEFINITIONS
0111 //---------------------------------------------------------------------------//
0112 /*!
0113  * Return whether a signal was intercepted.
0114  */
0115 bool ScopedSignalHandler::operator()() const
0116 {
0117     return *this && this->check_signal();
0118 }
0119 
0120 //---------------------------------------------------------------------------//
0121 }  // namespace celeritas