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