1 2 3 4 5 6 7 8
9
10 11 12 13
14
15 /*!
16 * ======== Error ========
17 * Runtime error manager
18 *
19 * The `Error` module provides mechanisms for raising, checking, and
20 * handling errors in a program. You can configure it via the
21 * `{@link Error#policy Error.policy}` and
22 * `{@link Error#raiseHook Error.raiseHook}` configuration parameters.
23 *
24 * Modules may define specific error types and reference these when
25 * raising an error. Each error type has a custom error message and
26 * can be parameterized with up to `{@link #NUMARGS}` arguments. A
27 * generic error type is provided for raising errors when not in a module.
28 *
29 * Use the `{@link #check Error_check()}` function to determine if an
30 * error has been raised. It is important to understand that it is the
31 * caller's responsibility to check the error block after calling a
32 * function that takes an error block as an argument. Otherwise, a raised
33 * error may go undetected, which could compromise the integrity of the
34 * system. For example:
35 *
36 * @p(code)
37 * Task_create(..., &eb);
38 *
39 * if (Error_check(&eb)) {
40 * ...an error has been raised...
41 * }
42 * @p
43 *
44 * The `{@link #raiseHook Error.raiseHook}` configuration parameter allows
45 * a configured function to be invoked when any error is raised. This
46 * function is passed a pointer to the error's error block and makes it
47 * easy to manage all errors from a common point. For example, you can
48 * trap any error (fatal or not) by simply setting a breakpoint in this
49 * function. You can use the following functions to extract information
50 * from an error block.
51 *
52 * @p(blist)
53 * - `{@link #getData Error_getData()}`
54 * - `{@link #getCode Error_getCode()}`
55 * - `{@link #getId Error_getId()}`
56 * - `{@link #getMsg Error_getMsg()}`
57 * - `{@link #getSite Error_getSite()}`
58 * @p
59 *
60 * @a(Examples)
61 * Example 1: The following example shows how a module, named ModA,
62 * defines a custom error type and shows how this error is raised by
63 * the module. The module defines an `Id` of `E_notEven` in its module
64 * specification file (in this case, `ModA.xdc`). The error's message
65 * string takes only one argument. The module also defines a `mayFail()`
66 * function that takes an error block. In the module's C source file,
67 * the function checks for the error condition and raises the error if
68 * needed.
69 *
70 * This is part of ModA's XDC specification file for the module:
71 *
72 * @p(code)
73 * config xdc.runtime.Error.Id E_notEven = {
74 * msg: "expected an even number (%d)"
75 * };
76 *
77 * Void mayFail(Int x, xdc.runtime.Error.Block *eb);
78 * @p
79 *
80 * This is part of the C code for the module:
81 *
82 * @p(code)
83 * Void ModA_mayFail(Int x, Error_Block *eb)
84 * {
85 * if ((x % 2) != 0) {
86 * Error_raise(eb, ModA_E_notEven, x, 0);
87 * ...add error handling code here...
88 * return;
89 * }
90 * ...
91 * }
92 * @p
93 *
94 * @p(html)
95 * <hr />
96 * @p
97 *
98 * Example 2: The following C code supplies an error block to a function
99 * that requires one and tests the error block to see if the function
100 * raised an error. Note that an error block must be initialized before
101 * it can be used and same error block may be passed to several functions.
102 *
103 * @p(code)
104 * #include <xdc/runtime/Error.h>
105 * #include <ti/sysbios/knl/Task.h>
106 * Error_Block eb;
107 * Task_Handle tsk;
108 *
109 * Error_init(&eb);
110 * tsk = Task_create(..., &eb);
111 *
112 * if (Error_check(&eb)) {
113 * ...an error has been raised...
114 * }
115 * @p
116 *
117 * @p(html)
118 * <hr />
119 * @p
120 *
121 * Example 3: The following C code shows that you may pass `NULL` to a
122 * function requiring an error block. In this case, if the function
123 * raises an error, the program is aborted (via
124 * `{@link System#abort xdc_runtime_System_abort()}`), thus execution
125 * control will never return to the caller.
126 *
127 * @p(code)
128 * #include <xdc/runtime/Error.h>
129 * #include <ti/sysbios/knl/Task.h>
130 *
131 * tsk = Task_create(..., NULL);
132 * ...will never get here if an error was raised in Task_create...
133 * @p
134 *
135 * @p(html)
136 * <hr />
137 * @p
138 *
139 * Example 4: The following C code shows how to write a function that
140 * is not part of a module and that takes an error block and raises
141 * the generic error type provided by the Error module. Note, if the
142 * caller passes `NULL` for the error block or if the error policy is
143 * `{@link #TERMINATE}`, then the call to `{@link #raise Error_raise()}`
144 * will call `{@link System#abort xdc_runtime_System_abort()}` and never
145 * return.
146 *
147 * @p(code)
148 * #include <xdc/runtime/Error.h>
149 *
150 * Void myFunc(..., Error_Block *eb)
151 * {
152 * ...
153 *
154 * if (...error condition detected...) {
155 * String myErrorMsg = "my custom error message";
156 * Error_raise(eb, Error_E_generic, myErrorMsg, 0);
157 * ...add error handling code here...
158 * return;
159 * }
160 * }
161 * @p
162 */
163
164 module Error {
165
166 /*!
167 * ======== Policy ========
168 * Error handling policies
169 *
170 * Regardless of the current policy in use, raising an error by
171 * calling `{@link #raise Error_raise}` will always invoke the
172 * error raise hook function assigned to the
173 * `{@link #raiseHook Error.raiseHook}` configuration parameter.
174 *
175 * @field(TERMINATE) All raised errors are fatal. A call to
176 * `{@link #raise Error_raise}` will never return to the caller.
177 *
178 * @field(UNWIND) Errors are returned to the caller. A call to
179 * `{@link #raise Error_raise}` will return back to the caller.
180 */
181 enum Policy {
182 TERMINATE,
183 UNWIND
184 };
185
186 /*!
187 * ======== Desc ========
188 * Error descriptor
189 *
190 * Each type of error is defined with an error descriptor. This
191 * structure groups common information about the errors of this type.
192 *
193 * @field(msg) The error message using a printf style format string, but
194 * limited to `{@link #NUMARGS}` arguments.
195 *
196 * @field(code) A user assignable code, 0 by default. The user may
197 * optionally set this field during config to give the
198 * error a well-known numeric code. This is in addition
199 * to its well-known string name, which may not be
200 * available on the target.
201 */
202 metaonly struct Desc {
203 String msg;
204 UInt16 code;
205 };
206
207 /*!
208 * ======== Id ========
209 * Error identifier
210 *
211 * Each type of error raised is defined with a metaonly
212 * `{@link Error#Desc}`.
213 * An `Error_Id` is a 32-bit target value that encodes the information
214 * in the `Desc`. Target programs use `Error_Id` values to "raise" and
215 * check for specific errors.
216 *
217 * @a(Warning) `{@link #Id}` values may vary among different
218 * configurations of an application. For example, the addition of a
219 * new module to a program may result in a different absolute value for
220 * `{@link E_generic}`. If you need error numbers that remain
221 * invariant, use the user definable `{@link Desc#code}` field.
222 */
223 @Encoded typedef Desc Id;
224
225 /*!
226 * ======== NUMARGS ========
227 * Maximum number of arguments supported by an error.
228 */
229 const Int NUMARGS = 2;
230
231 /*!
232 * ======== Data ========
233 * Error args
234 *
235 * The two arguments (arg1, arg2) passed to `{@link #raise}` are
236 * stored in one of these arrays within the associated Error_Block.
237 * To access these arguments use `{@link #getData}` to obtain a
238 * pointer to the Error_Block's Data array.
239 *
240 * @see #getData
241 */
242 struct Data {
243 IArg arg[NUMARGS];
244 }
245
246 /*!
247 * ======== Block ========
248 * Error block
249 *
250 * An opaque structure used to store information about errors once raised.
251 * This structure must be initialized via `{@link #init Error_init()}`
252 * before being used for the first time.
253 */
254 @Opaque struct Block {
255 UInt16 unused;
256 Data data;
257 Id id;
258 String msg;
259 Types.Site site;
260 IArg xtra[4];
261 };
262
263 /*!
264 * ======== E_generic ========
265 * Generic error
266 */
267 config Id E_generic = {msg: "generic error: %s"};
268
269 /*!
270 * ======== E_memory ========
271 * Out of memory error
272 */
273 config Id E_memory = {msg: "out of memory: heap=0x%x, size=%u"};
274
275 /*!
276 * ======== policy ========
277 * System-wide error handling policy
278 */
279 config Policy policy = UNWIND;
280
281 /*!
282 * ======== raiseHook ========
283 * The function to call whenever an error is raised
284 *
285 * This function is always called when an error is raised, even if the
286 * Error policy is `{@link TERMINATE}`. In rare cases it is possible
287 * that a raised error does not trigger a call to `raiseHook`; see
288 * `{@link #maxDepth}`.
289 *
290 * @param(eb) non-`NULL` pointer to an `Error_Block`
291 *
292 * Even if the client passes a `NULL` error block pointer, this
293 * parameter is always `non-NULL`.
294 *
295 * @see #maxDepth
296 */
297 config Void (*raiseHook)(Block *) = Error.print;
298
299 /*!
300 * ======== maxDepth ========
301 * Maximum number of concurrent calls to `{@link #raiseHook}`
302 *
303 * To prevent errors that occur in the raiseHook function from
304 * causing an infinite recursion, the maximum number of concurrent
305 * calls to `{@link #raiseHook}` is limited by `Error_maxDepth`. If
306 * the number of concurrent calls exceeds `Error_maxDepth`, the
307 * `raiseHook` function is not called.
308 *
309 * In multi-threaded systems, errors raised by separate threads may
310 * be detected as recursive calls to `raiseHook`. So, setting
311 * `Error.maxDepth` to a small value may - in rare instances - result in
312 * `errorHook` not being called for some raised errors.
313 *
314 * If it is important that all raised errors trigger a call to the
315 * `raiseHook` function, set `Error.maxDepth` to an impossibly large
316 * number (0xffff) and either ensure that the raise hook never calls a
317 * function that can raise an error or add checks in `raiseHook` to
318 * protect against "double faults".
319 */
320 config UInt16 maxDepth = 16;
321
322 /*!
323 * ======== check ========
324 * Return TRUE if an error was raised
325 *
326 * @param(eb) pointer to an `Error_Block` or `NULL`
327 *
328 * @a(Returns)
329 * If `eb` is non-`NULL` and `{@link #policy Error.policy} == UNWIND` and
330 * an error was raised on `eb`, this function returns `TRUE`. Otherwise,
331 * it returns `FALSE`.
332 */
333 Bool check(Block *eb);
334
335 /*!
336 * ======== getData ========
337 * Get an error's argument list
338 *
339 * @param(eb) non-`NULL` pointer to an `Error_Block`
340 *
341 * @a(Returns)
342 * `getData` returns an array of type `{@link #Data}` with
343 * `{@link #NUMARGS}` elements containing the arguments provided
344 * at the time the error was raised.
345 *
346 * @see #raise
347 */
348 Data *getData(Block *eb);
349
350 /*!
351 * ======== getCode ========
352 * Get an error's code
353 *
354 * @param(eb) non-`NULL` pointer to an `Error_Block`
355 *
356 * @a(Returns)
357 * `getCode` returns the error code associated with this error block.
358 *
359 * @see #raise
360 * @see #Desc
361 */
362 UInt16 getCode(Block *eb);
363
364 /*!
365 * ======== getId ========
366 * Get an error's id
367 *
368 * @param(eb) non-`NULL` pointer to an `Error_Block`
369 *
370 * @a(Warning)
371 * `Error_Id` values may vary among different configurations
372 * of an application. For example, the addition of a new module to a
373 * program may result in a different absolute value for
374 * `{@link E_generic}`. If you need error numbers that remain
375 * invariant, use the user definable `{@link Desc#code}` field.
376 *
377 * @see #raise
378 * @see #Desc
379 */
380 Id getId(Block *eb);
381
382 /*!
383 * ======== getMsg ========
384 * Get an error's "printf" format string
385 *
386 * @param(eb) non-`NULL` pointer to an `Error_Block`
387 *
388 * @see #raise
389 * @see #Desc
390 */
391 String getMsg(Block *eb);
392
393 /*!
394 * ======== getSite ========
395 * Get an error's call site info
396 *
397 * @param(eb) non-`NULL` pointer to an `Error_Block`
398 *
399 * @a(Returns)
400 * `getSite` returns a pointer to an initialized
401 * `{@link Types#Site Types.Site}` structure. However, in the
402 * event that the call site was compiled with `xdc_FILE` defined to
403 * be `NULL` (to minimize string space overhead) the `file`
404 * field may be set to `NULL`.
405 *
406 * @see #raise
407 * @see #Desc
408 */
409 Types.Site *getSite(Block *eb);
410
411 /*!
412 * ======== idToCode ========
413 * Extract the code associated with an `Error_Id`
414 *
415 * @param(id) `Error_Id` from which to extract the user defined
416 * code
417 * @_nodoc
418 */
419 @Macro UInt16 idToCode(Id id);
420
421 /*!
422 * ======== init ========
423 * Put an error block into its initial state
424 *
425 * To ensure reliable error detection, clients must call `init` for
426 * an `Error_Block` prior to any use.
427 *
428 * If the same Error Block is used multiple times, only the last error
429 * raised is retained.
430 *
431 * @param(eb) pointer to an `Error_Block` or `NULL`
432 *
433 * If `eb` is `NULL` this function simply returns.
434 */
435 Void init(Block *eb);
436
437 /*!
438 * ======== print ========
439 * Print error using System.printf()
440 *
441 * This function prints the error using `System_printf()`. The output
442 * is on a single line terminated with a new line character and has the
443 * following form:
444 * @p(code)
445 * <site>: <file>, line <line_num>: <err_msg>
446 * @p
447 * where `<site>` is the module that raised the error, `<file>` and
448 * `<line_num>` are the file and line number of the containing the call
449 * site of the `Error_raise()`, and `<err_msg>` is the error message
450 * rendered with the arguments associated with the error.
451 *
452 * @param(eb) pointer to an `Error_Block` or `NULL`
453 *
454 * If `eb` is `NULL` this function simply returns with no output.
455 *
456 * @a(Warning)
457 * This function is not protected by a gate and, as a result,
458 * if two threads call this method concurrently, the output of the two
459 * calls will be intermingled. To prevent intermingled error output,
460 * you can either wrap all calls to this method with an appropriate
461 * `Gate_enter`/`Gate_leave` pair or simply ensure that only one
462 * thread in the system ever calls this method.
463 */
464 Void print(Block *eb);
465
466 /*!
467 * ======== raise ========
468 * Raise an error
469 *
470 * This function is used to raise an `Error` by writing call site,
471 * error ID, and error argument information into the `Error_Block`
472 * pointed to by `eb`.
473 *
474 * If `Error_raise` is called more than once on an `Error_Block` object,
475 * the previous error information is overwritten; only the last error
476 * is retained in the `Error_Block` object.
477 *
478 * In all cases, any configured `{@link #raiseHook Error.raiseHook}`
479 * function is called with a non-`NULL` pointer to a fully
480 * initialized `Error_Block` object.
481 *
482 * @param(eb) pointer to an `Error_Block` or `NULL`
483 *
484 * If `eb` is `NULL` or `{@link #policy Error.policy} == TERMINATE`,
485 * this function does not return to the caller; after calling any
486 * configured `{@link #raiseHook}`, `System_abort` is called with the
487 * string `"xdc.runtime.Error.raise: terminating execution\n"`.
488 *
489 * @param(id) the error to raise
490 *
491 * This pointer identifies the class of error being raised;
492 * the error class indicates how to interpret any subsequent
493 * arguments passed to `{@link #raise}`.
494 *
495 * @param(arg1) error's first argument
496 *
497 * The argument interprested by the first control character
498 * in the error message format string. It is ignored if not needed.
499 *
500 * @param(arg2) error's second argument
501 *
502 * The argument interpreted by the second control character
503 * in the error message format string. It is ignored if not needed.
504 */
505 @Macro Void raise(Block *eb, Id id, IArg arg1, IArg arg2);
506
507 /*! @_nodoc */
508 Void raiseX(Block *eb, Types.ModuleId mod, String file, Int line, Id id,
509 IArg arg1, IArg arg2);
510
511 internal:
512
513 struct Module_State {
514 UInt16 count;
515 };
516
517 }
518 519 520
521