HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
registryManager.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 #ifndef PXR_BASE_TF_REGISTRY_MANAGER_H
8 #define PXR_BASE_TF_REGISTRY_MANAGER_H
9 
10 /// \file tf/registryManager.h
11 /// \ingroup group_tf_Initialization
12 
13 #include "pxr/pxr.h"
14 
17 #include "pxr/base/tf/api.h"
18 
19 #include <functional>
20 #include <typeinfo>
21 
23 
24 /// \class TfRegistryManager
25 /// \ingroup group_tf_Initialization
26 ///
27 /// Manage initialization of registries.
28 ///
29 /// See \ref page_tf_RegistryManager for a detailed description.
30 ///
32  TfRegistryManager(const TfRegistryManager&) = delete;
33  TfRegistryManager& operator=(const TfRegistryManager&) = delete;
34 
35 public:
36  // The type of a registration function. The arguments are not used.
37  typedef void (*RegistrationFunctionType)(void*, void*);
38  typedef std::function<void ()> UnloadFunctionType;
39 
40  /// Return the singleton \c TfRegistryManager instance.
42 
43  /// Request that any initialization for service \c T be performed.
44  ///
45  /// Calling \c SubscribeTo<T>() causes all existing \c
46  /// TF_REGISTRY_FUNCTION() functions of type \c T to be run. Once
47  /// this call is made, when new code is dynamically loaded then any
48  /// \c TF_REGISTRY_FUNCTION() functions of type \c T in the new code
49  /// will automatically be run when the code is loaded.
50  template <class T>
51  void SubscribeTo() {
52  _SubscribeTo(typeid(T));
53  }
54 
55  /// Cancel any previous subscriptions to service \c T.
56  ///
57  /// After this call, newly added code will no longer have \c
58  /// TF_REGISTRY_FUNCTION() functions of type \c T run.
59  template <class T>
60  void UnsubscribeFrom() {
61  _UnsubscribeFrom(typeid(T));
62  }
63 
64  /// Add an action to be performed at code unload time.
65  ///
66  /// When a \c TF_REGISTRY_FUNCTION() is run, it often needs to register an
67  /// inverse action to be taken when the code containing that function is
68  /// unloaded. For example, a plugin that adds information to a registry
69  /// will typically want to remove that information when the registry is
70  /// unloaded.
71  ///
72  /// Calling \c AddFunctionForUnload() requests that the given function be
73  /// run if the code from which the function is called is unloaded.
74  /// However, this is detectable only if this call is made from within the
75  /// call chain of some \c TF_REGISTRY_FUNCTION() function. In this case,
76  /// \c AddFunctionForUnload() returns true. Otherwise, false is returned
77  /// and the function is never run.
78  ///
79  /// Note however that by default, no unload functions are run when code is
80  /// being unloaded because exit() has been called. This is an
81  /// optimization, because most registries don't need to be deconstructed
82  /// at exit time. This behavior can be changed by calling \c
83  /// RunUnloadersAtExit().
85 
86  /// Run unload functions program exit time.
87  ///
88  /// The functions added by \c AddFunctionForUnload() are normally not run
89  /// when a program exits. For debugging purposes (e.g. checking for
90  /// memory leaks) it may be desirable to run the functions even at program
91  /// exit time. This call will force functions to be run at program exit
92  /// time.
93  ///
94  /// Note that this call does not cause construction of the singleton \c
95  /// TfRegistryManager object if it does not already exist.
96  TF_API static void RunUnloadersAtExit();
97 
98 private:
101 
102  TF_API void _SubscribeTo(const std::type_info&);
103  TF_API void _UnsubscribeFrom(const std::type_info&);
104 };
105 
106 TF_API void Tf_RegistryInitCtor(char const *name);
107 TF_API void Tf_RegistryInitDtor(char const *name);
108 
109 namespace {
110 struct Tf_RegistryStaticInit {
111  Tf_RegistryStaticInit() {
112  Tf_RegistryInitCtor(TF_PP_STRINGIZE(MFB_ALT_PACKAGE_NAME));
113  }
114  ~Tf_RegistryStaticInit() {
115  Tf_RegistryInitDtor(TF_PP_STRINGIZE(MFB_ALT_PACKAGE_NAME));
116  }
117 };
118 }
119 
120 // Private class used to indicate the library has finished registering
121 // functions, to indicate that the library is being unloaded and to
122 // add functions to the registry.
124 public:
125  TF_API static void Add(const char* libName,
127  const char* typeName);
128  template <class T, class U>
129  static void Add(const char* libName,
130  void (*func)(T*, U*),
131  const char* typeName)
132  {
133  Add(libName,(TfRegistryManager::RegistrationFunctionType)func,typeName);
134  }
135 };
136 
137 // The ARCH_CONSTRUCTOR priority for registering registry functions.
138 #define TF_REGISTRY_PRIORITY 100
139 
140 //
141 // Macros for adding registry functions outside class templates.
142 //
143 
144 // Define a registry function outside of a template. Follow the macro with
145 // the body of the function inside braces. KEY_TYPE and TAG must be types.
146 #define TF_REGISTRY_DEFINE_WITH_TYPE(KEY_TYPE, TAG) \
147  static void _Tf_RegistryFunction(KEY_TYPE*, TAG*); \
148  ARCH_CONSTRUCTOR(TF_PP_CAT(_Tf_RegistryAdd, __LINE__), \
149  TF_REGISTRY_PRIORITY, KEY_TYPE*, TAG*) \
150  { \
151  Tf_RegistryInit::Add(TF_PP_STRINGIZE(MFB_ALT_PACKAGE_NAME), \
152  (void(*)(KEY_TYPE*, TAG*))_Tf_RegistryFunction, \
153  TF_PP_STRINGIZE(KEY_TYPE)); \
154  } \
155  _ARCH_ENSURE_PER_LIB_INIT(Tf_RegistryStaticInit, _tfRegistryInit); \
156  static void _Tf_RegistryFunction(KEY_TYPE*, TAG*)
157 
158 // Define a registry function outside of a template. Follow the macro with
159 // the body of the function inside braces. KEY_TYPE must be a type and NAME
160 // must be a valid C++ name.
161 #define TF_REGISTRY_DEFINE(KEY_TYPE, NAME) \
162  static void TF_PP_CAT(_Tf_RegistryFunction, NAME)(KEY_TYPE*, void*); \
163  ARCH_CONSTRUCTOR(TF_PP_CAT(_Tf_RegistryAdd, NAME), \
164  TF_REGISTRY_PRIORITY, KEY_TYPE*) \
165  { \
166  Tf_RegistryInit::Add(TF_PP_STRINGIZE(MFB_ALT_PACKAGE_NAME), \
167  (void(*)(KEY_TYPE*, void*)) \
168  TF_PP_CAT(_Tf_RegistryFunction, NAME), \
169  TF_PP_STRINGIZE(KEY_TYPE)); \
170  } \
171  _ARCH_ENSURE_PER_LIB_INIT(Tf_RegistryStaticInit, _tfRegistryInit); \
172  static void TF_PP_CAT(_Tf_RegistryFunction, NAME)(KEY_TYPE*, void*)
173 
174 
175 /// Define a function that is called on demand by \c TfRegistryManager.
176 ///
177 /// This is a simpler form of TF_REGISTRY_FUNCTION_WITH_TAG() that provides
178 /// a tag for you, based on the MFB package, file name, and line number being
179 /// compiled. For most cases (private registry functions inside .cpp files)
180 /// this should do.
181 ///
182 /// A very common use is to symbolically define enum names (see \c TfEnum):
183 /// \code
184 /// TF_REGISTRY_FUNCTION(TfEnum)
185 /// {
186 /// // Bit-depth types.
187 /// TF_ADD_ENUM_NAME(ELEM_BITDEPTH_8);
188 /// TF_ADD_ENUM_NAME(ELEM_BITDEPTH_10);
189 /// TF_ADD_ENUM_NAME(ELEM_BITDEPTH_32);
190 ///
191 /// // Destination types.
192 /// TF_ADD_ENUM_NAME(ELEM_DESTINATION_DISKFARM);
193 /// TF_ADD_ENUM_NAME(ELEM_DESTINATION_JOBDIR);
194 ///
195 /// // Renderer types.
196 /// TF_ADD_ENUM_NAME(ELEM_RENDERER_GRAIL);
197 /// TF_ADD_ENUM_NAME(ELEM_RENDERER_PRMAN);
198 /// }
199 /// \endcode
200 ///
201 /// \hideinitializer
202 #define TF_REGISTRY_FUNCTION(KEY_TYPE) \
203  TF_REGISTRY_DEFINE(KEY_TYPE, __LINE__)
204 
205 /// Define a function that is called on demand by \c TfRegistryManager.
206 ///
207 /// Here is an example of using this macro:
208 /// \code
209 /// #include "pxr/base/tf/registryManager.h"
210 ///
211 /// TF_REGISTRY_FUNCTION_WITH_TAG(XyzRegistry, MyTag)
212 /// {
213 /// // calls to, presumably, XyzRegistry:
214 /// ...
215 /// }
216 ///\endcode
217 ///
218 /// Given the above, a call to \c TfRegistryManager::SubscribeTo<XyzRegistry>()
219 /// will cause the above function to be immediately run. (If the above function
220 /// has not yet been loaded, but is loaded in the future, it will be run then.)
221 /// The second type, \c MyType, is unimportant, but cannot be repeated with the
222 /// first type (i.e. there can be at most one call to \c TF_REGISTRY_FUNCTION()
223 /// for a given pair of types).
224 ///
225 /// In contrast to the typical static-constructor design, the code within a
226 /// TF_REGISTRY_FUNCTION() function is (usually) not run before main();
227 /// specifically, it is not run unless and until a call to SubscribeTo<T>()
228 /// occurs. This is important: if there are no subscribers, the code may never
229 /// be run.
230 ///
231 /// Note two restrictions: the type-names \p KEY_TYPE and \c TAG passed
232 /// to this macro must be untemplated, and not qualified with a
233 /// namespace. (Translation: the name as given must consist solely of letters and
234 /// numbers: no "<", ">" or ":" characters are allowed.) KEY_TYPE may be inside
235 /// a namespace but must not be explicitly qualified; you must use 'using
236 /// namespace &lt;foo>::KEY_TYPE' before calling this macro. Every use of \c
237 /// TF_REGISTRY_FUNCTION() must use a different pair for \c KEY_TYPE and \c
238 /// TAG or a multiply defined symbol will result at link time. Note
239 /// that this means the same KEY_TYPE in two or more namespaces may not be
240 /// registered in more than one namespace.
241 ///
242 /// \hideinitializer
243 #define TF_REGISTRY_FUNCTION_WITH_TAG(KEY_TYPE, TAG) \
244  TF_REGISTRY_DEFINE(KEY_TYPE, TF_PP_CAT(TAG, __LINE__))
245 
247 
248 #endif // PXR_BASE_TF_REGISTRY_MANAGER_H
static TF_API void RunUnloadersAtExit()
#define TF_API
Definition: api.h:23
std::function< void()> UnloadFunctionType
void
Definition: png.h:1083
#define TF_PP_STRINGIZE(x)
Expand and convert the argument to a string, using a most minimal macro.
void(* RegistrationFunctionType)(void *, void *)
static void Add(const char *libName, void(*func)(T *, U *), const char *typeName)
static TF_API void Add(const char *libName, TfRegistryManager::RegistrationFunctionType func, const char *typeName)
TF_API void Tf_RegistryInitCtor(char const *name)
static TF_API TfRegistryManager & GetInstance()
Return the singleton TfRegistryManager instance.
TF_API bool AddFunctionForUnload(const UnloadFunctionType &)
GLuint const GLchar * name
Definition: glcorearb.h:786
TF_API void Tf_RegistryInitDtor(char const *name)
GLenum func
Definition: glcorearb.h:783
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74