Loading...
Searching...
No Matches
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
21
22#include "pxr/pxr.h"
27
28#include <memory>
29#include <thread>
30
31PXR_NAMESPACE_OPEN_SCOPE
32
33struct Tf_SingletonInitState
34{
35 const std::thread::id initThreadId;
36 void * const initInstance;
37};
38
39// This GIL-releasing helper is implemented in singleton.cpp. We do it this way
40// to avoid including the Python headers here.
41struct Tf_SingletonPyGILDropper
42{
43 TF_API
44 Tf_SingletonPyGILDropper();
45 TF_API
46 ~Tf_SingletonPyGILDropper();
47private:
48 std::unique_ptr<class TfPyLock> _pyLock;
49};
50
51template <class T>
52std::atomic<T *> TfSingleton<T>::_instance;
53
54template <class T>
55std::atomic<Tf_SingletonInitState *> TfSingleton<T>::_initState;
56
57template <class T>
58void
60{
61 // Capture the initializing thread id so that it can call GetInstance()
62 // successfully while other threads wait for full construction to complete.
63 std::unique_ptr<Tf_SingletonInitState> initState(
64 new Tf_SingletonInitState {
65 std::this_thread::get_id(), static_cast<void *>(&instance)
66 });
67
68 if (_instance.load() || _initState.exchange(initState.get()) != nullptr) {
69 TF_FATAL_ERROR("this function may not be called after "
70 "GetInstance() or another SetInstanceConstructed() "
71 "has completed");
72 }
73 initState.release();
74}
75
76template <class T>
77T *
78TfSingleton<T>::_CreateOrWaitForInstance(std::atomic<T *> &instance)
79{
80 static std::atomic<bool> isInitializing;
81
82 TfAutoMallocTag tag("Tf", "TfSingleton::_CreateOrWaitForInstance",
83 "Create Singleton " + ArchGetDemangled<T>());
84
85 // Check to see if we're the thread that's currently initializing the
86 // singleton. If so, return the initializing instance. Other threads will
87 // wait for initialization to complete.
88 if (Tf_SingletonInitState *initState = _initState.load()) {
89 if (initState->initThreadId == std::this_thread::get_id()) {
90 TF_AXIOM(initState->initInstance);
91 return static_cast<T *>(initState->initInstance);
92 }
93 // Otherwise fall through and wait for the instance to appear.
94 }
95
96 // Drop the GIL if we have it, before possibly locking to create the
97 // singleton instance.
98 Tf_SingletonPyGILDropper dropGIL;
99
100 // Try to take isInitializing false -> true. If we do it, then check to see
101 // if we don't yet have an instance. If we don't, then we get to create it.
102 // Otherwise we just wait until the instance shows up.
103 if (isInitializing.exchange(true) == false) {
104 // Do we not yet have an instance?
105 if (!instance) {
106 // Try to create the instance.
107 T *newInst;
108 try {
109 newInst = new T;
110 }
111 catch (...) {
112 // Ensure we clean up the _initState if it was set by a call to
113 // SetInstanceConstructed() in T's ctor.
114 delete _initState.exchange(nullptr);
115 throw;
116 }
117 T *curInst = nullptr;
118 if (Tf_SingletonInitState *initState = _initState.load()) {
119 TF_AXIOM(initState->initInstance);
120 curInst = static_cast<T *>(initState->initInstance);
121 }
122 if (curInst && (curInst != newInst)) {
123 TF_FATAL_ERROR("race detected setting singleton instance");
124 }
125 TF_AXIOM(instance.exchange(newInst) == nullptr);
126 }
127 isInitializing = false;
128 }
129 else {
130 while (!instance) {
131 std::this_thread::yield();
132 }
133 }
134
135 return instance.load();
136}
137
138template <typename T>
139void
141{
142 // Try to swap out a non-null instance for nullptr -- if we do it, we delete
143 // it.
144 T *instance = _instance.load();
145 if (instance && _instance.compare_exchange_strong(instance, nullptr)) {
146 delete instance;
147 delete _initState.exchange(nullptr);
148 }
149}
150
158#define TF_INSTANTIATE_SINGLETON(T) \
159 template class PXR_NS_GLOBAL::TfSingleton<T>
160
161
162PXR_NAMESPACE_CLOSE_SCOPE
Scoped (i.e.
Definition mallocTag.h:251
Manage a single instance of an object (see.
Definition singleton.h:107
static void DeleteInstance()
Destroy the sole instance object of type T, if it exists.
static void SetInstanceConstructed(T &instance)
Indicate that the sole instance object has already been created.
Demangle C++ typenames generated by the typeid() facility.
Stripped down version of diagnostic.h that doesn't define std::string.
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
Definition demangle.h:86
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
Definition diagnostic.h:193
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition diagnostic.h:91
Manage a single instance of an object.