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