/[svn]/linuxsampler/trunk/src/common/Ref.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/common/Ref.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3767 by schoenebeck, Fri May 15 19:28:13 2020 UTC revision 3768 by schoenebeck, Fri May 15 19:52:31 2020 UTC
# Line 10  Line 10 
10  #ifndef LS_REF_H  #ifndef LS_REF_H
11  #define LS_REF_H  #define LS_REF_H
12    
13    #include "global.h"
14    
15  #include <set>  #include <set>
16  #include <stdio.h>  #include <stdio.h>
17  #if __cplusplus >= 201103L && !CONFIG_NO_CPP11STL  #if __cplusplus >= 201103L && !CONFIG_NO_CPP11STL
# Line 23  Line 25 
25  // be much slower.  // be much slower.
26  #define LS_REF_ASSERT_MODE 0  #define LS_REF_ASSERT_MODE 0
27    
28  #if LS_REF_ASSERT_MODE  // Enable this for VERY verbose debug messages for debugging deep issues with
 # warning LS_REF_ASSERT_MODE is enabled which will decrease runtime efficiency!  
 #endif  
   
 // Enable this for VERY verbose debug messages for debbugging deep issues with  
29  // Ref class.  // Ref class.
30  #define LS_REF_VERBOSE_DEBUG_MSG 0  #define LS_REF_VERBOSE_DEBUG_MSG 0
31    
32  #if LS_REF_ASSERT_MODE  #if LS_REF_ASSERT_MODE
33    # warning LS_REF_ASSERT_MODE is enabled which will decrease runtime efficiency!
34  # include <assert.h>  # include <assert.h>
35  #endif  #endif
36    
37  namespace LinuxSampler {  // Whether the Ref<> class shall be thread safe. Performance penalty should not
38    // be measurable in practice due to non blocking, lock-free atomic add, sub and
39    // CAS instructions being used, so this is recommended and enabled by default.
40    #ifndef LS_REF_ATOMIC
41    # define LS_REF_ATOMIC 1
42    #endif
43    
44      //TODO: make reference count increment/decrement thread safe  //NOTE: We are using our own atomic implementation instead of std::atomic of the
45    // C++ STL, because our atomic implementation is lock-free and wait-free. The
46    // C++ standard just recommends, but does not guarantee lock-free implementation
47    // (state of the C++20 standard as of 2020-04-27):
48    // https://en.cppreference.com/w/cpp/atomic/atomic/is_lock_free
49    #if LS_REF_ATOMIC
50    # include "atomic.h"
51    # include <stdatomic.h>
52    # if __STDC_NO_ATOMICS__
53    #  undef LS_REF_ATOMIC
54    #  warning Ref<> class will not be thread safe, since compiler does not support C11 atomics!
55    # endif
56    #else
57    # warning Ref<> class will not be thread safe (feature explicitly disabled)!
58    #endif
59    
60    #if LS_REF_ASSERT_MODE && LS_REF_ATOMIC
61    # include "Mutex.h"
62    #endif
63    
64    namespace LinuxSampler {
65    
66      template<typename T, typename T_BASE> class Ref;      template<typename T, typename T_BASE> class Ref;
67    
68        #if LS_REF_ASSERT_MODE
69      extern std::set<void*> _allRefPtrs;      extern std::set<void*> _allRefPtrs;
70        #endif
71        #if LS_REF_ASSERT_MODE && LS_REF_ATOMIC
72        extern Mutex _allRefPtrsMutex;
73        #endif
74    
75      /**      /**
76       * Exists just for implementation detail purpose, you cannot use it       * Exists just for implementation detail purpose, you cannot use it
# Line 55  namespace LinuxSampler { Line 84  namespace LinuxSampler {
84          template<typename T_BASE1>          template<typename T_BASE1>
85          class _RefCounter {          class _RefCounter {
86          public:          public:
87              _RefCounter(T_BASE1* p, int refs) :              _RefCounter(T_BASE1* p, int refs, bool released) :
88                  references(refs), ptr(p)                  #if LS_REF_ATOMIC
89                    references(ATOMIC_INIT(refs)),
90                    #else
91                    references(refs),
92                    #endif
93                    ptr(p)
94              {              {
95                    #if LS_REF_ATOMIC
96                    atomic_store(&zombi, released);
97                    #endif
98                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
99                  printf("Ref 0x%lx: new counter (refs=%d)\n", (long long)ptr, references);                  printf("Ref %p: new counter (refs=%d)\n", ptr,
100                        #if LS_REF_ATOMIC
101                           atomic_read(&references)
102                        #else
103                           references
104                        #endif
105                    );
106                  #endif                  #endif
107                  #if LS_REF_ASSERT_MODE                  #if LS_REF_ASSERT_MODE
108                  assert(p);                  assert(p);
109                  assert(refs > 0);                  assert(refs > 0);
110                  assert(!_allRefPtrs.count(p));                  assert(!released);
111                  _allRefPtrs.insert(p);                  {
112                        #if LS_REF_ATOMIC
113                        LockGuard lock(_allRefPtrsMutex);
114                        #endif
115                        assert(!_allRefPtrs.count(p));
116                        _allRefPtrs.insert(p);
117                    }
118                  #endif                  #endif
119              }              }
120    
121              virtual ~_RefCounter() {              virtual ~_RefCounter() {
122                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
123                  printf("Ref 0x%lx: counter destructor (refs=%d)\n", (long long)ptr, references);                  printf("Ref %p: counter destructor (refs=%d)\n", ptr,
124                        #if LS_REF_ATOMIC
125                           atomic_read(&references)
126                        #else
127                           references
128                        #endif
129                    );
130                  #endif                  #endif
131                  fflush(stdout);                  fflush(stdout);
132              }              }
133    
134              void retain() {              void retain() {
135                    #if LS_REF_ATOMIC
136                    atomic_inc(&references);
137                    #else
138                  references++;                  references++;
139                    #endif
140                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
141                  printf("Ref 0x%lx: retain (refs=%d)\n", (long long)ptr, references);                  printf("Ref %p: retain (refs=%d)\n", ptr,
142                        #if LS_REF_ATOMIC
143                           atomic_read(&references)
144                        #else
145                           references
146                        #endif
147                    );
148                  #endif                  #endif
149              }              }
150    
151              void release() {              void release() {
152                    #if LS_REF_ATOMIC
153                    bool zero = atomic_dec_and_test(&references);
154                    # if LS_REF_VERBOSE_DEBUG_MSG
155                    printf("Ref %p: release (zero=%d)\n", ptr, zero);
156                    # endif
157                    if (!zero) return;
158                    bool expect = false;
159                    bool release = atomic_compare_exchange_strong(&zombi, &expect, true);
160                    if (release) deletePtr();
161                    #else
162                  if (!references) return;                  if (!references) return;
163                  references--;                  references--;
164                  #if LS_REF_VERBOSE_DEBUG_MSG                  # if LS_REF_VERBOSE_DEBUG_MSG
165                  printf("Ref 0x%lx: release (refs=%d)\n", (long long)ptr, references);                  printf("Ref %p: release (refs=%d)\n", ptr, references);
166                  #endif                  # endif
167                  if (!references) deletePtr();                  if (!references) deletePtr();
168                    #endif // LS_REF_ATOMIC
169              }              }
170          //protected:          //protected:
171              void deletePtr() {              void deletePtr() {
172                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
173                  printf("RefCounter 0x%lx: deletePtr() (refs=%d)\n", (long long)ptr, references);                  printf("RefCounter %p: deletePtr() (refs=%d)\n", ptr,
174                        #if LS_REF_ATOMIC
175                           atomic_read(&references)
176                        #else
177                           references
178                        #endif
179                    );
180                  #endif                  #endif
181                  #if LS_REF_ASSERT_MODE                  #if LS_REF_ASSERT_MODE
182                    # if LS_REF_ATOMIC
183                    assert(!atomic_read(&references));
184                    # else
185                  assert(!references);                  assert(!references);
186                  _allRefPtrs.erase(ptr);                  # endif
187                    {
188                        #if LS_REF_ATOMIC
189                        LockGuard lock(_allRefPtrsMutex);
190                        #endif
191                        _allRefPtrs.erase(ptr);
192                    }
193                  #endif                  #endif
194                  delete ptr;                  delete ptr;
195                  delete this;                  delete this;
196              }              }
197    
198                #if LS_REF_ATOMIC
199                atomic_t references;
200                atomic_bool zombi; ///< @c false if not released yet, @c true once @c ptr was released
201                #else
202              int references;              int references;
203                #endif
204              T_BASE1* ptr;              T_BASE1* ptr;
205              //friend class ... todo              //friend class ... todo
206          };          };
# Line 138  namespace LinuxSampler { Line 234  namespace LinuxSampler {
234      };      };
235    
236      /**      /**
237       * Replicates a std::shared_ptr template class, to avoid a build requirement       * Replicates a std::shared_ptr template class. Originally this class was
238       * of having a C++11 compliant compiler (std::shared_ptr was not part of the       * introduced to avoid a build requirement of having a C++11 compliant
239       * C++03 standard).       * compiler (std::shared_ptr was not part of the C++03 standard). This class
240         * had been preserved though due to some advantages over the STL
241         * implementation, most notably: unlike std::shared_ptr from the STL, this
242         * Ref<> class provides thread safety by using a (guaranteed) lock-free and
243         * wait-free implementation, which is relevant for real-time applications.
244       *       *
245       * In contrast to the STL implementation though this implementation here       * In contrast to the STL implementation though this implementation here
246       * also supports copying references of derived, different types (in a type       * also supports copying references of derived, different types (in a type
# Line 202  namespace LinuxSampler { Line 302  namespace LinuxSampler {
302                    
303          Ref() : RefBaseT() {          Ref() : RefBaseT() {
304              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
305              printf("Ref empty ctor Ref:0x%lx\n", (long long)this);              printf("Ref empty ctor Ref:%p\n", this);
306              #endif              #endif
307          }          }
308    
# Line 211  namespace LinuxSampler { Line 311  namespace LinuxSampler {
311          #endif          #endif
312          Ref(const T_BASE* p) : RefBaseT() {          Ref(const T_BASE* p) : RefBaseT() {
313              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
314              printf("Ref base ptr ctor Ref:0x%lx <- p:0x%lx\n", (long long)this, (long long)p);              printf("Ref base ptr ctor Ref:%p <- p:%p\n", this, p);
315              #endif              #endif
316              RefBaseT::refCounter = p ? new RefCounter((T_BASE*)p, 1) : NULL;              RefBaseT::refCounter = p ? new RefCounter((T_BASE*)p, 1, false) : NULL;
317          }          }
318    
319          Ref(const T* p) : RefBaseT() {          Ref(const T* p) : RefBaseT() {
320              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
321              printf("Ref main ptr ctor Ref:0x%lx <- p:0x%lx\n", (long long)this, (long long)p);              printf("Ref main ptr ctor Ref:%p <- p:%p\n", this, p);
322              #endif              #endif
323              RefBaseT::refCounter = p ? new RefCounter((T*)p, 1) : NULL;              RefBaseT::refCounter = p ? new RefCounter((T*)p, 1, false) : NULL;
324          }          }
325    
326          Ref(const RefBaseT& r) : RefBaseT() {          Ref(const RefBaseT& r) : RefBaseT() {
327              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
328              printf("Ref base ref ctor Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&r);              printf("Ref base ref ctor Ref:%p <- Ref:%p\n", this, &r);
329              #endif              #endif
330              RefBaseT::refCounter = r.refCounter;              RefBaseT::refCounter = r.refCounter;
331              if (RefBaseT::refCounter)              if (RefBaseT::refCounter)
# Line 234  namespace LinuxSampler { Line 334  namespace LinuxSampler {
334    
335          Ref(const Ref& r) : RefBaseT() {          Ref(const Ref& r) : RefBaseT() {
336              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
337              printf("Ref main ref ctor Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&r);              printf("Ref main ref ctor Ref:%p <- Ref:%p\n", this, &r);
338              #endif              #endif
339              RefBaseT::refCounter = r.refCounter;              RefBaseT::refCounter = r.refCounter;
340              if (RefBaseT::refCounter)              if (RefBaseT::refCounter)
# Line 298  namespace LinuxSampler { Line 398  namespace LinuxSampler {
398    
399          Ref<T,T_BASE>& operator=(const RefBaseT& other) {          Ref<T,T_BASE>& operator=(const RefBaseT& other) {
400              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
401              printf("Ref base ref assignment Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&other);              printf("Ref base ref assignment Ref:%p <- Ref:%p\n", this, &other);
402              #endif              #endif
403              if (isEquivalent(other)) {              if (isEquivalent(other)) {
404                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
405                  printf("Ref 0x%lx WRN: equivalent ref assignment ignored.\n", (long long)this);                  printf("Ref %p WRN: equivalent ref assignment ignored.\n", this);
406                  #endif                  #endif
407                  return *this;                  return *this;
408              }              }
# Line 318  namespace LinuxSampler { Line 418  namespace LinuxSampler {
418    
419          Ref<T,T_BASE>& operator=(const Ref<T,T_BASE>& other) {          Ref<T,T_BASE>& operator=(const Ref<T,T_BASE>& other) {
420              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
421              printf("Ref main ref assignment Ref:0x%lx <- Ref:0x%lx\n", (long long)this, (long long)&other);              printf("Ref main ref assignment Ref:%p <- Ref:%p\n", this, &other);
422              #endif              #endif
423              if (isEquivalent(other)) {              if (isEquivalent(other)) {
424                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
425                  printf("Ref 0x%lx WRN: equivalent ref assignment ignored.\n", (long long)this);                  printf("Ref %p WRN: equivalent ref assignment ignored.\n", this);
426                  #endif                  #endif
427                  return *this;                  return *this;
428              }              }
# Line 338  namespace LinuxSampler { Line 438  namespace LinuxSampler {
438    
439          Ref<T,T_BASE>& operator=(const T* p) {          Ref<T,T_BASE>& operator=(const T* p) {
440              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
441              printf("Ref main ptr assignment Ref:0x%lx <- p:0x%lx\n", (long long)this, p);              printf("Ref main ptr assignment Ref:%p <- p:%p\n", this, p);
442              #endif              #endif
443              if (isEquivalent(p)) {              if (isEquivalent(p)) {
444                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
445                  printf("Ref 0x%lx WRN: equivalent ptr assignment ignored.\n", (long long)this);                  printf("Ref %p WRN: equivalent ptr assignment ignored.\n", this);
446                  #endif                  #endif
447                  return *this;                  return *this;
448              }              }
# Line 350  namespace LinuxSampler { Line 450  namespace LinuxSampler {
450                  RefBaseT::refCounter->release();                  RefBaseT::refCounter->release();
451                  RefBaseT::refCounter = NULL;                  RefBaseT::refCounter = NULL;
452              }              }
453              RefBaseT::refCounter = p ? new RefCounter((T*)p, 1) : NULL;              RefBaseT::refCounter = p ? new RefCounter((T*)p, 1, false) : NULL;
454              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
455              printf("Ref main ptr assignment done\n");              printf("Ref main ptr assignment done\n");
456              #endif              #endif
# Line 362  namespace LinuxSampler { Line 462  namespace LinuxSampler {
462          #endif          #endif
463          Ref<T,T_BASE>& operator=(const T_BASE* p) {          Ref<T,T_BASE>& operator=(const T_BASE* p) {
464              #if LS_REF_VERBOSE_DEBUG_MSG              #if LS_REF_VERBOSE_DEBUG_MSG
465              printf("Ref base ptr assignment Ref:0x%lx <- p:0x%lx\n", (long long)this, p);              printf("Ref base ptr assignment Ref:%p <- p:%p\n", this, p);
466              #endif              #endif
467              if (isEquivalent(p)) {              if (isEquivalent(p)) {
468                  #if LS_REF_VERBOSE_DEBUG_MSG                  #if LS_REF_VERBOSE_DEBUG_MSG
469                  printf("Ref 0x%lx WRN: equivalent ptr assignment ignored.\n", (long long)this);                  printf("Ref %p WRN: equivalent ptr assignment ignored.\n", this);
470                  #endif                  #endif
471                  return *this;                  return *this;
472              }              }
# Line 374  namespace LinuxSampler { Line 474  namespace LinuxSampler {
474                  RefBaseT::refCounter->release();                  RefBaseT::refCounter->release();
475                  RefBaseT::refCounter = NULL;                  RefBaseT::refCounter = NULL;
476              }              }
477              RefBaseT::refCounter = p ? new RefCounter((T*)p, 1) : NULL;              RefBaseT::refCounter = p ? new RefCounter((T*)p, 1, false) : NULL;
478              return *this;              return *this;
479          }          }
480      };      };

Legend:
Removed from v.3767  
changed lines
  Added in v.3768

  ViewVC Help
Powered by ViewVC