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 
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 
37 PXR_NAMESPACE_OPEN_SCOPE
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.
44 class Tf_Remnant : public TfSimpleRefBase
45 {
46 public:
47 
48  TF_API virtual ~Tf_Remnant();
49 
50  void _Forget() {
51  _alive = false;
52 
53  if (_notify2)
54  Tf_ExpiryNotifier::Invoke2(this);
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 
105  Tf_Remnant()
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 
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 
157  const TfWeakBase& operator= (const TfWeakBase&) {
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 
174  ~TfWeakBase() {
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  */
186  TfRefPtr<Tf_Remnant> _Register() const {
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 
210 class Tf_WeakBaseAccess {
211 public:
212  static TfRefPtr<Tf_Remnant> GetRemnant(TfWeakBase const &wb) {
213  return wb._Register();
214  }
215 private:
216  Tf_WeakBaseAccess();
217 };
218 
219 PXR_NAMESPACE_CLOSE_SCOPE
220 
221 #endif // PXR_BASE_TF_WEAK_BASE_H
Enable a concrete base class for use with TfRefPtr that inhibits the "unique changed" facility of TfR...
Definition: refBase.h:131
Reference counting.
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141