HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
weakBase.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_WEAK_BASE_H
25 #define PXR_BASE_TF_WEAK_BASE_H
26 
27 /// \file tf/weakBase.h
28 /// \ingroup group_tf_Memory
29 
30 #include "pxr/pxr.h"
31 
32 #include "pxr/base/tf/api.h"
34 #include "pxr/base/tf/refPtr.h"
35 #include <atomic>
36 
38 
39 // The _Remnant structure is simply a persistent memory of an object's
40 // address. When the object dies, the pointer is set to NULL. A _Remnant
41 // object is destroyed when both the original whose address it was
42 // initialized with, and there are no weak pointers left pointing to that
43 // remnant.
45 {
46 public:
47 
48  TF_API virtual ~Tf_Remnant();
49 
50  void _Forget() {
51  _alive = false;
52 
53  if (_notify2)
55  }
56 
57  // Note that only "false" is of value in a multi-threaded world...
58  bool _IsAlive() const {
59  return _alive;
60  }
61 
62  // Must return an object's address whose lifetime is as long or longer than
63  // this object. Default implementation returns 'this'.
64  TF_API virtual void const *_GetUniqueIdentifier() const;
65 
66  // Note: this initializes a class member -- the parameter is a non-const
67  // reference.
69  Register(std::atomic<Tf_Remnant*> &remnantPtr) {
70  if (Tf_Remnant *remnant = remnantPtr.load()) {
71  // Remnant exists. Return additional reference.
72  return TfRefPtr<Tf_Remnant>(remnant);
73  } else {
74  // Allocate a remnant and attempt to register it.
75  return Register(remnantPtr, new Tf_Remnant);
76  }
77  }
78 
79  // Note: this initializes a class member -- the parameter is a non-const
80  // reference.
81  template <class T>
83  Register(std::atomic<Tf_Remnant*> &remnantPtr, T *candidate) {
84  Tf_Remnant *existing = nullptr;
85  if (remnantPtr.compare_exchange_strong(
86  existing,
87  static_cast<Tf_Remnant*>(candidate))) {
88  // Candidate registered. Return additional reference.
89  return TfRefPtr<Tf_Remnant>(candidate);
90  } else {
91  // Somebody beat us to it.
92  // Discard candidate and return additional reference.
93  delete candidate;
94  return TfRefPtr<Tf_Remnant>(existing);
95  }
96  }
97 
98  // Mark this remnant to call the expiry notification callback function when
99  // it dies. See ExpiryNotifier.h
100  TF_API virtual void EnableNotification() const;
101 
102 protected:
103  friend class TfWeakBase;
104 
106  : _notify(false),
107  _notify2(false),
108  _alive(true)
109  {
110  }
111 
112 private:
113 
114  mutable bool _notify, _notify2;
115  bool _alive;
116 };
117 
118 /// \class TfWeakBase
119 /// \ingroup group_tf_Memory
120 ///
121 /// Enable a concrete base class for use with \c TfWeakPtr.
122 ///
123 /// You should be familiar with the \c TfWeakPtr type before reading further.
124 ///
125 /// A class is enabled for use with the \c TfWeakPtr type by publicly deriving
126 /// from \c TfWeakBase. (Note that deriving from \c TfWeakBase adds data to a
127 /// structure, so the result is no longer a "pure" interface class.)
128 ///
129 /// For example,
130 /// \code
131 /// #include "pxr/base/tf/weakBase.h"
132 ///
133 /// class Simple : public TfWeakBase {
134 /// ...
135 /// };
136 /// \endcode
137 ///
138 /// Given the above inheritance, a \c Simple* can now be used to initialize an
139 /// object of type \c TfWeakPtr<Simple>.
140 ///
141 class TfWeakBase {
142 public:
143  TfWeakBase() : _remnantPtr(nullptr) {}
144 
145  TfWeakBase(const TfWeakBase&) : _remnantPtr(nullptr) {
146  // A newly created copy of a weak base doesn't start with a remnant
147  }
148 
149  // Don't call this method -- only for Tf internal use. The presence of this
150  // method is used by TfWeakPtr and related classes to determine whether a
151  // class may be pointed to by a TfWeakPtr. It is named nonstandardly to
152  // avoid any possible conflict with other names in derived classes.
153  const TfWeakBase& __GetTfWeakBase__() const {
154  return *this;
155  }
156 
158  // Do nothing. An assignment should NOT assign the other object's
159  // remnant and should NOT create a new remnant. We want to keep
160  // the one we already have (if any).
161  return *this;
162  }
163 
164  // Don't call this. Really.
165  void EnableNotification2() const;
166 
167  TF_API void const* GetUniqueIdentifier() const;
168 
169 protected:
170  /*
171  * Prohibit deletion through a TfWeakBase pointer.
172  */
173 
175  if (Tf_Remnant *remnant = _remnantPtr.load(std::memory_order_relaxed)) {
176  remnant->_Forget();
177  // Briefly forge a TfRefPtr to handle dropping our implied
178  // reference to the remnant.
179  TfRefPtr<Tf_Remnant> lastRef = TfCreateRefPtr(remnant);
180  }
181  }
182 
183  /*
184  * This needs to be atomic, for multithreading.
185  */
187  return Tf_Remnant::Register(_remnantPtr);
188  }
189 
190  template <class T>
191  TfRefPtr<Tf_Remnant> _Register(T *tempRmnt) const {
192  return Tf_Remnant::Register<T>(_remnantPtr, tempRmnt);
193  }
194 
195  bool _HasRemnant() const {
196  return _remnantPtr.load(std::memory_order_relaxed) ? true : false;
197  }
198 
199 private:
200 
201  // XXX Conceptually this plays the same role as a TfRefPtr to the
202  // Tf_Remnant, in the sense that we want TfWeakBase to participate
203  // in the ref-counted lifetime tracking of its remnant.
204  // However, we require atomic initialization of this pointer.
205  mutable std::atomic<Tf_Remnant*> _remnantPtr;
206 
207  friend class Tf_WeakBaseAccess;
208 };
209 
211 public:
213  return wb._Register();
214  }
215 private:
217 };
218 
220 
221 #endif // PXR_BASE_TF_WEAK_BASE_H
TfRefPtr< T > TfCreateRefPtr(T *ptr)
Definition: refPtr.h:1198
virtual TF_API ~Tf_Remnant()
#define TF_API
Definition: api.h:40
TfRefPtr< Tf_Remnant > _Register(T *tempRmnt) const
Definition: weakBase.h:191
bool _HasRemnant() const
Definition: weakBase.h:195
const TfWeakBase & operator=(const TfWeakBase &)
Definition: weakBase.h:157
static TfRefPtr< Tf_Remnant > GetRemnant(TfWeakBase const &wb)
Definition: weakBase.h:212
const TfWeakBase & __GetTfWeakBase__() const
Definition: weakBase.h:153
TfWeakBase(const TfWeakBase &)
Definition: weakBase.h:145
void EnableNotification2() const
static TfRefPtr< Tf_Remnant > Register(std::atomic< Tf_Remnant * > &remnantPtr)
Definition: weakBase.h:69
static TF_API void Invoke2(void const *p)
Tf_Remnant()
Definition: weakBase.h:105
~TfWeakBase()
Definition: weakBase.h:174
virtual TF_API void const * _GetUniqueIdentifier() const
TfWeakBase()
Definition: weakBase.h:143
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1441
static TfRefPtr< Tf_Remnant > Register(std::atomic< Tf_Remnant * > &remnantPtr, T *candidate)
Definition: weakBase.h:83
bool _IsAlive() const
Definition: weakBase.h:58
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
TfRefPtr< Tf_Remnant > _Register() const
Definition: weakBase.h:186
virtual TF_API void EnableNotification() const
TF_API void const * GetUniqueIdentifier() const
void _Forget()
Definition: weakBase.h:50