1    /*
     2     *  Copyright 2008 by Texas Instruments Incorporated.
     3     *
     4     *  All rights reserved. Property of Texas Instruments Incorporated.
     5     *  Restricted rights to use, duplicate or disclose this code are
     6     *  granted through contract.
     7     *
     8     */
     9    
    10    /*
    11     *  ======== Error.xdc ========
    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;     /* for backward compatibility (was code) */
   256            Data        data;       /* arguments passed to raise() */
   257            Id          id;         /* id passed to raise() */
   258            String      msg;        /* msg associated with id */
   259            Types.Site  site;       /* info about Error_raise call site */
   260            IArg        xtra[4];    /* future expansion */
   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     *  @(#) xdc.runtime; 2, 0, 0, 0,123; 8-1-2008 14:41:03; /db/ztree/library/trees/xdc-s32x/src/packages/
   520     */
   521