// ____ ______ __ // / __ \ / ____// / // / /_/ // / / / // / ____// /___ / /___ PixInsight Class Library // /_/ \____//_____/ PCL 2.4.23 // ---------------------------------------------------------------------------- // pcl/Atomic.h - Released 2022-03-12T18:59:29Z // ---------------------------------------------------------------------------- // This file is part of the PixInsight Class Library (PCL). // PCL is a multiplatform C++ framework for development of PixInsight modules. // // Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved. // // Redistribution and use in both source and binary forms, with or without // modification, is permitted provided that the following conditions are met: // // 1. All redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. All redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names // of their contributors, may be used to endorse or promote products derived // from this software without specific prior written permission. For written // permission, please contact info@pixinsight.com. // // 4. All products derived from this software, in any form whatsoever, must // reproduce the following acknowledgment in the end-user documentation // and/or other materials provided with the product: // // "This product is based on software from the PixInsight project, developed // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)." // // Alternatively, if that is where third-party acknowledgments normally // appear, this acknowledgment must be reproduced in the product itself. // // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE, // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------------- #ifndef __PCL_Atomic_h #define __PCL_Atomic_h /// \file pcl/Atomic.h #include #ifdef __PCL_WINDOWS # include #ifdef _MSC_VER # pragma intrinsic (_InterlockedIncrement) # pragma intrinsic (_InterlockedDecrement) # pragma intrinsic (_InterlockedCompareExchange) # pragma intrinsic (_InterlockedExchange) # pragma intrinsic (_InterlockedExchangeAdd) #endif #endif namespace pcl { // ---------------------------------------------------------------------------- /*! * \class AtomicInt * \brief Atomic operations on integers. * * %AtomicInt allows non-blocking synchronization of multithreaded code with * respect to reference counting and other critical operations in parallel * algorithm implementations. This class is used extensively by PCL code to * implement copy-on-write shared containers and container operations in a * thread-safe way. An example is the ReferenceCounter class, which is at the * hearth of most PCL container and image classes. * * %AtomicInt implements the following synchronization primitives on integers: * * reference \n * dereference \n * test-and-set \n * fetch-and-store \n * fetch-and-add * * \sa ReferenceCounter */ class PCL_CLASS AtomicInt { public: /*! * Constructs an %AtomicInt instance with the specified \a value. When not * explicitly specified, the default value is zero. */ AtomicInt( int value = 0 ) : m_value( value ) { // ### N.B.: // The default zero initialization is *critical* - DO NOT change it. } /*! * Copy constructor. */ AtomicInt( const AtomicInt& ) = default; /*! * Copy assignment operator. Returns a reference to this object. */ AtomicInt& operator =( const AtomicInt& ) = default; /*! * Returns the current value of this atomic integer. * * \note This operation is not guaranteed to be atomic. */ operator int() const { return m_value; } /*! * Logical negation operator. Returns true iff this atomic integer is zero. * * \note This operation is not guaranteed to be atomic. */ bool operator !() const { return m_value == 0; } /*! * Equality operator. Returns true iff this atomic integer is equal to an * integer \a x. * * \note This operation is not guaranteed to be atomic. */ bool operator ==( int x ) const { return m_value == x; } /*! * Inequality operator. Returns true iff this atomic integer is not equal to * an integer \a x. * * \note This operation is not guaranteed to be atomic. */ bool operator !=( int x ) const { return m_value != x; } /*! * Integer assignment operator. Assigns the specified integer \a x to this * atomic integer. Returns a reference to this object. * * \note This operation is not guaranteed to be atomic. */ AtomicInt& operator =( int x ) { m_value = x; return *this; } /*! * Atomic load operation. * * Returns the current value of this atomic integer. * * \note The integer load operation is guaranteed to be atomic on all * supported platforms and architectures. */ int Load() { return FetchAndAdd( 0 ); } /*! * Atomic store operation. * * Assigns the specified \a newValue to this object. * * \note The integer store operation is guaranteed to be atomic on all * supported platforms and architectures. */ void Store( int newValue ) { (void)FetchAndStore( newValue ); } /*! * Atomic increment operation. * * Increments the value of this object as an atomic operation. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ void Increment() { #ifdef __PCL_WINDOWS (void)_InterlockedIncrement( &m_value ); #else asm volatile( "lock\n\t" "incl %0\n" : "=m" (m_value) : "m" (m_value) : "memory", "cc" ); #endif } /*! * Atomic decrement operation. * * Decrements the value of this object as an atomic operation. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ void Decrement() { #ifdef __PCL_WINDOWS (void)_InterlockedDecrement( &m_value ); #else asm volatile( "lock\n\t" "decl %0\n" : "=m" (m_value) : "m" (m_value) : "memory", "cc" ); #endif } /*! * Atomic reference operation. * * Increments the value of this object as an atomic operation. Returns true * if the resulting value after incrementing this object is nonzero. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ bool Reference() { #ifdef __PCL_WINDOWS return _InterlockedIncrement( &m_value ) != 0; #else uint8 result; asm volatile( "lock\n\t" "incl %0\n\t" "setnz %1\n" : "=m" (m_value), "=qm" (result) : "m" (m_value) : "memory", "cc" ); return result != 0; #endif } /*! * Atomic dereference operation. * * Decrements the value of this object as an atomic operation. Returns true * if the resulting value after decrementing this object is nonzero. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ bool Dereference() { #ifdef __PCL_WINDOWS return _InterlockedDecrement( &m_value ) != 0; #else uint8 result; asm volatile( "lock\n\t" "decl %0\n\t" "setnz %1\n" : "=m" (m_value), "=qm" (result) : "m" (m_value) : "memory", "cc" ); return result != 0; #endif } /*! * Atomic test-and-set operation. * * If the current value of this object is equal to \a expectedValue, this * function assigns \a newValue to this object and returns true. If the * current value is not equal to \a expectedValue, this function performs no * operation and returns false. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ bool TestAndSet( int expectedValue, int newValue ) { #ifdef __PCL_WINDOWS return _InterlockedCompareExchange( &m_value, newValue, expectedValue ) == expectedValue; #else uint8 result; asm volatile( "lock\n\t" "cmpxchgl %3,%2\n\t" "setz %1\n" : "=a" (newValue), "=qm" (result), "+m" (m_value) : "r" (newValue), "0" (expectedValue) : "memory", "cc" ); return result != 0; #endif } /*! * Atomic fetch-and-store operation. * * Assigns \a newValue to this object and returns the initial value before * assignment, as an atomic operation. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ int FetchAndStore( int newValue ) { #ifdef __PCL_WINDOWS return _InterlockedExchange( &m_value, newValue ); #else asm volatile( "xchgl %0,%1\n" : "=r" (newValue), "+m" (m_value) : "0" (newValue) : "memory" ); return newValue; #endif } /*! * Atomic fetch-and-add operation. Adds \a valueToAdd to this object and * returns the initial value before addition, as an atomic operation. * * \note This operation is guaranteed to be atomic on all supported * platforms and architectures. */ int FetchAndAdd( int valueToAdd ) { #ifdef __PCL_WINDOWS return _InterlockedExchangeAdd( &m_value, valueToAdd ); #else asm volatile( "lock\n\t" "xaddl %0,%1\n" : "=r" (valueToAdd), "+m" (m_value) : "0" (valueToAdd) : "memory", "cc" ); return valueToAdd; #endif } private: #ifdef _MSC_VER __declspec(align(4)) volatile long m_value; #elif __PCL_WINDOWS volatile long m_value __attribute__ ((aligned (4))); #else volatile int m_value __attribute__ ((aligned (4))); #endif }; // ---------------------------------------------------------------------------- /*! * \defgroup reentrancy_protection Thread-Safe Protection of Non-Reentrant Code */ // ---------------------------------------------------------------------------- /*! * \class AutoReentrancyGuard * \brief Automatic reentrancy guard sentinel. * * %AutoReentrancyGuard allows you to protect a block of code ensuring that it * cannot be reentrant. All you need is a static AtomicInt variable that works * as a 'busy state' flag persistent across function invocations. * * Consider the following example: * * \code void foo() * { * static AtomicInt flag; * AutoReentrancyGuard guard( flag ); * if ( guard ) * { * // protected code * } * } * \endcode * * The function \c foo is not reentrant, so we want to protect it against * possible reentrant invocations while the function's code is being executed. * * The \c flag variable is initially zero (because AtomicInt's default * constructor initializes its integer member to zero). The first time \c foo * is called, %AutoReentrancyGuard's constructor can change the value of * \c flag from zero to one as an atomic operation. When this happens, * AutoReentrancyGuard::operator bool() returns true, and the code protected * within the \c if block can be executed. * * When the \c guard object gets out of scope (just before the \c foo function * returns), its class destructor resets \c flag to zero automatically, which * permits the next non-reentrant execution of \c foo. However, if \c foo is * called again before \c guard is destroyed, a newly constructed * %AutoReentrancyGuard object cannot make a transition 0 -> 1 with the static * \c flag variable, and hence a reentrant execution of the protected code is * not allowed (in this case, the function simply does nothing and returns * after the \c if block). Note that the protected code can freely return from * the function or throw exceptions; the \c flag variable will be reset to zero * automatically when \c guard gets out of scope. * * Since %AutoReentrancyGuard uses AtomicInt to implement atomic transitions, * code blocks can be protected against reentrant execution in multithreaded * environments. * * The macros PCL_REENTRANCY_GUARDED_BEGIN and PCL_REENTRANCY_GUARDED_END * greatly simplify reentrancy protection. For example, the above code could be * implemented as follows: * * \code void foo() * { * PCL_REENTRANCY_GUARDED_BEGIN * // protected code * PCL_REENTRANCY_GUARDED_END * } \endcode * * In addition, the macros PCL_CLASS_REENTRANCY_GUARD and * PCL_CLASS_REENTRANCY_GUARDED_BEGIN are useful for protection of all * non-reentrant member functions of a class, and the macros * PCL_MEMBER_REENTRANCY_GUARD and PCL_MEMBER_REENTRANCY_GUARDED_BEGIN provide * protection of specific member functions. See these macros for examples. * * \ingroup reentrancy_protection */ class AutoReentrancyGuard { public: /*! * Constructs an %AutoReentrancyGuard object to monitor the specified * \a guard variable. If \c guard is zero, its value is set to one as an * atomic operation. If \c guard is nonzero, its value is not changed. * * \warning The monitored guard variable *must* be either a static variable * local to the function being protected, or a data member of the same class * to which a protected member function belongs. Otherwise the protection * mechanism will not work. This can be dangerous, especially because you * may erroneously think that your code is being protected when it is not. * In addition, the guard variable must be zero initially, or the protected * code will never be allowed to work. We strongly recommend you don't use * this class directly, but the PCL_REENTRANCY_GUARDED_BEGIN and * PCL_REENTRANCY_GUARDED_END macros to implement function level protection, * or PCL_CLASS_REENTRANCY_GUARD, PCL_CLASS_REENTRANCY_GUARDED_BEGIN and * PCL_CLASS_REENTRANCY_GUARDED_END to implement per-instance function * member protection. */ AutoReentrancyGuard( AtomicInt& guard ) : m_guard( guard ) { m_guarded = m_guard.TestAndSet( 0, 1 ); } /*! * Destroys this object. If the value of the monitored guard variable (see * the class constructor) was zero when this object was constructed, its * value is reset to zero as an atomic operation. */ ~AutoReentrancyGuard() { if ( m_guarded ) m_guard.Store( 0 ); } /*! * Returns true iff the value of the monitored guard variable (see the class * constructor) was zero when this object was constructed. */ operator bool() const volatile { return m_guarded; } private: AtomicInt& m_guard; bool m_guarded = false; }; /*! * \def PCL_REENTRANCY_GUARDED_BEGIN * * This macro along with PCL_REENTRANCY_GUARDED_END simplifies protection of * non-reentrant code. See the AutoReentrancyGuard class for detailed * information and examples. * * \ingroup reentrancy_protection */ #define PCL_REENTRANCY_GUARDED_BEGIN \ { \ static pcl::AtomicInt __r_g__( 0 ); \ volatile pcl::AutoReentrancyGuard __a_r_g__( __r_g__ ); \ if ( __a_r_g__ ) \ { /*! * \def PCL_REENTRANCY_GUARDED_END * * This macro, along with PCL_REENTRANCY_GUARDED_BEGIN, simplifies protection * of non-reentrant code. See the AutoReentrancyGuard class for detailed * information and examples. * * \ingroup reentrancy_protection */ #define PCL_REENTRANCY_GUARDED_END \ } \ } /*! * \def PCL_CLASS_REENTRANCY_GUARD * * Declares a class data member for class-wide protection of non-reentrant * member functions with the PCL_CLASS_REENTRANCY_GUARDED_BEGIN and * PCL_REENTRANCY_GUARDED_END macros. * * Example: * * \code class foo * { * public: * // ... * private: * PCL_CLASS_REENTRANCY_GUARD * * void bar1() * { * PCL_CLASS_REENTRANCY_GUARDED_BEGIN * // Protected code * PCL_REENTRANCY_GUARDED_END * } * * void bar2() const * { * PCL_CLASS_REENTRANCY_GUARDED_BEGIN * // Protected code * PCL_REENTRANCY_GUARDED_END * } * }; \endcode * * In this example the bar1 and bar2 member functions are protected against * reentrant execution. Note that reentrancy protection is a per-instance, * class-wide property in this case: the bar1() and bar2() functions can be * executed simultaneously for different objects, but they cannot be re-entered * for the same instance. Furthermore, one of these functions cannot call the * other for the same object, since both share the same reentrancy guard member * in the foo class. * * See the AutoReentrancyGuard class for more information on the PCL * implementation of reentrancy protection. * * \ingroup reentrancy_protection */ #define PCL_CLASS_REENTRANCY_GUARD \ mutable pcl::AtomicInt __pcl_guard__; /*! * \def PCL_CLASS_REENTRANCY_GUARDED_BEGIN * * This macro, along with PCL_CLASS_REENTRANCY_GUARD and * PCL_REENTRANCY_GUARDED_END, simplifies per-instance protection of * non-reentrant class member functions. See PCL_CLASS_REENTRANCY_GUARD for an * example. * * See the AutoReentrancyGuard class for more information on the PCL * implementation of reentrancy protection. * * \ingroup reentrancy_protection */ #define PCL_CLASS_REENTRANCY_GUARDED_BEGIN \ { \ volatile pcl::AutoReentrancyGuard __a_r_g__( __pcl_guard__ ); \ if ( __a_r_g__ ) \ { /*! * \def PCL_MEMBER_REENTRANCY_GUARD * * Declares a class data member for protection of a specific non-reentrant * member function with the PCL_MEMBER_REENTRANCY_GUARDED_BEGIN and * PCL_REENTRANCY_GUARDED_END macros. * * Example: * * \code class foo * { * public: * // ... * private: * PCL_MEMBER_REENTRANCY_GUARD( bar1 ) * PCL_MEMBER_REENTRANCY_GUARD( bar2 ) * * void bar1() * { * PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( bar1 ) * // Protected code * PCL_REENTRANCY_GUARDED_END * } * * void bar2() const * { * PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( bar2 ) * // Protected code * PCL_REENTRANCY_GUARDED_END * } * }; \endcode * * In this example the bar1 and bar2 member functions are protected against * reentrant execution. Note that reentrancy protection is a per-instance, * function-specific property in this case: the bar1() and bar2() functions can * be executed simultaneously for different objects, but they cannot be * re-entered for the same instance. Since each member function uses its own * reentrancy guard member in the foo class, each of them can safely call the * other for the same object. * * See the AutoReentrancyGuard class for more information on the PCL * implementation of reentrancy protection. * * \ingroup reentrancy_protection */ #define PCL_MEMBER_REENTRANCY_GUARD( member ) \ mutable pcl::AtomicInt __pcl_guard_##member##__; /*! * \def PCL_MEMBER_REENTRANCY_GUARDED_BEGIN * * This macro, along with PCL_MEMBER_REENTRANCY_GUARD and * PCL_REENTRANCY_GUARDED_END, simplifies per-instance protection of specific * non-reentrant member functions. See PCL_MEMBER_REENTRANCY_GUARD for an * example. * * See the AutoReentrancyGuard class for more information on the PCL * implementation of reentrancy protection. * * \ingroup reentrancy_protection */ #define PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( member ) \ { \ volatile pcl::AutoReentrancyGuard __a_r_g__( __pcl_guard_##member##__ );\ if ( __a_r_g__ ) \ { // ---------------------------------------------------------------------------- } // pcl #endif // __PCL_Atomic_h // ---------------------------------------------------------------------------- // EOF pcl/Atomic.h - Released 2022-03-12T18:59:29Z