All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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
21
22#include "pxr/pxr.h"
27
28#include <memory>
29#include <thread>
30
31PXR_NAMESPACE_OPEN_SCOPE
32
33// This GIL-releasing helper is implemented in singleton.cpp. We do it this way
34// to avoid including the Python headers here.
35struct Tf_SingletonPyGILDropper
36{
37 TF_API
38 Tf_SingletonPyGILDropper();
39 TF_API
40 ~Tf_SingletonPyGILDropper();
41private:
42#ifdef PXR_PYTHON_SUPPORT_ENABLED
43 std::unique_ptr<class TfPyLock> _pyLock;
44#endif // PXR_PYTHON_SUPPORT_ENABLED
45};
46
47template <class T> std::atomic<T *> TfSingleton<T>::_instance;
48
49template <class T>
50void
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
60template <class T>
61T *
62TfSingleton<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.
71 Tf_SingletonPyGILDropper dropGIL;
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) {
97 std::this_thread::yield();
98 }
99 }
100
101 return instance.load();
102}
103
104template <typename T>
105void
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)) {
112 std::this_thread::yield();
113 }
114 delete instance;
115}
116
124#define TF_INSTANTIATE_SINGLETON(T) \
125 template class PXR_NS_GLOBAL::TfSingleton<T>
126
127
128PXR_NAMESPACE_CLOSE_SCOPE
Scoped (i.e.
Definition: mallocTag.h:249
Manage a single instance of an object (see.
Definition: singleton.h:105
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.