Files
tenmon/3rdparty/include/pcl/Atomic.h
T
2022-04-12 08:17:18 +02:00

671 lines
21 KiB
C++

// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ 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 <pcl/Defs.h>
#ifdef __PCL_WINDOWS
# include <intrin.h>
#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