HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
diagnostic.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_DIAGNOSTIC_H
25 #define PXR_BASE_TF_DIAGNOSTIC_H
26 
27 /// \file tf/diagnostic.h
28 /// \ingroup group_tf_Diagnostic
29 /// Low-level utilities for informing users of various internal and external
30 /// diagnostic conditions.
31 ///
32 /// lib/tf supports a range of error-reporting routines.
33 ///
34 /// For a more detailed explanation of when each of the facilities described
35 /// in this file is appropriate, (and more importantly, when they're not!)
36 /// see \ref page_tf_Diagnostic.
37 
38 #include "pxr/pxr.h"
39 #include "pxr/base/arch/function.h"
41 #include "pxr/base/tf/api.h"
42 
43 #if defined(__cplusplus) || defined (doxygen)
44 
45 #include "pxr/base/arch/hints.h"
47 
48 #include <stddef.h>
49 #include <stdarg.h>
50 #include <string>
51 
53 
54 // Note: diagnosticLite.h defines the various macros, but we'll document
55 // them here. The following block is only for doxygen, not seen by a real
56 // compile. To see the actual macro definition, look in diagnosticLite.h.
57 
58 #if defined(doxygen)
59 
60 /// \addtogroup group_tf_Diagnostic
61 ///@{
62 
63 /// Issue an internal programming error, but continue execution.
64 ///
65 /// Please see \ref page_tf_TfError for more information about how to use
66 /// TF_ERROR().
67 ///
68 /// This is safe to call in secondary threads.
69 ///
70 /// \hideinitializer
71 #define TF_ERROR(...)
72 
73 /// Issue an internal programming error, but continue execution.
74 ///
75 /// This macro is a convenience. It produces a TF_ERROR() with an error code
76 /// indicating a coding error. It takes a printf-like format specification or a
77 /// std::string. Generally, an error handling delegate will take action to turn
78 /// this error into a python exception, and if it remains unhandled at the end of
79 /// an application iteration will roll-back the undo stack to a last-known-good
80 /// state.
81 ///
82 /// This is safe to call in secondary threads.
83 ///
84 /// \hideinitializer
85 #define TF_CODING_ERROR(fmt, args)
86 
87 /// Issue a generic runtime error, but continue execution.
88 ///
89 /// This macro is a convenience. It produces a TF_ERROR() with an error code
90 /// indicating a generic runtime error. It is preferred over TF_ERROR(0),
91 /// but using a specific error code is preferred over this. It takes a
92 /// printf-like format specification or a std::string. Generally, an error
93 /// handling delegate will take action to turn this error into a python
94 /// exception, and if it remains unhandled at the end of an application iteration
95 /// will roll-back the undo stack to a last-known-good state.
96 ///
97 /// This is safe to call in secondary threads.
98 ///
99 /// \hideinitializer
100 #define TF_RUNTIME_ERROR(fmt, args)
101 
102 /// Issue a fatal error and end the program.
103 ///
104 /// This macro takes a printf-like format specification or a std::string. The
105 /// program will generally terminate upon a fatal error.
106 ///
107 /// \hideinitializer
108 #define TF_FATAL_ERROR(fmt, args)
109 
110 /// Issue a warning, but continue execution.
111 ///
112 /// This macro works with a variety of argument sets. It supports simple
113 /// printf-like format specification or a std::string. It also supports
114 /// specification of a diagnostic code and a piece of arbitrary information in
115 /// the form of a TfDiagnosticInfo. The following is a full list of supported
116 /// argument lists:
117 ///
118 /// \code
119 /// TF_WARN(const char *) // plain old string
120 /// TF_WARN(const char *, ...) // printf like formatting
121 /// TF_WARN(std::string) // stl string
122 /// \endcode
123 ///
124 /// A diagnostic code can be passed in along with the warning message. See
125 /// \ref DiagnosticEnumConventions for an example of registering an enum type
126 /// and it's values as diagnostic codes.
127 ///
128 /// \code
129 /// TF_WARN(DIAGNOSTIC_ENUM, const char *)
130 /// TF_WARN(DIAGNOSTIC_ENUM, const char *, ...)
131 /// TF_WARN(DIAGNOSTIC_ENUM, std::string)
132 /// \endcode
133 ///
134 /// A piece of arbitrary data can also be passed in along with the diagnostic
135 /// code and warning message as follows:
136 ///
137 /// \code
138 /// TF_WARN(info, DIAGNOSTIC_ENUM, const char *)
139 /// TF_WARN(info, DIAGNOSTIC_ENUM, const char *, ...)
140 /// TF_WARN(info, DIAGNOSTIC_ENUM, std::string)
141 /// \endcode
142 ///
143 /// Generally, no adjustment to program state should occur as the result of
144 /// this macro. This is in contrast with errors as mentioned above.
145 ///
146 /// This is safe to call in secondary threads.
147 ///
148 /// \hideinitializer
149 #define TF_WARN(...)
150 
151 /// Issue a status message, but continue execution.
152 ///
153 /// This macro works with a variety of argument sets. It supports simple
154 /// printf-like format specification or a std::string. It also supports
155 /// specification of a diagnostic code and a piece of arbitrary information in
156 /// the form of a TfDiagnosticInfo. The following is a full list of supported
157 /// argument lists:
158 ///
159 /// \code
160 /// TF_STATUS(const char *) // plain old string
161 /// TF_STATUS(const char *, ...) // printf like formatting
162 /// TF_STATUS(std::string) // stl string
163 /// \endcode
164 ///
165 /// A diagnostic code can be passed in along with the status message. See
166 /// \ref DiagnosticEnumConventions for an example of registering an enum type
167 /// and it's values as diagnostic codes.
168 ///
169 /// \code
170 /// TF_STATUS(DIAGNOSTIC_ENUM, const char *)
171 /// TF_STATUS(DIAGNOSTIC_ENUM, const char *, ...)
172 /// TF_STATUS(DIAGNOSTIC_ENUM, std::string)
173 /// \endcode
174 ///
175 /// A piece of arbitrary data can also be passed in along with the diagnostic
176 /// code and status message as follows:
177 ///
178 /// \code
179 /// TF_STATUS(info, DIAGNOSTIC_ENUM, const char *)
180 /// TF_STATUS(info, DIAGNOSTIC_ENUM, const char *, ...)
181 /// TF_STATUS(info, DIAGNOSTIC_ENUM, std::string)
182 /// \endcode
183 ///
184 /// Generally, no adjustment to program state should occur as the result of
185 /// this macro. This is in contrast with errors as mentioned above.
186 ///
187 /// This is safe to call in secondary threads.
188 ///
189 /// \hideinitializer
190 #define TF_STATUS(...)
191 
192 /// Aborts if the condition \c cond is not met.
193 ///
194 /// \param cond is any expression convertible to bool; if the condition evaluates
195 /// to \c false, program execution ends with this call.
196 ///
197 /// Note that the diagnostic message sent is the code \c cond, in the form of
198 /// a string. Unless the condition expression is self-explanatory, use
199 /// \c TF_FATAL_ERROR(). See \ref DiagnosticTF_FATAL_ERROR for further
200 /// discussion.
201 ///
202 /// Currently, a \c TF_AXIOM() statement is not made a no-op in optimized
203 /// builds; however, it always possible that either (a) the axiom statement
204 /// might be removed at some point if the code is deemed correct or (b) in the
205 /// future, some flavor of build might choose to make axioms be no-ops. Thus,
206 /// programmers must make \e certain that the code in \p cond is entirely free
207 /// of side effects.
208 ///
209 /// \hideinitializer
210 #define TF_AXIOM(cond)
211 
212 /// The same as TF_AXIOM, but compiled only in dev builds.
213 ///
214 /// \param cond is any expression convertible to bool; if the condition evaluates
215 /// to \c false, program execution ends with this call.
216 ///
217 /// This macro has the same behavior as TF_AXIOM, but it is compiled only
218 /// in dev builds. This version should only be used in code that is
219 /// known (not just suspected!) to be performance critical.
220 ///
221 /// \hideinitializer
222 #define TF_DEV_AXIOM(cond)
223 
224 /// Checks a condition and reports an error if it evaluates false.
225 ///
226 /// This can be thought of as something like a softer, recoverable TF_AXIOM.
227 ///
228 /// The macro expands to an expression whose value is either true or false
229 /// depending on \c cond. If \c cond evaluates to false, issues a coding error
230 /// indicating the failure.
231 ///
232 /// \param cond is any expression convertible to bool.
233 ///
234 /// Usage generally follows patterns like these:
235 /// \code
236 /// // Simple check. This is like a non-fatal TF_AXIOM.
237 /// TF_VERIFY(condition);
238 ///
239 /// // Avoiding code that requires the condition be met.
240 /// if (TF_VERIFY(condition)) {
241 /// // code requiring condition be met.
242 /// }
243 ///
244 /// // Executing recovery code in case the condition is not met.
245 /// if (not TF_VERIFY(condition)) {
246 /// // recovery code to execute since condition was not met.
247 /// }
248 /// \endcode
249 ///
250 /// Here are some examples:
251 /// \code
252 /// // List should be empty. If not, issue an error, clear it out and continue.
253 /// if (not TF_VERIFY(list.empty()) {
254 /// // The list was unexpectedly not empty. TF_VERIFY will have
255 /// // issued a coding error with details. We clear the list and continue.
256 /// list.clear();
257 /// }
258 ///
259 /// // Only add to string if ptr is valid.
260 /// string result = ...;
261 /// if (TF_VERIFY(ptr != NULL)) {
262 /// result += ptr->Method();
263 /// }
264 /// \endcode
265 ///
266 /// The macro also optionally accepts printf-style arguments to generate a
267 /// message emitted in case the condition is not met. For example:
268 /// \code
269 /// if (not TF_VERIFY(index < size,
270 /// "Index out of bounds (%zu >= %zu)", index, size)) {
271 /// // Recovery code...
272 /// }
273 /// \endcode
274 ///
275 /// Unmet conditions generate TF_CODING_ERRORs by default, but setting the
276 /// environment variable TF_FATAL_VERIFY to 1 will make unmet conditions
277 /// generate TF_FATAL_ERRORs instead and abort the program. This is intended for
278 /// testing.
279 ///
280 /// This is safe to call in secondary threads.
281 ///
282 /// \hideinitializer
283 #define TF_VERIFY(cond [, format, ...])
284 
285 #endif /* defined(doxygen) */
286 
287 //
288 // The rest of this is seen by a regular compile (or doxygen).
289 //
290 
291 #if defined(__cplusplus) || defined(doxygen)
292 
293 /// Get the name of the current function as a \c std::string.
294 ///
295 /// This macro will return the name of the current function, nicely
296 /// formatted, as an \c std::string. This is meant primarily for
297 /// diagnostics. Code should not rely on a specific format, because it
298 /// may change in the future or vary across architectures. For example,
299 /// \code
300 /// void YourClass::SomeMethod(int x) {
301 /// cout << "Debugging info about function " << TF_FUNC_NAME() << "." << endl;
302 /// ...
303 /// }
304 /// \endcode
305 /// Should display something like:
306 /// "Debugging info about function YourClass::SomeMethod."
307 ///
308 /// \hideinitializer
309 #define TF_FUNC_NAME() \
310  ArchGetPrettierFunctionName(__ARCH_FUNCTION__, __ARCH_PRETTY_FUNCTION__)
311 
312 void Tf_TerminateHandler();
313 
314 #if !defined(doxygen)
315 
316 // Redefine these macros from DiagnosticLite to versions that will accept
317 // either string or printf-like args.
318 
319 #ifdef TF_CODING_ERROR
320 #undef TF_CODING_ERROR
321 #endif
322 #define TF_CODING_ERROR(...) \
323  Tf_PostErrorHelper(TF_CALL_CONTEXT, \
324  TF_DIAGNOSTIC_CODING_ERROR_TYPE, __VA_ARGS__)
325 
326 #ifdef TF_FATAL_CODING_ERROR
327 #undef TF_FATAL_CODING_ERROR
328 #endif
329 #define TF_FATAL_CODING_ERROR \
330  Tf_DiagnosticHelper(TF_CALL_CONTEXT, \
331  TF_DIAGNOSTIC_CODING_ERROR_TYPE).IssueFatalError
332 
333 
334 #ifdef TF_CODING_WARNING
335 #undef TF_CODING_WARNING
336 #endif
337 #define TF_CODING_WARNING(...) \
338  Tf_PostWarningHelper(TF_CALL_CONTEXT, \
339  TF_DIAGNOSTIC_CODING_ERROR_TYPE, __VA_ARGS__)
340 
341 #ifdef TF_DIAGNOSTIC_WARNING
342 #undef TF_DIAGNOSTIC_WARNING
343 #endif
344 #define TF_DIAGNOSTIC_WARNING \
345  Tf_DiagnosticHelper(TF_CALL_CONTEXT.Hide(), \
346  TF_DIAGNOSTIC_WARNING_TYPE).IssueWarning
347 
348 #ifdef TF_RUNTIME_ERROR
349 #undef TF_RUNTIME_ERROR
350 #endif // TF_RUNTIME_ERROR
351 #define TF_RUNTIME_ERROR(...) \
352  Tf_PostErrorHelper(TF_CALL_CONTEXT, \
353  TF_DIAGNOSTIC_RUNTIME_ERROR_TYPE, __VA_ARGS__)
354 
355 #ifdef TF_FATAL_ERROR
356 #undef TF_FATAL_ERROR
357 #endif // TF_FATAL_ERROR
358 #define TF_FATAL_ERROR \
359  Tf_DiagnosticHelper(TF_CALL_CONTEXT, \
360  TF_DIAGNOSTIC_FATAL_ERROR_TYPE).IssueFatalError
361 
362 #ifdef TF_DIAGNOSTIC_FATAL_ERROR
363 #undef TF_DIAGNOSTIC_FATAL_ERROR
364 #endif // TF_DIAGNOSTIC_FATAL_ERROR
365 #define TF_DIAGNOSTIC_FATAL_ERROR \
366  Tf_DiagnosticHelper(TF_CALL_CONTEXT, \
367  TF_DIAGNOSTIC_RUNTIME_ERROR_TYPE).IssueFatalError
368 
369 #ifdef TF_DIAGNOSTIC_NONFATAL_ERROR
370 #undef TF_DIAGNOSTIC_NONFATAL_ERROR
371 #endif // TF_DIAGNOSTIC_NONFATAL_ERROR
372 #define TF_DIAGNOSTIC_NONFATAL_ERROR \
373  Tf_DiagnosticHelper(TF_CALL_CONTEXT, \
374  TF_DIAGNOSTIC_WARNING_TYPE).IssueWarning
375 
376 // Redefine the following three macros from DiagnosticLite to versions that will
377 // accept the following sets of arguments:
378 // * MACRO(const char *, ...)
379 // * MACRO(const std::string &msg)
380 // * MACRO(ENUM, const char *, ...)
381 // * MACRO(ENUM, const std::string *msg)
382 // * MACRO(TfDiagnosticInfo, ENUM, const char *, ...)
383 // * MACRO(TfDiagnosticInfo, ENUM, const std::string *msg)
384 
385 #ifdef TF_WARN
386 #undef TF_WARN
387 #endif // TF_WARN
388 #define TF_WARN(...) \
389  Tf_PostWarningHelper(TF_CALL_CONTEXT, __VA_ARGS__)
390 
391 #ifdef TF_STATUS
392 #undef TF_STATUS
393 #endif // TF_STATUS
394 #define TF_STATUS(...) \
395  Tf_PostStatusHelper(TF_CALL_CONTEXT, __VA_ARGS__)
396 
397 #ifdef TF_ERROR
398 #undef TF_ERROR
399 #endif // TF_ERROR
400 #define TF_ERROR(...) \
401  Tf_PostErrorHelper(TF_CALL_CONTEXT, __VA_ARGS__)
402 
403 #ifdef TF_QUIET_ERROR
404 #undef TF_QUIET_ERROR
405 #endif // TF_ERROR
406 #define TF_QUIET_ERROR(...) \
407  Tf_PostQuietlyErrorHelper(TF_CALL_CONTEXT, __VA_ARGS__)
408 
409 // See documentation above.
410 #define TF_VERIFY(cond, ...) \
411  (ARCH_LIKELY(cond) ? true : \
412  Tf_FailedVerifyHelper(TF_CALL_CONTEXT, # cond, \
413  Tf_VerifyStringFormat(__VA_ARGS__)))
414 
415 // Helpers for TF_VERIFY.
416 TF_API bool
417 Tf_FailedVerifyHelper(TfCallContext const &context,
418  char const *condition, char const *msg);
419 
420 // Helpers for TF_VERIFY.
421 inline char const *
422 Tf_VerifyStringFormat() { return nullptr; }
423 TF_API char const *
424 Tf_VerifyStringFormat(const char *format, ...) ARCH_PRINTF_FUNCTION(1, 2);
425 
426 #endif // !doxygen
427 
428 #endif // __cplusplus || doxygen
429 
430 /// Sets program name for reporting errors.
431 ///
432 /// This function simply calls to ArchSetProgramNameForErrors().
433 void TfSetProgramNameForErrors(std::string const& programName);
434 
435 /// Returns currently set program info.
436 ///
437 /// This function simply calls to ArchGetProgramNameForErrors().
438 std::string TfGetProgramNameForErrors();
439 
440 /// \private
441 struct Tf_DiagnosticHelper {
442  Tf_DiagnosticHelper(TfCallContext const &context,
444  _context(context),
445  _type(type)
446  {
447  }
448 
449  TfCallContext const &GetContext() const { return _context; }
450  TfDiagnosticType GetType() const { return _type; }
451 
452  TF_API void IssueError(std::string const &msg) const;
453  TF_API void IssueError(char const *fmt, ...) const ARCH_PRINTF_FUNCTION(2,3);
454  TF_API void IssueFatalError(std::string const &msg) const;
455  TF_API void IssueFatalError(char const *fmt, ...) const ARCH_PRINTF_FUNCTION(2,3);
456  TF_API void IssueWarning(std::string const &msg) const;
457  TF_API void IssueWarning(char const *fmt, ...) const ARCH_PRINTF_FUNCTION(2,3);
458  TF_API void IssueStatus(std::string const &msg) const;
459  TF_API void IssueStatus(char const *fmt, ...) const ARCH_PRINTF_FUNCTION(2,3);
460 
461  private:
462  TfCallContext _context;
463  TfDiagnosticType _type;
464 };
465 
466 #endif
467 
468 /// (Re)install Tf's crash handler. This should not generally need to be
469 /// called since Tf does this itself when loaded. However, when run in 3rd
470 /// party environments that install their own signal handlers, possibly
471 /// overriding Tf's, this provides a way to reinstall them, in hopes that
472 /// they'll stick.
473 ///
474 /// This calls std::set_terminate() and installs signal handlers for SIGSEGV,
475 /// SIGBUS, SIGFPE, and SIGABRT.
476 TF_API
478 
479 ///@}
480 
482 
483 #endif // PXR_BASE_TF_DIAGNOSTIC_H
#define TF_API
Definition: api.h:40
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:108
TfDiagnosticType
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
TF_API void TfInstallTerminateAndCrashHandlers()
type
Definition: core.h:1059