HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
instantiateSingleton.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 /*
8  * This header is not meant to be included in a .h file.
9  * Complain if we see this header twice through.
10  */
11 
12 #ifdef PXR_BASE_TF_INSTANTIATE_SINGLETON_H
13 #error This file should only be included once in any given source (.cpp) file.
14 #endif
15 
16 #define PXR_BASE_TF_INSTANTIATE_SINGLETON_H
17 
18 /// \file tf/instantiateSingleton.h
19 /// \ingroup group_tf_ObjectCreation
20 /// Manage a single instance of an object.
21 
22 #include "pxr/pxr.h"
23 #include "pxr/base/tf/singleton.h"
25 #include "pxr/base/tf/mallocTag.h"
26 #include "pxr/base/arch/demangle.h"
27 
28 #include <memory>
29 #include <thread>
30 
32 
33 // This GIL-releasing helper is implemented in singleton.cpp. We do it this way
34 // to avoid including the Python headers here.
36 {
37  TF_API
39  TF_API
41 private:
42 #ifdef PXR_PYTHON_SUPPORT_ENABLED
43  std::unique_ptr<class TfPyLock> _pyLock;
44 #endif // PXR_PYTHON_SUPPORT_ENABLED
45 };
46 
47 template <class T> std::atomic<T *> TfSingleton<T>::_instance;
48 
49 template <class T>
50 void
52 {
53  if (_instance.exchange(&instance) != nullptr) {
54  TF_FATAL_ERROR("this function may not be called after "
55  "GetInstance() or another SetInstanceConstructed() "
56  "has completed");
57  }
58 }
59 
60 template <class T>
61 T *
62 TfSingleton<T>::_CreateInstance(std::atomic<T *> &instance)
63 {
64  static std::atomic<bool> isInitializing;
65 
66  TfAutoMallocTag2 tag("Tf", "TfSingleton::_CreateInstance",
67  "Create Singleton " + ArchGetDemangled<T>());
68 
69  // Drop the GIL if we have it, before possibly locking to create the
70  // singleton instance.
72 
73  // Try to take isInitializing false -> true. If we do it, then check to see
74  // if we don't yet have an instance. If we don't, then we get to create it.
75  // Otherwise we just wait until the instance shows up.
76  if (isInitializing.exchange(true) == false) {
77  // Do we not yet have an instance?
78  if (!instance) {
79  // Create it. The constructor may set instance via
80  // SetInstanceConstructed(), so check for that.
81  T *newInst = new T;
82 
83  T *curInst = instance.load();
84  if (curInst) {
85  if (curInst != newInst) {
86  TF_FATAL_ERROR("race detected setting singleton instance");
87  }
88  }
89  else {
90  TF_AXIOM(instance.exchange(newInst) == nullptr);
91  }
92  }
93  isInitializing = false;
94  }
95  else {
96  while (!instance) {
98  }
99  }
100 
101  return instance.load();
102 }
103 
104 template <typename T>
105 void
107 {
108  // Try to swap out a non-null instance for nullptr -- if we do it, we delete
109  // it.
110  T *instance = _instance.load();
111  while (instance && !_instance.compare_exchange_weak(instance, nullptr)) {
113  }
114  delete instance;
115 }
116 
117 /// Source file definition that a type is being used as a singleton.
118 ///
119 /// To use a type \c T in conjunction with \c TfSingleton, add
120 /// TF_INSTANTIATE_SINGLETON(T) in one source file (typically the .cpp) file
121 /// for class \c T.
122 ///
123 /// \hideinitializer
124 #define TF_INSTANTIATE_SINGLETON(T) \
125  template class PXR_NS_GLOBAL::TfSingleton<T>
126 
127 
#define TF_API
Definition: api.h:23
#define TF_FATAL_ERROR
static void SetInstanceConstructed(T &instance)
#define TF_AXIOM(cond)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
void yield() noexcept
Definition: thread.h:94
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
static void DeleteInstance()
TF_API ~Tf_SingletonPyGILDropper()