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