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 TF_WEAKBASE_H
25 #define TF_WEAKBASE_H
26 
29 
30 #include "pxr/pxr.h"
31 
32 #include "pxr/base/tf/expiryNotifier.h"
33 #include "pxr/base/tf/refPtr.h"
34 #include "pxr/base/tf/traits.h"
35 #include "pxr/base/tf/api.h"
36 #include <atomic>
37 
38 PXR_NAMESPACE_OPEN_SCOPE
39 
40 // The _Remnant structure is simply a persistent memory of an object's
41 // address. When the object dies, the pointer is set to NULL. A _Remnant
42 // object is destroyed when both the original whose address it was
43 // initialized with, and there are no weak pointers left pointing to that
44 // remnant.
45 class Tf_Remnant : public TfSimpleRefBase
46 {
47 public:
48 
49  TF_API virtual ~Tf_Remnant();
50 
51  void _Forget() {
52  _alive = false;
53 
54  if (_notify2)
55  Tf_ExpiryNotifier::Invoke2(this);
56  }
57 
58  // Note that only "false" is of value in a multi-threaded world...
59  bool _IsAlive() {
60  return _alive;
61  }
62 
63  // Must return an object's address whose lifetime is as long or longer than
64  // this object. Default implementation returns 'this'.
65  TF_API virtual void const *_GetUniqueIdentifier() const;
66 
67  // Note: this initializes a class member -- the parameter is a non-const
68  // reference.
70  Register(std::atomic<Tf_Remnant*> &remnantPtr) {
71  if (Tf_Remnant *remnant = remnantPtr.load()) {
72  // Remnant exists. Return additional reference.
73  return TfRefPtr<Tf_Remnant>(remnant);
74  } else {
75  // Allocate a remnant and attempt to register it.
76  return Register(remnantPtr, new Tf_Remnant);
77  }
78  }
79 
80  // Note: this initializes a class member -- the parameter is a non-const
81  // reference.
82  template <class T>
84  Register(std::atomic<Tf_Remnant*> &remnantPtr, T *candidate) {
85  Tf_Remnant *existing = nullptr;
86  if (remnantPtr.compare_exchange_strong(
87  existing,
88  static_cast<Tf_Remnant*>(candidate))) {
89  // Candidate registered. Return additional reference.
90  return TfRefPtr<Tf_Remnant>(candidate);
91  } else {
92  // Somebody beat us to it.
93  // Discard candidate and return additional reference.
94  delete candidate;
95  return TfRefPtr<Tf_Remnant>(existing);
96  }
97  }
98 
99  // Mark this remnant to call the expiry notification callback function when
100  // it dies. See ExpiryNotifier.h
101  TF_API virtual void EnableNotification() const;
102 
103 protected:
104  friend class TfWeakBase;
105 
106  Tf_Remnant()
107  : _notify(false),
108  _notify2(false),
109  _alive(true)
110  {
111  }
112 
113 private:
114 
115  mutable bool _notify, _notify2;
116  bool _alive;
117 };
118 
142 class TfWeakBase {
143 public:
144  TfWeakBase() : _remnantPtr(nullptr) {}
145 
146  TfWeakBase(const TfWeakBase&) : _remnantPtr(nullptr) {
147  // A newly created copy of a weak base doesn't start with a remnant
148  }
149 
150  // Don't call this method -- only for Tf internal use. The presence of this
151  // method is used by TfWeakPtr and related classes to determine whether a
152  // class may be pointed to by a TfWeakPtr. It is named nonstandardly to
153  // avoid any possible conflict with other names in derived classes.
154  const TfWeakBase& __GetTfWeakBase__() const {
155  return *this;
156  }
157 
158  const TfWeakBase& operator= (const TfWeakBase&) {
159  // Do nothing. An assignment should NOT assign the other object's
160  // remnant and should NOT create a new remnant. We want to keep
161  // the one we already have (if any).
162  return *this;
163  }
164 
165  // Don't call this. Really.
166  void EnableNotification2() const;
167 
168  TF_API void const* GetUniqueIdentifier() const;
169 
170 protected:
171  /*
172  * Prohibit deletion through a TfWeakBase pointer.
173  */
174 
175  ~TfWeakBase() {
176  if (Tf_Remnant *remnant = _remnantPtr.load(std::memory_order_relaxed)) {
177  remnant->_Forget();
178  // Briefly forge a TfRefPtr to handle dropping our implied
179  // reference to the remnant.
180  TfRefPtr<Tf_Remnant> lastRef = TfCreateRefPtr(remnant);
181  }
182  }
183 
184  /*
185  * This needs to be atomic, for multithreading.
186  */
187  TfRefPtr<Tf_Remnant> _Register() const {
188  return Tf_Remnant::Register(_remnantPtr);
189  }
190 
191  template <class T>
192  TfRefPtr<Tf_Remnant> _Register(T *tempRmnt) const {
193  return Tf_Remnant::Register<T>(_remnantPtr, tempRmnt);
194  }
195 
196  bool _HasRemnant() const {
197  return _remnantPtr.load(std::memory_order_relaxed) ? true : false;
198  }
199 
200 private:
201 
202  // XXX Conceptually this plays the same role as a TfRefPtr to the
203  // Tf_Remnant, in the sense that we want TfWeakBase to participate
204  // in the ref-counted lifetime tracking of its remnant.
205  // However, we require atomic initialization of this pointer.
206  mutable std::atomic<Tf_Remnant*> _remnantPtr;
207 
208  friend class Tf_WeakBaseAccess;
209 };
210 
211 class Tf_WeakBaseAccess {
212 public:
213  static TfRefPtr<Tf_Remnant> GetRemnant(TfWeakBase const &wb) {
214  return wb._Register();
215  }
216 private:
217  Tf_WeakBaseAccess();
218 };
219 
220 PXR_NAMESPACE_CLOSE_SCOPE
221 
222 #endif // TF_WEAKBASE_H
Enable a concrete base class for use with TfRefPtr that inhibits the &quot;unique changed&quot; facility of TfR...
Definition: refBase.h:132
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:142