1 /*
2 * Copyright (c) 2008 Texas Instruments. All rights reserved.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License
5 * v. 1.0 which accompanies this distribution. The Eclipse Public License is
6 * available at http://www.eclipse.org/legal/epl-v10.html and the Eclipse
7 * Distribution License is available at
8 * http://www.eclipse.org/org/documents/edl-v10.php.
9 *
10 * Contributors:
11 * Texas Instruments - initial implementation
12 * */
13 /*
14 * ======== Error.xdc ========
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
182 module Error {
183
184 /*!
185 * ======== Policy ========
186 * Error handling policies
187 *
188 * Regardless of the current policy in use, raising an error by
189 * calling `{@link #raise Error_raise}` will always invoke the
190 * error raise hook function assigned to the
191 * `{@link #raiseHook Error.raiseHook}` configuration parameter.
192 *
193 * @field(TERMINATE) All raised errors are fatal. A call to
194 * `{@link #raise Error_raise}` will never return to the caller.
195 *
196 * @field(UNWIND) Errors are returned to the caller. A call to
197 * `{@link #raise Error_raise}` will return back to the caller.
198 */
199 enum Policy {
200 TERMINATE,
201 UNWIND
202 };
203
204 /*!
205 * ======== Desc ========
206 * Error descriptor
207 *
208 * Each type of error is defined with an error descriptor. This
209 * structure groups common information about the errors of this type.
210 *
211 * @field(msg) The error message using a `printf` style format string,
212 * but limited to `{@link #NUMARGS}` arguments.
213 * This format string together with the two arguments passed
214 * to `Error_raise`` are used to create a human readable
215 * error message.
216 *
217 * @field(code) A user assignable code, 0 by default. The user may
218 * optionally set this field during config to give the
219 * error a well-known numeric code.
220 */
221 metaonlystruct Desc {
222 String msg;
223 UInt16 code;
224 };
225
226 /*!
227 * ======== Id ========
228 * Error identifier
229 *
230 * Each type of error raised is defined with a metaonly
231 * `{@link Error#Desc}`.
232 * An `Error_Id` is a 32-bit target value that encodes the information
233 * in the `Desc`. Target programs use `Error_Id` values to "raise" and
234 * 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 * ======== NUMARGS ========
246 * Maximum number of arguments supported by an error.
247 */
248 const Int NUMARGS = 2;
249
250 /*!
251 * ======== Data ========
252 * Error args
253 *
254 * The two arguments (arg1, arg2) passed to `{@link #raise}` are
255 * stored in one of these arrays within the associated Error_Block.
256 * To access these arguments use `{@link #getData}` to obtain a
257 * pointer to the Error_Block's Data array.
258 *
259 * @see #getData
260 */
261 struct Data {
262 IArg arg[NUMARGS];
263 }
264
265 /*!
266 * ======== Block ========
267 * Error block
268 *
269 * An opaque structure used to store information about errors once raised.
270 * This structure must be initialized via `{@link #init Error_init()}`
271 * before being used for the first time.
272 */
273 @Opaque struct Block {
274 UInt16 unused; /* for backward compatibility (was code) */
275 Data data; /* arguments passed to raise() */
276 Id id; /* id passed to raise() */
277 String msg; /* msg associated with id */
278 Types.Site site; /* info about Error_raise call site */
279 IArg xtra[4]; /* future expansion */
280 };
281
282 /*!
283 * ======== E_generic ========
284 * Generic error
285 *
286 * This error takes advantage of the $S specifier to allow for recursive
287 * formatting of the error message passed to error raise.
288 *
289 * For example, the following is possible:
290 * @p(code) 291 * Error_raise(eb, Error_E_generic, "Error occurred, code: %d", code);
292 * @p 293 *
294 * @see System#extendedFormats
295 * @see System#printf
296 */
297 config Id E_generic = {msg: "%$S"};
298
299 /*!
300 * ======== E_memory ========
301 * Out of memory error
302 *
303 * The first parameter must be the heap instance handle. The second
304 * parameter is the size of the object for which the allocation failed.
305 */
306 config Id E_memory = {msg: "out of memory: heap=0x%x, size=%u"};
307
308 /*!
309 * ======== E_msgCode ========
310 * Generic error that displays a string and a numeric value
311 */
312 config Id E_msgCode = {msg: "%s 0x%x"};
313
314 /*!
315 * ======== policy ========
316 * System-wide error handling policy
317 */
318 config Policy policy = UNWIND;
319
320 /*!
321 * ======== raiseHook ========
322 * The function to call whenever an error is raised
323 *
324 * This function is always called when an error is raised, even if the
325 * Error policy is `{@link #Policy TERMINATE}`. In rare cases it is
326 * possible that a raised error does not trigger a call to `raiseHook`;
327 * see `{@link #maxDepth}`.
328 *
329 * @param(eb) non-`NULL` pointer to an `Error_Block`
330 *
331 * Even if the client passes a `NULL` error block pointer, this
332 * parameter is always `non-NULL`.
333 *
334 * @see #maxDepth
335 */
336 config Void (*raiseHook)(Block *) = Error.print;
337
338 /*!
339 * ======== maxDepth ========
340 * Maximum number of concurrent calls to `{@link #raiseHook}`
341 *
342 * To prevent errors that occur in the raiseHook function from
343 * causing an infinite recursion, the maximum number of concurrent
344 * calls to `{@link #raiseHook}` is limited by `Error_maxDepth`. If
345 * the number of concurrent calls exceeds `Error_maxDepth`, the
346 * `raiseHook` function is not called.
347 *
348 * In multi-threaded systems, errors raised by separate threads may
349 * be detected as recursive calls to `raiseHook`. So, setting
350 * `Error.maxDepth` to a small value may - in rare instances - result in
351 * `errorHook` not being called for some raised errors.
352 *
353 * If it is important that all raised errors trigger a call to the
354 * `raiseHook` function, set `Error.maxDepth` to an impossibly large
355 * number (0xffff) and either ensure that the raise hook never calls a
356 * function that can raise an error or add checks in `raiseHook` to
357 * protect against "double faults".
358 */
359 config UInt16 maxDepth = 16;
360
361 /*!
362 * ======== check ========
363 * Return TRUE if an error was raised
364 *
365 * @param(eb) pointer to an `Error_Block` or `NULL`
366 *
367 * @a(returns) 368 * If `eb` is non-`NULL` and `{@link #policy Error.policy} == UNWIND` and
369 * an error was raised on `eb`, this function returns `TRUE`. Otherwise,
370 * it returns `FALSE`.
371 */
372 Bool check(Block *eb);
373
374 /*!
375 * ======== getData ========
376 * Get an error's argument list
377 *
378 * @param(eb) non-`NULL` pointer to an `Error_Block`
379 *
380 * @a(returns) 381 * `getData` returns an array of type `{@link #Data}` with
382 * `{@link #NUMARGS}` elements containing the arguments provided
383 * at the time the error was raised.
384 *
385 * @see #raise
386 */
387 Data *getData(Block *eb);
388
389 /*!
390 * ======== getCode ========
391 * Get an error's code
392 *
393 * @param(eb) non-`NULL` pointer to an `Error_Block`
394 *
395 * @a(returns) 396 * `getCode` returns the error code associated with this error block.
397 *
398 * @see #raise
399 * @see #Desc
400 */
401 UInt16 getCode(Block *eb);
402
403 /*!
404 * ======== getId ========
405 * Get an error's id
406 *
407 * @param(eb) non-`NULL` pointer to an `Error_Block`
408 *
409 * @a(Warning) 410 * `Error_Id` values may vary among different configurations
411 * of an application. For example, the addition of a new module to a
412 * program may result in a different absolute value for
413 * `{@link #E_generic}`. If you need error numbers that remain
414 * invariant, use the user definable `{@link #Desc Desc.code}` field.
415 *
416 * @see #raise
417 * @see #Desc
418 */
419 Id getId(Block *eb);
420
421 /*!
422 * ======== getMsg ========
423 * Get an error's "printf" format string
424 *
425 * @param(eb) non-`NULL` pointer to an `Error_Block`
426 *
427 * @see #raise
428 * @see #Desc
429 */
430 String getMsg(Block *eb);
431
432 /*!
433 * ======== getSite ========
434 * Get an error's call site info
435 *
436 * @param(eb) non-`NULL` pointer to an `Error_Block`
437 *
438 * @a(returns) 439 * `getSite` returns a pointer to an initialized
440 * `{@link Types#Site Types.Site}` structure. However, in the
441 * event that the call site was compiled with `xdc_FILE` defined to
442 * be `NULL` (to minimize string space overhead) the `file`
443 * field may be set to `NULL`.
444 *
445 * @see #raise
446 * @see #Desc
447 */
448 Types.Site *getSite(Block *eb);
449
450 /*!
451 * ======== idToCode ========
452 * Extract the code associated with an `Error_Id`
453 *
454 * @param(id) `Error_Id` from which to extract the user defined
455 * code
456 * @_nodoc 457 */
458 @Macro UInt16 idToCode(Id id);
459
460 /*!
461 * ======== init ========
462 * Put an error block into its initial state
463 *
464 * To ensure reliable error detection, clients must call `init` for
465 * an `Error_Block` prior to any use.
466 *
467 * If the same Error Block is used multiple times, only the last error
468 * raised is retained.
469 *
470 * @param(eb) pointer to an `Error_Block` or `NULL`
471 *
472 * If `eb` is `NULL` this function simply returns.
473 */
474 Void init(Block *eb);
475
476 /*!
477 * ======== print ========
478 * Print error using System.printf()
479 *
480 * This function prints the error using `System_printf()`. The output
481 * is on a single line terminated with a new line character and has the
482 * following form:
483 * @p(code) 484 * <site>: <file>, line <line_num>: <err_msg>
485 * @p 486 * where `<site>` is the module that raised the error, `<file>` and
487 * `<line_num>` are the file and line number of the containing the call
488 * site of the `Error_raise()`, and `<err_msg>` is the error message
489 * rendered with the arguments associated with the error.
490 *
491 * @param(eb) pointer to an `Error_Block` or `NULL`
492 *
493 * If `eb` is `NULL` this function simply returns with no output.
494 *
495 * @a(Warning) 496 * This function is not protected by a gate and, as a result,
497 * if two threads call this method concurrently, the output of the two
498 * calls will be intermingled. To prevent intermingled error output,
499 * you can either wrap all calls to this method with an appropriate
500 * `Gate_enter`/`Gate_leave` pair or simply ensure that only one
501 * thread in the system ever calls this method.
502 */
503 Void print(Block *eb);
504
505 /*!
506 * ======== raise ========
507 * Raise an error
508 *
509 * This function is used to raise an `Error` by writing call site,
510 * error ID, and error argument information into the `Error_Block`
511 * pointed to by `eb`.
512 *
513 * If `Error_raise` is called more than once on an `Error_Block` object,
514 * the previous error information is overwritten; only the last error
515 * is retained in the `Error_Block` object.
516 *
517 * In all cases, any configured `{@link #raiseHook Error.raiseHook}`
518 * function is called with a non-`NULL` pointer to a fully
519 * initialized `Error_Block` object.
520 *
521 * @param(eb) pointer to an `Error_Block` or `NULL`
522 *
523 * If `eb` is `NULL` or `{@link #policy Error.policy} == TERMINATE`,
524 * this function does not return to the caller; after calling any
525 * configured `{@link #raiseHook}`, `System_abort` is called with the
526 * string `"xdc.runtime.Error.raise: terminating execution\n"`.
527 *
528 * @param(id) the error to raise
529 *
530 * This pointer identifies the class of error being raised;
531 * the error class indicates how to interpret any subsequent
532 * arguments passed to `{@link #raise}`.
533 *
534 * @param(arg1) error's first argument
535 *
536 * The argument interpreted by the first control character
537 * in the error message format string. It is ignored if not needed.
538 *
539 * @param(arg2) error's second argument
540 *
541 * The argument interpreted by the second control character
542 * in the error message format string. It is ignored if not needed.
543 */
544 @Macro Void raise(Block *eb, Id id, IArg arg1, IArg arg2);
545
546 /*! @_nodoc */
547 Void raiseX(Block *eb, Types.ModuleId mod, String file, Int line, Id id,
548 IArg arg1, IArg arg2);
549
550 internal:
551
552 struct Module_State {
553 UInt16 count;
554 };
555
556 }
557 /*
558 * @(#) xdc.runtime; 2, 1, 0,288; 8-6-2010 17:20:29; /db/ztree/library/trees/xdc/xdc-v47x/src/packages/
559 */
560