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