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#ifdef PXR_PYTHON_SUPPORT_ENABLED
49 std::unique_ptr<class TfPyLock> _pyLock;
50#endif // PXR_PYTHON_SUPPORT_ENABLED
51};
52
53template <class T>
54std::atomic<T *> TfSingleton<T>::_instance;
55
56template <class T>
57std::atomic<Tf_SingletonInitState *> TfSingleton<T>::_initState;
58
59template <class T>
60void
62{
63 // Capture the initializing thread id so that it can call GetInstance()
64 // successfully while other threads wait for full construction to complete.
65 std::unique_ptr<Tf_SingletonInitState> initState(
66 new Tf_SingletonInitState {
67 std::this_thread::get_id(), static_cast<void *>(&instance)
68 });
69
70 if (_instance.load() || _initState.exchange(initState.get()) != nullptr) {
71 TF_FATAL_ERROR("this function may not be called after "
72 "GetInstance() or another SetInstanceConstructed() "
73 "has completed");
74 }
75 initState.release();
76}
77
78template <class T>
79T *
80TfSingleton<T>::_CreateOrWaitForInstance(std::atomic<T *> &instance)
81{
82 static std::atomic<bool> isInitializing;
83
84 TfAutoMallocTag tag("Tf", "TfSingleton::_CreateOrWaitForInstance",
85 "Create Singleton " + ArchGetDemangled<T>());
86
87 // Check to see if we're the thread that's currently initializing the
88 // singleton. If so, return the initializing instance. Other threads will
89 // wait for initialization to complete.
90 if (Tf_SingletonInitState *initState = _initState.load()) {
91 if (initState->initThreadId == std::this_thread::get_id()) {
92 TF_AXIOM(initState->initInstance);
93 return static_cast<T *>(initState->initInstance);
94 }
95 // Otherwise fall through and wait for the instance to appear.
96 }
97
98 // Drop the GIL if we have it, before possibly locking to create the
99 // singleton instance.
100 Tf_SingletonPyGILDropper dropGIL;
101
102 // Try to take isInitializing false -> true. If we do it, then check to see
103 // if we don't yet have an instance. If we don't, then we get to create it.
104 // Otherwise we just wait until the instance shows up.
105 if (isInitializing.exchange(true) == false) {
106 // Do we not yet have an instance?
107 if (!instance) {
108 // Try to create the instance.
109 T *newInst;
110 try {
111 newInst = new T;
112 }
113 catch (...) {
114 // Ensure we clean up the _initState if it was set by a call to
115 // SetInstanceConstructed() in T's ctor.
116 delete _initState.exchange(nullptr);
117 throw;
118 }
119 T *curInst = nullptr;
120 if (Tf_SingletonInitState *initState = _initState.load()) {
121 TF_AXIOM(initState->initInstance);
122 curInst = static_cast<T *>(initState->initInstance);
123 }
124 if (curInst && (curInst != newInst)) {
125 TF_FATAL_ERROR("race detected setting singleton instance");
126 }
127 TF_AXIOM(instance.exchange(newInst) == nullptr);
128 }
129 isInitializing = false;
130 }
131 else {
132 while (!instance) {
133 std::this_thread::yield();
134 }
135 }
136
137 return instance.load();
138}
139
140template <typename T>
141void
143{
144 // Try to swap out a non-null instance for nullptr -- if we do it, we delete
145 // it.
146 T *instance = _instance.load();
147 if (instance && _instance.compare_exchange_strong(instance, nullptr)) {
148 delete instance;
149 delete _initState.exchange(nullptr);
150 }
151}
152
160#define TF_INSTANTIATE_SINGLETON(T) \
161 template class PXR_NS_GLOBAL::TfSingleton<T>
162
163
164PXR_NAMESPACE_CLOSE_SCOPE
Scoped (i.e.
Definition: mallocTag.h:250
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.
#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.