This document is for a version of USD that is under development. See this page for the current release.
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.