1 2 3 4 5 6 7 8 9 10 11 12
13 14 15
16
17 /*!
18 * ======== Error ========
19 * Runtime error manager
20 *
21 * The `Error` module provides mechanisms for raising, checking, and
22 * handling errors in a program. You can configure it via the
23 * `{@link Error#policy Error.policy}` and
24 * `{@link Error#raiseHook Error.raiseHook}` configuration parameters.
25 *
26 * Modules may define specific error types and reference these when
27 * raising an error. Each error type has a custom error message and
28 * can be parameterized with up to `{@link #NUMARGS}` arguments. A
29 * generic error type is provided for raising errors when not in a module.
30 *
31 * Use the `{@link #check Error_check()}` function to determine if an
32 * error has been raised. It is important to understand that it is the
33 * caller's responsibility to check the error block after calling a
34 * function that takes an error block as an argument. Otherwise, a raised
35 * error may go undetected, which could compromise the integrity of the
36 * system. For example:
37 *
38 * @p(code)
39 * Task_create(..., &eb);
40 *
41 * if (Error_check(&eb)) {
42 * ...an error has been raised...
43 * }
44 * @p
45 *
46 * The `{@link #raiseHook Error.raiseHook}` configuration parameter allows
47 * a configured function to be invoked when any error is raised. This
48 * function is passed a pointer to the error's error block and makes it
49 * easy to manage all errors from a common point. For example, you can
50 * trap any error (fatal or not) by simply setting a breakpoint in this
51 * function. You can use the following functions to extract information
52 * from an error block.
53 *
54 * @p(blist)
55 * - `{@link #getData Error_getData()}`
56 * - `{@link #getCode Error_getCode()}`
57 * - `{@link #getId Error_getId()}`
58 * - `{@link #getMsg Error_getMsg()}`
59 * - `{@link #getSite Error_getSite()}`
60 * @p
61 *
62 * The Error module provides facilities for handling errors, but the Log
63 * module also provides features for logging error events. These are separate
64 * concepts; however, to ensure that users do not have to both raise and log
65 * an error, the Error module will automatically log an error event when one
66 * is raised. The Error module logs the standard {@link Log#L_error} event,
67 * passing it the error message and arguments.
68 *
69 * The error event is logged to the Error module's logger using the Error
70 * module's diags mask. Logging of errors is enabled by default in the diags
71 * mask, but the event will not be logged unless a logger is configured for
72 * the Error module as well.
73 *
74 * To make the error event appear as though it is coming from the module which
75 * called Error_raise, the event is logged with the caller's module id and
76 * with the caller's call site information.
77 *
78 * @a(Examples)
79 * Example 1: The following example shows how a module, named ModA,
80 * defines a custom error type and shows how this error is raised by
81 * the module. The module defines an `Id` of `E_notEven` in its module
82 * specification file (in this case, `ModA.xdc`). The error's message
83 * string takes only one argument. The module also defines a `mayFail()`
84 * function that takes an error block. In the module's C source file,
85 * the function checks for the error condition and raises the error if
86 * needed.
87 *
88 * This is part of ModA's XDC specification file for the module:
89 *
90 * @p(code)
91 * config xdc.runtime.Error.Id E_notEven = {
92 * msg: "expected an even number (%d)"
93 * };
94 *
95 * Void mayFail(Int x, xdc.runtime.Error.Block *eb);
96 * @p
97 *
98 * This is part of the C code for the module:
99 *
100 * @p(code)
101 * Void ModA_mayFail(Int x, Error_Block *eb)
102 * {
103 * if ((x % 2) != 0) {
104 * Error_raise(eb, ModA_E_notEven, x, 0);
105 * ...add error handling code here...
106 * return;
107 * }
108 * ...
109 * }
110 * @p
111 *
112 * @p(html)
113 * <hr />
114 * @p
115 *
116 * Example 2: The following C code supplies an error block to a function
117 * that requires one and tests the error block to see if the function
118 * raised an error. Note that an error block must be initialized before
119 * it can be used and same error block may be passed to several functions.
120 *
121 * @p(code)
122 * #include <xdc/runtime/Error.h>
123 * #include <ti/sysbios/knl/Task.h>
124 * Error_Block eb;
125 * Task_Handle tsk;
126 *
127 * Error_init(&eb);
128 * tsk = Task_create(..., &eb);
129 *
130 * if (Error_check(&eb)) {
131 * ...an error has been raised...
132 * }
133 * @p
134 *
135 * @p(html)
136 * <hr />
137 * @p
138 *
139 * Example 3: The following C code shows that you may pass `NULL` to a
140 * function requiring an error block. In this case, if the function
141 * raises an error, the program is aborted (via
142 * `{@link System#abort xdc_runtime_System_abort()}`), thus execution
143 * control will never return to the caller.
144 *
145 * @p(code)
146 * #include <xdc/runtime/Error.h>
147 * #include <ti/sysbios/knl/Task.h>
148 *
149 * tsk = Task_create(..., NULL);
150 * ...will never get here if an error was raised in Task_create...
151 * @p
152 *
153 * @p(html)
154 * <hr />
155 * @p
156 *
157 * Example 4: The following C code shows how to write a function that
158 * is not part of a module and that takes an error block and raises
159 * the generic error type provided by the Error module. Note, if the
160 * caller passes `NULL` for the error block or if the error policy is
161 * `{@link #Policy TERMINATE}`, then the call to
162 * `{@link #raise Error_raise()}` will call
163 * `{@link System#abort xdc_runtime_System_abort()}` and never return.
164 *
165 * @p(code)
166 * #include <xdc/runtime/Error.h>
167 *
168 * Void myFunc(..., Error_Block *eb)
169 * {
170 * ...
171 *
172 * if (...error condition detected...) {
173 * String myErrorMsg = "my custom error message";
174 * Error_raise(eb, Error_E_generic, myErrorMsg, 0);
175 * ...add error handling code here...
176 * return;
177 * }
178 * }
179 * @p
180 */
181 @DirectCall
182
183 module Error {
184
185 /*!
186 * ======== Policy ========
187 * Error handling policies
188 *
189 * Regardless of the current policy in use, raising an error by
190 * calling `{@link #raise Error_raise}` will always invoke the
191 * error raise hook function assigned to the
192 * `{@link #raiseHook Error.raiseHook}` configuration parameter.
193 *
194 * @field(TERMINATE) All raised errors are fatal. A call to
195 * `{@link #raise Error_raise}` will never return to the caller.
196 *
197 * @field(UNWIND) Errors are returned to the caller. A call to
198 * `{@link #raise Error_raise}` will return back to the caller.
199 */
200 enum Policy {
201 TERMINATE,
202 UNWIND
203 };
204
205 /*!
206 * ======== Desc ========
207 * Error descriptor
208 *
209 * Each type of error is defined with an error descriptor. This
210 * structure groups common information about the errors of this type.
211 *
212 * @field(msg) The error message using a `printf` style format string,
213 * but limited to `{@link #NUMARGS}` arguments.
214 * This format string together with the two arguments passed
215 * to `Error_raise`` are used to create a human readable
216 * error message.
217 *
218 * @field(code) A user assignable code, 0 by default. The user may
219 * optionally set this field during config to give the
220 * error a well-known numeric code.
221 */
222 metaonly struct Desc {
223 String msg;
224 UInt16 code;
225 };
226
227 /*!
228 * ======== Id ========
229 * Error identifier
230 *
231 * Each type of error raised is defined with a metaonly
232 * `{@link Error#Desc}`. An `Error_Id` is a 32-bit target value that
233 * encodes the information in the `Desc`. Target programs use
234 * `Error_Id` values to "raise" and check for specific errors.
235 *
236 * @a(Warning) `{@link #Id}` values may vary among different
237 * configurations of an application. For example, the addition of a
238 * new module to a program may result in a different absolute value for
239 * `{@link #E_generic}`. If you need error numbers that remain
240 * invariant, use the user definable `{@link #Desc Desc.code}` field.
241 */
242 @Encoded typedef Desc Id;
243
244 /*!
245 * ======== HookFxn ========
246 * Function called whenever an error is raised
247 *
248 * The first parameter and only parameter passed to this function is a
249 * pointer to an `Error_Block`. Even if the client passes a `NULL` error
250 * block pointer to `{@link #raise Error_raise}`, this parameter passed
251 * to this "hook" function is always `non-NULL`.
252 */
253 typedef Void (*HookFxn)(Block *);
254
255 /*!
256 * ======== NUMARGS ========
257 * Maximum number of arguments supported by an error
258 */
259 const Int NUMARGS = 2;
260
261 /*!
262 * ======== Data ========
263 * Error args
264 *
265 * The two arguments (arg1, arg2) passed to `{@link #raise}` are
266 * stored in one of these arrays within the associated Error_Block.
267 * To access these arguments use `{@link #getData}` to obtain a
268 * pointer to the Error_Block's Data array.
269 *
270 * @see #getData
271 */
272 struct Data {
273 IArg arg[NUMARGS];
274 }
275
276 /*!
277 * ======== Block ========
278 * Error block
279 *
280 * An opaque structure used to store information about errors once raised.
281 * This structure must be initialized via `{@link #init Error_init()}`
282 * before being used for the first time.
283 */
284 @Opaque struct Block {
285 UInt16 unused;
286 Data data;
287 Id id;
288 String msg;
289 Types.Site site;
290 IArg xtra[4];
291 };
292
293 /*!
294 * ======== PolicyFxn ========
295 * Error policy function signature
296 *
297 * @a(Parameters)
298 * A policy function is passed the following parameters:
299 * @p(dlist)
300 * - `eb`
301 * A pointer to an `{@link #Block Error_Block}` structure to be
302 * initialized using the subsequent arguments. This pointer may
303 * be `NULL`.
304 * - `modId`
305 * The module ID of the module calling
306 * `{@link #raise Error_raise()}`
307 * - `fileName`
308 * A string naming the source file which made the call to
309 * `{@link #raise Error_raise()}`
310 * - `lineNumber`
311 * An integer line number within the file named above where
312 * the call `{@link #raise Error_raise()}` occured
313 * - `errId`
314 * The `{@link #Id Error_Id}` of the error being raised
315 * - `arg1` and `arg2`
316 * Two `IArg` arguments associated with the error being raised
317 * @p
318 */
319 typedef Void (*PolicyFxn)(Block *, Types.ModuleId, CString, Int, Id,
320 IArg, IArg);
321
322 /*!
323 * ======== policyFxn ========
324 * Error handler function
325 *
326 * This function is called to handle all raised errors but, unlike
327 * `{@link raiseHook}`, this function is responsible for completely
328 * handling the error (including calling `{@link #raiseHook raiseHook}`
329 * with an appropriately initialized `{@link #Block Error_Block}`, if
330 * `raiseHook` functionality is required).
331 *
332 * The default value is a function which, in addition to calling `raiseHook`
333 * with an initialized `Error_Block` structure, logs the error using this
334 * module's logger.
335 *
336 * Alternately, `{@link #policySpin}`, which simply loops
337 * infinitely, can be used to minimize target footprint. Note, this function
338 * does NOT call `raiseHook`.
339 */
340 config PolicyFxn policyFxn = Error.policyDefault;
341
342 /*!
343 * ======== E_generic ========
344 * Generic error
345 *
346 * This error takes advantage of the $S specifier to allow for recursive
347 * formatting of the error message passed to error raise.
348 *
349 * For example, the following is possible:
350 * @p(code)
351 * Error_raise(eb, Error_E_generic, "Error occurred, code: %d", code);
352 * @p
353 *
354 * @see System#extendedFormats
355 * @see System#printf
356 */
357 config Id E_generic = {msg: "%$S"};
358
359 /*!
360 * ======== E_memory ========
361 * Out of memory error
362 *
363 * The first parameter must be the heap instance handle. The second
364 * parameter is the size of the object for which the allocation failed.
365 */
366 config Id E_memory = {msg: "out of memory: heap=0x%x, size=%u"};
367
368 /*!
369 * ======== E_msgCode ========
370 * Generic error that displays a string and a numeric value
371 */
372 config Id E_msgCode = {msg: "%s 0x%x"};
373
374 /*!
375 * ======== policy ========
376 * System-wide error handling policy
377 */
378 config Policy policy = UNWIND;
379
380 /*!
381 * ======== raiseHook ========
382 * The function to call whenever an error is raised
383 *
384 * If set to a non-`null` value, the referenced function is always
385 * called when an error is raised, even if the `Error` policy is
386 * `{@link #Policy TERMINATE}`. In rare cases, it is possible that a
387 * raised error does not trigger a call to `raiseHook`; see
388 * `{@link #maxDepth}`.
389 *
390 * By default, this function is set to `{@link #print Error_print}`
391 * which causes the error to be formatted and output via
392 * `{@link xdc.runtime.System#aprintf System_printf}`. Setting this
393 * configuration parameter to `null` indicates that no function hook
394 * should be called.
395 *
396 * @see #maxDepth
397 * @see #HookFxn
398 * @see #print
399 */
400 config HookFxn raiseHook = Error.print;
401
402 /*!
403 * ======== maxDepth ========
404 * Maximum number of concurrent calls to `{@link #raiseHook}`
405 *
406 * To prevent errors that occur in the raiseHook function from
407 * causing an infinite recursion, the maximum number of concurrent
408 * calls to `{@link #raiseHook}` is limited by `Error_maxDepth`. If
409 * the number of concurrent calls exceeds `Error_maxDepth`, the
410 * `raiseHook` function is not called.
411 *
412 * In multi-threaded systems, errors raised by separate threads may
413 * be detected as recursive calls to `raiseHook`. So, setting
414 * `Error.maxDepth` to a small value may - in rare instances - result in
415 * `errorHook` not being called for some raised errors.
416 *
417 * If it is important that all raised errors trigger a call to the
418 * `raiseHook` function, set `Error.maxDepth` to an impossibly large
419 * number (0xffff) and either ensure that the raise hook never calls a
420 * function that can raise an error or add checks in `raiseHook` to
421 * protect against "double faults".
422 */
423 config UInt16 maxDepth = 16;
424
425 /*!
426 * ======== check ========
427 * Return TRUE if an error was raised
428 *
429 * @param(eb) pointer to an `Error_Block` or `NULL`
430 *
431 * @a(returns)
432 * If `eb` is non-`NULL` and `{@link #policy Error.policy} == UNWIND` and
433 * an error was raised on `eb`, this function returns `TRUE`. Otherwise,
434 * it returns `FALSE`.
435 */
436 Bool check(Block *eb);
437
438 /*!
439 * ======== getData ========
440 * Get an error's argument list
441 *
442 * @param(eb) non-`NULL` pointer to an `Error_Block`
443 *
444 * @a(returns)
445 * `getData` returns an array of type `{@link #Data}` with
446 * `{@link #NUMARGS}` elements containing the arguments provided
447 * at the time the error was raised.
448 *
449 * @see #raise
450 */
451 Data *getData(Block *eb);
452
453 /*!
454 * ======== getCode ========
455 * Get an error's code
456 *
457 * @param(eb) non-`NULL` pointer to an `Error_Block`
458 *
459 * @a(returns)
460 * `getCode` returns the error code associated with this error block.
461 *
462 * @see #raise
463 * @see #Desc
464 */
465 UInt16 getCode(Block *eb);
466
467 /*!
468 * ======== getId ========
469 * Get an error's id
470 *
471 * @param(eb) non-`NULL` pointer to an `Error_Block`
472 *
473 * @a(Warning)
474 * `Error_Id` values may vary among different configurations
475 * of an application. For example, the addition of a new module to a
476 * program may result in a different absolute value for
477 * `{@link #E_generic}`. If you need error numbers that remain
478 * invariant, use the user definable `{@link #Desc Desc.code}` field.
479 *
480 * @see #raise
481 * @see #Desc
482 */
483 Id getId(Block *eb);
484
485 /*!
486 * ======== getMsg ========
487 * Get an error's "printf" format string
488 *
489 * @param(eb) non-`NULL` pointer to an `Error_Block`
490 *
491 * @see #raise
492 * @see #Desc
493 */
494 String getMsg(Block *eb);
495
496 /*!
497 * ======== getSite ========
498 * Get an error's call site info
499 *
500 * @param(eb) non-`NULL` pointer to an `Error_Block`
501 *
502 * @a(returns)
503 * `getSite` returns a pointer to an initialized
504 * `{@link Types#Site Types.Site}` structure. However, in the
505 * event that the call site was compiled with `xdc_FILE` defined to
506 * be `NULL` (to minimize string space overhead) the `file`
507 * field may be set to `NULL`.
508 *
509 * @see #raise
510 * @see #Desc
511 */
512 Types.Site *getSite(Block *eb);
513
514 /*!
515 * ======== idToCode ========
516 * Extract the user's error code associated with an `Error_Id`
517 *
518 * @param(id) `Error_Id` from which to extract the user defined
519 * code
520 * @_nodoc
521 */
522 @Macro UInt16 idToCode(Id id);
523
524 /*!
525 * ======== idToUid ========
526 * Extract the unique error id associated with an `Error_Id`
527 *
528 * @param(id) `Error_Id` from which to extract the system unique
529 * id associated with the specified `Error_Id`
530 * @_nodoc
531 */
532 @Macro UInt16 idToUid(Id id);
533
534 /*!
535 * ======== init ========
536 * Put an error block into its initial state
537 *
538 * To ensure reliable error detection, clients must call `init` for
539 * an `Error_Block` prior to any use.
540 *
541 * If the same Error Block is used multiple times, only the last error
542 * raised is retained.
543 *
544 * @param(eb) pointer to an `Error_Block` or `NULL`
545 *
546 * If `eb` is `NULL` this function simply returns.
547 */
548 Void init(Block *eb);
549
550 /*!
551 * ======== print ========
552 * Print error using System.printf()
553 *
554 * This function prints the error using `System_printf()`. The output
555 * is on a single line terminated with a new line character and has the
556 * following form:
557 * @p(code)
558 * <site>: <file>, line <line_num>: <err_msg>
559 * @p
560 * where `<site>` is the module that raised the error, `<file>` and
561 * `<line_num>` are the file and line number of the containing the call
562 * site of the `Error_raise()`, and `<err_msg>` is the error message
563 * rendered with the arguments associated with the error.
564 *
565 * @param(eb) pointer to an `Error_Block` or `NULL`
566 *
567 * If `eb` is `NULL` this function simply returns with no output.
568 *
569 * @a(Warning)
570 * This function is not protected by a gate and, as a result,
571 * if two threads call this method concurrently, the output of the two
572 * calls will be intermingled. To prevent intermingled error output,
573 * you can either wrap all calls to this method with an appropriate
574 * `Gate_enter`/`Gate_leave` pair or simply ensure that only one
575 * thread in the system ever calls this method.
576 */
577 Void print(Block *eb);
578
579 /*!
580 * ======== policyDefault ========
581 * Default implementation of the policyFxn
582 *
583 * This function is the implementation which is plugged in by default to
584 * the `{@link #policyFxn}`. It processes the error and logs it before
585 * returning to the caller or aborting - depending on the error policy
586 * `{@link #policy}`.
587 */
588 Void policyDefault(Block *eb, Types.ModuleId mod, CString file, Int line,
589 Id id, IArg arg1, IArg arg2);
590
591 /*!
592 * ======== policySpin ========
593 * Lightweight implementation of the policyFxn
594 *
595 * This function is a lightweight alternative which can be plugged in to
596 * the `{@link #policyFxn}`. It just loops infinitely.
597 *
598 * @a(Warning)
599 * This function does not call `{@link #raiseHook}` and never returns to
600 * the caller. As a result, ANY error raised by the application will cause
601 * it to indefinitly hang.
602 */
603 Void policySpin(Block *eb, Types.ModuleId mod, CString file, Int line,
604 Id id, IArg arg1, IArg arg2);
605
606 /*!
607 * ======== raise ========
608 * Raise an error
609 *
610 * This function is used to raise an `Error` by writing call site,
611 * error ID, and error argument information into the `Error_Block`
612 * pointed to by `eb`.
613 *
614 * If `Error_raise` is called more than once on an `Error_Block` object,
615 * the previous error information is overwritten; only the last error
616 * is retained in the `Error_Block` object.
617 *
618 * In all cases, any configured `{@link #raiseHook Error.raiseHook}`
619 * function is called with a non-`NULL` pointer to a fully
620 * initialized `Error_Block` object.
621 *
622 * @param(eb) pointer to an `Error_Block` or `NULL`
623 *
624 * If `eb` is `NULL` or `{@link #policy Error.policy} == TERMINATE`,
625 * this function does not return to the caller; after calling any
626 * configured `{@link #raiseHook}`, `System_abort` is called with the
627 * string `"xdc.runtime.Error.raise: terminating execution\n"`.
628 *
629 * @param(id) the error to raise
630 *
631 * This pointer identifies the class of error being raised;
632 * the error class indicates how to interpret any subsequent
633 * arguments passed to `{@link #raise}`.
634 *
635 * @param(arg1) error's first argument
636 *
637 * The argument interpreted by the first control character
638 * in the error message format string. It is ignored if not needed.
639 *
640 * @param(arg2) error's second argument
641 *
642 * The argument interpreted by the second control character
643 * in the error message format string. It is ignored if not needed.
644 */
645 @Macro Void raise(Block *eb, Id id, IArg arg1, IArg arg2);
646
647 /*! @_nodoc */
648 Void raiseX(Block *eb, Types.ModuleId mod, CString file, Int line,
649 Id id, IArg arg1, IArg arg2);
650
651 /*! @_nodoc EXPERIMENTAL */
652 Void setX(Block *eb, Types.ModuleId mod, CString file, Int line,
653 Id id, IArg arg1, IArg arg2);
654
655 internal:
656
657 struct Module_State {
658 UInt16 count;
659 };
660
661 }
662 663 664
665