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 @RomConsts
183
184 module Error {
185
186 /*!
187 * ======== Policy ========
188 * Error handling policies
189 *
190 * Regardless of the current policy in use, raising an error by
191 * calling `{@link #raise Error_raise}` will always invoke the
192 * error raise hook function assigned to the
193 * `{@link #raiseHook Error.raiseHook}` configuration parameter.
194 *
195 * @field(TERMINATE) All raised errors are fatal. A call to
196 * `{@link #raise Error_raise}` will never return to the caller.
197 *
198 * @field(UNWIND) Errors are returned to the caller. A call to
199 * `{@link #raise Error_raise}` will return back to the caller.
200 */
201 enum Policy {
202 TERMINATE,
203 UNWIND
204 };
205
206 /*!
207 * ======== Desc ========
208 * Error descriptor
209 *
210 * Each type of error is defined with an error descriptor. This
211 * structure groups common information about the errors of this type.
212 *
213 * @field(msg) The error message using a `printf` style format string,
214 * but limited to `{@link #NUMARGS}` arguments.
215 * This format string together with the two arguments passed
216 * to `Error_raise`` are used to create a human readable
217 * error message.
218 *
219 * @field(code) A user assignable code, 0 by default. The user may
220 * optionally set this field during config to give the
221 * error a well-known numeric code.
222 */
223 metaonly struct Desc {
224 String msg;
225 UInt16 code;
226 };
227
228 /*!
229 * ======== Id ========
230 * Error identifier
231 *
232 * Each type of error raised is defined with a metaonly
233 * `{@link Error#Desc}`. An `Error_Id` is a 32-bit target value that
234 * encodes the information in the `Desc`. Target programs use
235 * `Error_Id` values to "raise" and check for specific errors.
236 *
237 * @a(Warning) `{@link #Id}` values may vary among different
238 * configurations of an application. For example, the addition of a
239 * new module to a program may result in a different absolute value for
240 * `{@link #E_generic}`. If you need error numbers that remain
241 * invariant, use the user definable `{@link #Desc Desc.code}` field.
242 */
243 @Encoded typedef Desc Id;
244
245 /*!
246 * ======== HookFxn ========
247 * Function called whenever an error is raised
248 *
249 * The first parameter and only parameter passed to this function is a
250 * pointer to an `Error_Block`. Even if the client passes a `NULL` error
251 * block pointer to `{@link #raise Error_raise}`, this parameter passed
252 * to this "hook" function is always `non-NULL`.
253 */
254 typedef Void (*HookFxn)(Block *);
255
256 /*!
257 * ======== NUMARGS ========
258 * Maximum number of arguments supported by an error
259 */
260 const Int NUMARGS = 2;
261
262 /*!
263 * ======== Data ========
264 * Error args
265 *
266 * The two arguments (arg1, arg2) passed to `{@link #raise}` are
267 * stored in one of these arrays within the associated Error_Block.
268 * To access these arguments use `{@link #getData}` to obtain a
269 * pointer to the Error_Block's Data array.
270 *
271 * @see #getData
272 */
273 struct Data {
274 IArg arg[NUMARGS];
275 }
276
277 /*!
278 * ======== Block ========
279 * Error block
280 *
281 * An opaque structure used to store information about errors once raised.
282 * This structure must be initialized via `{@link #init Error_init()}`
283 * before being used for the first time.
284 */
285 @Opaque struct Block {
286 UInt16 unused;
287 Data data;
288 Id id;
289 String msg;
290 Types.Site site;
291 IArg xtra[4];
292 };
293
294 /*!
295 * ======== PolicyFxn ========
296 * Error policy function signature
297 *
298 * @a(Parameters)
299 * A policy function is passed the following parameters:
300 * @p(dlist)
301 * - `eb`
302 * A pointer to an `{@link #Block Error_Block}` structure to be
303 * initialized using the subsequent arguments. This pointer may
304 * be `NULL`.
305 * - `modId`
306 * The module ID of the module calling
307 * `{@link #raise Error_raise()}`
308 * - `fileName`
309 * A string naming the source file which made the call to
310 * `{@link #raise Error_raise()}`
311 * - `lineNumber`
312 * An integer line number within the file named above where
313 * the call `{@link #raise Error_raise()}` occured
314 * - `errId`
315 * The `{@link #Id Error_Id}` of the error being raised
316 * - `arg1` and `arg2`
317 * Two `IArg` arguments associated with the error being raised
318 * @p
319 */
320 typedef Void (*PolicyFxn)(Block *, Types.ModuleId, CString, Int, Id,
321 IArg, IArg);
322
323 /*!
324 * ======== policyFxn ========
325 * Error handler function
326 *
327 * This function is called to handle all raised errors but, unlike
328 * `{@link raiseHook}`, this function is responsible for completely
329 * handling the error (including calling `{@link #raiseHook raiseHook}`
330 * with an appropriately initialized `{@link #Block Error_Block}`, if
331 * `raiseHook` functionality is required).
332 *
333 * The default value is a function which, in addition to calling `raiseHook`
334 * with an initialized `Error_Block` structure, logs the error using this
335 * module's logger.
336 *
337 * Alternately, `{@link #policySpin}`, which simply loops
338 * infinitely, can be used to minimize target footprint. Note, this function
339 * does NOT call `raiseHook`.
340 */
341 config PolicyFxn policyFxn = Error.policyDefault;
342
343 /*!
344 * ======== E_generic ========
345 * Generic error
346 *
347 * This error takes advantage of the $S specifier to allow for recursive
348 * formatting of the error message passed to error raise.
349 *
350 * For example, the following is possible:
351 * @p(code)
352 * Error_raise(eb, Error_E_generic, "Error occurred, code: %d", code);
353 * @p
354 *
355 * @see System#extendedFormats
356 * @see System#printf
357 */
358 config Id E_generic = {msg: "%$S"};
359
360 /*!
361 * ======== E_memory ========
362 * Out of memory error
363 *
364 * The first parameter must be the heap instance handle. The second
365 * parameter is the size of the object for which the allocation failed.
366 */
367 config Id E_memory = {msg: "out of memory: heap=0x%x, size=%u"};
368
369 /*!
370 * ======== E_msgCode ========
371 * Generic error that displays a string and a numeric value
372 */
373 config Id E_msgCode = {msg: "%s 0x%x"};
374
375 /*!
376 * ======== policy ========
377 * System-wide error handling policy
378 */
379 config Policy policy = UNWIND;
380
381 /*!
382 * ======== raiseHook ========
383 * The function to call whenever an error is raised
384 *
385 * If set to a non-`null` value, the referenced function is always
386 * called when an error is raised, even if the `Error` policy is
387 * `{@link #Policy TERMINATE}`. In rare cases, it is possible that a
388 * raised error does not trigger a call to `raiseHook`; see
389 * `{@link #maxDepth}`.
390 *
391 * By default, this function is set to `{@link #print Error_print}`
392 * which causes the error to be formatted and output via
393 * `{@link xdc.runtime.System#aprintf System_printf}`. Setting this
394 * configuration parameter to `null` indicates that no function hook
395 * should be called.
396 *
397 * @see #maxDepth
398 * @see #HookFxn
399 * @see #print
400 */
401 config HookFxn raiseHook = Error.print;
402
403 /*!
404 * ======== maxDepth ========
405 * Maximum number of concurrent calls to `{@link #raiseHook}`
406 *
407 * To prevent errors that occur in the raiseHook function from
408 * causing an infinite recursion, the maximum number of concurrent
409 * calls to `{@link #raiseHook}` is limited by `Error_maxDepth`. If
410 * the number of concurrent calls exceeds `Error_maxDepth`, the
411 * `raiseHook` function is not called.
412 *
413 * In multi-threaded systems, errors raised by separate threads may
414 * be detected as recursive calls to `raiseHook`. So, setting
415 * `Error.maxDepth` to a small value may - in rare instances - result in
416 * `errorHook` not being called for some raised errors.
417 *
418 * If it is important that all raised errors trigger a call to the
419 * `raiseHook` function, set `Error.maxDepth` to an impossibly large
420 * number (0xffff) and either ensure that the raise hook never calls a
421 * function that can raise an error or add checks in `raiseHook` to
422 * protect against "double faults".
423 */
424 config UInt16 maxDepth = 16;
425
426 /*!
427 * ======== check ========
428 * Return TRUE if an error was raised
429 *
430 * @param(eb) pointer to an `Error_Block` or `NULL`
431 *
432 * @a(returns)
433 * If `eb` is non-`NULL` and `{@link #policy Error.policy} == UNWIND` and
434 * an error was raised on `eb`, this function returns `TRUE`. Otherwise,
435 * it returns `FALSE`.
436 */
437 Bool check(Block *eb);
438
439 /*!
440 * ======== getData ========
441 * Get an error's argument list
442 *
443 * @param(eb) non-`NULL` pointer to an `Error_Block`
444 *
445 * @a(returns)
446 * `getData` returns an array of type `{@link #Data}` with
447 * `{@link #NUMARGS}` elements containing the arguments provided
448 * at the time the error was raised.
449 *
450 * @see #raise
451 */
452 Data *getData(Block *eb);
453
454 /*!
455 * ======== getCode ========
456 * Get an error's code
457 *
458 * @param(eb) non-`NULL` pointer to an `Error_Block`
459 *
460 * @a(returns)
461 * `getCode` returns the error code associated with this error block.
462 *
463 * @see #raise
464 * @see #Desc
465 */
466 UInt16 getCode(Block *eb);
467
468 /*!
469 * ======== getId ========
470 * Get an error's id
471 *
472 * @param(eb) non-`NULL` pointer to an `Error_Block`
473 *
474 * @a(Warning)
475 * `Error_Id` values may vary among different configurations
476 * of an application. For example, the addition of a new module to a
477 * program may result in a different absolute value for
478 * `{@link #E_generic}`. If you need error numbers that remain
479 * invariant, use the user definable `{@link #Desc Desc.code}` field.
480 *
481 * @see #raise
482 * @see #Desc
483 */
484 Id getId(Block *eb);
485
486 /*!
487 * ======== getMsg ========
488 * Get an error's "printf" format string
489 *
490 * @param(eb) non-`NULL` pointer to an `Error_Block`
491 *
492 * @see #raise
493 * @see #Desc
494 */
495 String getMsg(Block *eb);
496
497 /*!
498 * ======== getSite ========
499 * Get an error's call site info
500 *
501 * @param(eb) non-`NULL` pointer to an `Error_Block`
502 *
503 * @a(returns)
504 * `getSite` returns a pointer to an initialized
505 * `{@link Types#Site Types.Site}` structure. However, in the
506 * event that the call site was compiled with `xdc_FILE` defined to
507 * be `NULL` (to minimize string space overhead) the `file`
508 * field may be set to `NULL`.
509 *
510 * @see #raise
511 * @see #Desc
512 */
513 Types.Site *getSite(Block *eb);
514
515 /*!
516 * ======== idToCode ========
517 * Extract the user's error code associated with an `Error_Id`
518 *
519 * @param(id) `Error_Id` from which to extract the user defined
520 * code
521 * @_nodoc
522 */
523 @Macro UInt16 idToCode(Id id);
524
525 /*!
526 * ======== idToUid ========
527 * Extract the unique error id associated with an `Error_Id`
528 *
529 * @param(id) `Error_Id` from which to extract the system unique
530 * id associated with the specified `Error_Id`
531 * @_nodoc
532 */
533 @Macro UInt16 idToUid(Id id);
534
535 /*!
536 * ======== init ========
537 * Put an error block into its initial state
538 *
539 * To ensure reliable error detection, clients must call `init` for
540 * an `Error_Block` prior to any use.
541 *
542 * If the same Error Block is used multiple times, only the last error
543 * raised is retained.
544 *
545 * @param(eb) pointer to an `Error_Block` or `NULL`
546 *
547 * If `eb` is `NULL` this function simply returns.
548 */
549 Void init(Block *eb);
550
551 /*!
552 * ======== print ========
553 * Print error using System.printf()
554 *
555 * This function prints the error using `System_printf()`. The output
556 * is on a single line terminated with a new line character and has the
557 * following form:
558 * @p(code)
559 * <site>: <file>, line <line_num>: <err_msg>
560 * @p
561 * where `<site>` is the module that raised the error, `<file>` and
562 * `<line_num>` are the file and line number of the containing the call
563 * site of the `Error_raise()`, and `<err_msg>` is the error message
564 * rendered with the arguments associated with the error.
565 *
566 * @param(eb) pointer to an `Error_Block` or `NULL`
567 *
568 * If `eb` is `NULL` this function simply returns with no output.
569 *
570 * @a(Warning)
571 * This function is not protected by a gate and, as a result,
572 * if two threads call this method concurrently, the output of the two
573 * calls will be intermingled. To prevent intermingled error output,
574 * you can either wrap all calls to this method with an appropriate
575 * `Gate_enter`/`Gate_leave` pair or simply ensure that only one
576 * thread in the system ever calls this method.
577 */
578 Void print(Block *eb);
579
580 /*!
581 * ======== policyDefault ========
582 * Default implementation of the policyFxn
583 *
584 * This function is the implementation which is plugged in by default to
585 * the `{@link #policyFxn}`. It processes the error and logs it before
586 * returning to the caller or aborting - depending on the error policy
587 * `{@link #policy}`.
588 */
589 Void policyDefault(Block *eb, Types.ModuleId mod, CString file, Int line,
590 Id id, IArg arg1, IArg arg2);
591
592 /*!
593 * ======== policySpin ========
594 * Lightweight implementation of the policyFxn
595 *
596 * This function is a lightweight alternative which can be plugged in to
597 * the `{@link #policyFxn}`. It just loops infinitely.
598 *
599 * @a(Warning)
600 * This function does not call `{@link #raiseHook}` and never returns to
601 * the caller. As a result, ANY error raised by the application will cause
602 * it to indefinitly hang.
603 */
604 Void policySpin(Block *eb, Types.ModuleId mod, CString file, Int line,
605 Id id, IArg arg1, IArg arg2);
606
607 /*!
608 * ======== raise ========
609 * Raise an error
610 *
611 * This function is used to raise an `Error` by writing call site,
612 * error ID, and error argument information into the `Error_Block`
613 * pointed to by `eb`.
614 *
615 * If `Error_raise` is called more than once on an `Error_Block` object,
616 * the previous error information is overwritten; only the last error
617 * is retained in the `Error_Block` object.
618 *
619 * In all cases, any configured `{@link #raiseHook Error.raiseHook}`
620 * function is called with a non-`NULL` pointer to a fully
621 * initialized `Error_Block` object.
622 *
623 * @param(eb) pointer to an `Error_Block` or `NULL`
624 *
625 * If `eb` is `NULL` or `{@link #policy Error.policy} == TERMINATE`,
626 * this function does not return to the caller; after calling any
627 * configured `{@link #raiseHook}`, `System_abort` is called with the
628 * string `"xdc.runtime.Error.raise: terminating execution\n"`.
629 *
630 * @param(id) the error to raise
631 *
632 * This pointer identifies the class of error being raised;
633 * the error class indicates how to interpret any subsequent
634 * arguments passed to `{@link #raise}`.
635 *
636 * @param(arg1) error's first argument
637 *
638 * The argument interpreted by the first control character
639 * in the error message format string. It is ignored if not needed.
640 *
641 * @param(arg2) error's second argument
642 *
643 * The argument interpreted by the second control character
644 * in the error message format string. It is ignored if not needed.
645 */
646 @Macro Void raise(Block *eb, Id id, IArg arg1, IArg arg2);
647
648 /*! @_nodoc */
649 Void raiseX(Block *eb, Types.ModuleId mod, CString file, Int line,
650 Id id, IArg arg1, IArg arg2);
651
652 /*! @_nodoc EXPERIMENTAL */
653 Void setX(Block *eb, Types.ModuleId mod, CString file, Int line,
654 Id id, IArg arg1, IArg arg2);
655
656 internal:
657
658 struct Module_State {
659 UInt16 count;
660 };
661
662 }
663 664 665
666