PCL
Atomic.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/Atomic.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_Atomic_h
53 #define __PCL_Atomic_h
54 
56 
57 #include <pcl/Defs.h>
58 
59 #ifdef __PCL_WINDOWS
60 # include <intrin.h>
61 # pragma intrinsic (_InterlockedIncrement)
62 # pragma intrinsic (_InterlockedDecrement)
63 # pragma intrinsic (_InterlockedCompareExchange)
64 # pragma intrinsic (_InterlockedExchange)
65 # pragma intrinsic (_InterlockedExchangeAdd)
66 #endif
67 
68 namespace pcl
69 {
70 
71 // ----------------------------------------------------------------------------
72 
94 class PCL_CLASS AtomicInt
95 {
96 public:
97 
102  AtomicInt( int value = 0 )
103  : m_value( value )
104  {
105  // ### N.B.:
106  // The default zero initialization is *critical* - DO NOT change it.
107  }
108 
112  AtomicInt( const AtomicInt& ) = default;
113 
117  AtomicInt& operator =( const AtomicInt& ) = default;
118 
124  operator int() const
125  {
126  return m_value;
127  }
128 
134  bool operator !() const
135  {
136  return m_value == 0;
137  }
138 
145  bool operator ==( int x ) const
146  {
147  return m_value == x;
148  }
149 
156  bool operator !=( int x ) const
157  {
158  return m_value != x;
159  }
160 
167  AtomicInt& operator =( int x )
168  {
169  m_value = x;
170  return *this;
171  }
172 
181  int Load()
182  {
183  return FetchAndAdd( 0 );
184  }
185 
194  void Store( int newValue )
195  {
196  (void)FetchAndStore( newValue );
197  }
198 
207  void Increment()
208  {
209 #ifdef __PCL_WINDOWS
210  (void)_InterlockedIncrement( &m_value );
211 #else
212  asm volatile( "lock\n\t"
213  "incl %0\n"
214  : "=m" (m_value)
215  : "m" (m_value)
216  : "memory", "cc" );
217 #endif
218  }
219 
228  void Decrement()
229  {
230 #ifdef __PCL_WINDOWS
231  (void)_InterlockedDecrement( &m_value );
232 #else
233  asm volatile( "lock\n\t"
234  "decl %0\n"
235  : "=m" (m_value)
236  : "m" (m_value)
237  : "memory", "cc" );
238 #endif
239  }
240 
250  bool Reference()
251  {
252 #ifdef __PCL_WINDOWS
253  return _InterlockedIncrement( &m_value ) != 0;
254 #else
255  uint8 result;
256  asm volatile( "lock\n\t"
257  "incl %0\n\t"
258  "setnz %1\n"
259  : "=m" (m_value), "=qm" (result)
260  : "m" (m_value)
261  : "memory", "cc" );
262  return result != 0;
263 #endif
264  }
265 
275  bool Dereference()
276  {
277 #ifdef __PCL_WINDOWS
278  return _InterlockedDecrement( &m_value ) != 0;
279 #else
280  uint8 result;
281  asm volatile( "lock\n\t"
282  "decl %0\n\t"
283  "setnz %1\n"
284  : "=m" (m_value), "=qm" (result)
285  : "m" (m_value)
286  : "memory", "cc" );
287  return result != 0;
288 #endif
289  }
290 
302  bool TestAndSet( int expectedValue, int newValue )
303  {
304 #ifdef __PCL_WINDOWS
305  return _InterlockedCompareExchange( &m_value, newValue, expectedValue ) == expectedValue;
306 #else
307  uint8 result;
308  asm volatile( "lock\n\t"
309  "cmpxchgl %3,%2\n\t"
310  "setz %1\n"
311  : "=a" (newValue), "=qm" (result), "+m" (m_value)
312  : "r" (newValue), "0" (expectedValue)
313  : "memory", "cc" );
314  return result != 0;
315 #endif
316  }
317 
327  int FetchAndStore( int newValue )
328  {
329 #ifdef __PCL_WINDOWS
330  return _InterlockedExchange( &m_value, newValue );
331 #else
332  asm volatile( "xchgl %0,%1\n"
333  : "=r" (newValue), "+m" (m_value)
334  : "0" (newValue)
335  : "memory" );
336  return newValue;
337 #endif
338  }
339 
347  int FetchAndAdd( int valueToAdd )
348  {
349 #ifdef __PCL_WINDOWS
350  return _InterlockedExchangeAdd( &m_value, valueToAdd );
351 #else
352  asm volatile( "lock\n\t"
353  "xaddl %0,%1\n"
354  : "=r" (valueToAdd), "+m" (m_value)
355  : "0" (valueToAdd)
356  : "memory", "cc" );
357  return valueToAdd;
358 #endif
359  }
360 
361 private:
362 
363 #ifdef _MSC_VER
364  __declspec(align(4)) volatile long m_value;
365 #else
366  volatile int m_value __attribute__ ((aligned (4)));
367 #endif
368 };
369 
370 // ----------------------------------------------------------------------------
371 
376 // ----------------------------------------------------------------------------
377 
444 {
445 public:
446 
466  : m_guard( guard )
467  {
468  m_guarded = m_guard.TestAndSet( 0, 1 );
469  }
470 
477  {
478  if ( m_guarded )
479  m_guard.Store( 0 );
480  }
481 
486  operator bool() const volatile
487  {
488  return m_guarded;
489  }
490 
491 private:
492 
493  AtomicInt& m_guard;
494  bool m_guarded = false;
495 };
496 
506 #define PCL_REENTRANCY_GUARDED_BEGIN \
507  { \
508  static pcl::AtomicInt __r_g__( 0 ); \
509  volatile pcl::AutoReentrancyGuard __a_r_g__( __r_g__ ); \
510  if ( __a_r_g__ ) \
511  {
512 
522 #define PCL_REENTRANCY_GUARDED_END \
523  } \
524  }
525 
570 #define PCL_CLASS_REENTRANCY_GUARD \
571  mutable pcl::AtomicInt __pcl_guard__;
572 
586 #define PCL_CLASS_REENTRANCY_GUARDED_BEGIN \
587  { \
588  volatile pcl::AutoReentrancyGuard __a_r_g__( __pcl_guard__ ); \
589  if ( __a_r_g__ ) \
590  {
591 
637 #define PCL_MEMBER_REENTRANCY_GUARD( member ) \
638  mutable pcl::AtomicInt __pcl_guard_##member##__;
639 
653 #define PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( member ) \
654  { \
655  volatile pcl::AutoReentrancyGuard __a_r_g__( __pcl_guard_##member##__ );\
656  if ( __a_r_g__ ) \
657  {
658 
659 // ----------------------------------------------------------------------------
660 
661 } // pcl
662 
663 #endif // __PCL_Atomic_h
664 
665 // ----------------------------------------------------------------------------
666 // EOF pcl/Atomic.h - Released 2024-06-18T15:48:54Z
Atomic operations on integers.
Definition: Atomic.h:95
AtomicInt(const AtomicInt &)=default
bool Reference()
Definition: Atomic.h:250
int FetchAndAdd(int valueToAdd)
Definition: Atomic.h:347
bool Dereference()
Definition: Atomic.h:275
int FetchAndStore(int newValue)
Definition: Atomic.h:327
void Increment()
Definition: Atomic.h:207
int Load()
Definition: Atomic.h:181
void Store(int newValue)
Definition: Atomic.h:194
void Decrement()
Definition: Atomic.h:228
bool TestAndSet(int expectedValue, int newValue)
Definition: Atomic.h:302
AtomicInt(int value=0)
Definition: Atomic.h:102
Automatic reentrancy guard sentinel.
Definition: Atomic.h:444
AutoReentrancyGuard(AtomicInt &guard)
Definition: Atomic.h:465
bool operator==(const Array< T, A > &x1, const Array< T, A > &x2) noexcept
Definition: Array.h:2267
bool operator!=(const T1 &a, const T2 &b)
Definition: Relational.h:86
unsigned char uint8
Definition: Defs.h:642
PCL root namespace.
Definition: AbstractImage.h:77