Main Page   Modules   Compound List   File List   Compound Members   File Members  

gan_err_trace.h File Reference

#include <gandalf/common/gan_err.h>

Go to the source code of this file.

Compounds

struct  Gan_ErrorTrace
 Stores details of single error in an error trace. More...


Defines

#define GAN_ET_YES   0
 Values for the 'f_spare' and 'f_static_message' in the Gan_ErrorTrace structure.

#define GAN_ET_NO   1

Typedefs

typedef Gan_ErrorTrace Gan_ErrorTrace
 Stores details of single error in an error trace.


Functions

Gan_ErrorTracegan_et_push (Gan_ErrorTrace *et_top, const char *func_name, int err_code, const char *file_name, int line_number, const char *message)
 Pushes a new error recorded onto error trace.

int gan_et_get_record_count (Gan_ErrorTrace *et_record)
 Counts number of records in trace from specified starting point.

Gan_ErrorTracegan_et_get_record_next (Gan_ErrorTrace *et_record)
 Returns pointer to next non-spare error record after et_record.

Gan_ErrorTracegan_et_get_record_first (Gan_ErrorTrace *et_record)
 Returns pointer to first non-spare error record from et_record.

Gan_ErrorTracegan_et_flush_trace (Gan_ErrorTrace *et_record)
 Flush all errors in error trace.


Detailed Description

Module: Error trace

Part of: Gandalf Exception Handling

Revision: Last edited: Author:

Copyright: (c) 2000 Industrial Research Limited

Short Desc: Data structure and management functions for error trace Description: This module implements the error trace used in gan_err.[ch].

An error trace is a last-in first-out (LIFO) stack for temporarily holding details of multiple error events until an application is ready to read the stack.

The stack is usually flushed by the function in a sequence of nested calls that initially detects an error. As the call stack unwinds the successive functions also register errors, but they should not flush the error trace.

The stack is implemented as a linked list of error records. If in the process of allocating heap memory for a new error record a memory error occurs, then this is refered to as a deep error.

The stack always maintains two preallocated and unused error records for storing the details of the deep error and the error that was in the process of being registered when the deep error occured.

Even if the top of the stack holds a deep error record and the two preallocated records are used, new errors can still be registered into the trace. These attempts may lead to repeated deep errors, in which case the top deep error serves as an indicator of the deep continuing error state. However, if the registration process is successful (because in the intervening time, some external agent has free'd heap memory) the old deep error record is left on the stack and the new errors are registered on top of it.

To ensure that the stack has at least two preallocated records at process startup time, the bottom and second to bottom records of the stack use statically allocated memory. These can never be dynamically free'd.

To do this, an external module must define two static error records. In gan_err.c, this is implemented as:

Gan_ErrorTrace record_last = {NULL, GAN_ET_YES, GAN_ET_NO, GAN_ET_YES, NULL, GAN_EC_DFT_SPARE, NULL, 0,NULL}; Gan_ErrorTrace record_2nd_last = {&record_last, GAN_ET_YES, GAN_ET_NO, GAN_ET_YES, NULL,GAN_EC_DFT_SPARE, NULL,0,NULL};

Gan_ErrorTrace * gan_et_trace_top =

The symbol gan_et_trace_top refers to the current top of stack and is passed into the functions defined in this module as argument 1.

NB. A statically allocated string containing the deep error text message must also exist, but this is defined in gan_err_trace.c.


Function Documentation

Gan_ErrorTrace* gan_et_flush_trace Gan_ErrorTrace   a_record
 

Flush all errors in error trace.

Parameters:
a_record The top record in error trace
Returns:
Pointer to new top of error trace.
Flush all errors in error trace.
Warning:
et_record must be top record in trace, or else residual trace will malformed (i.e. not NULL terminated).
Note:
Traverse error trace from start to finish deleting all records, except leaving the final two which are reserved to store deep error information.
Don't free free_me, but mark it spare, and continue

int gan_et_get_record_count Gan_ErrorTrace   et_record
 

Counts number of records in trace from specified starting point.

Parameters:
et_record Pointer to top record of error trace
Returns:
The number of records in trace from and including et_record to bottom of trace.
Counts number of non-spare records in trace from and including et_record to the last (oldest) record in stack. Total number of non-spare records in error trace is returned when the top of error trace is specified by et_record.

Gan_ErrorTrace* gan_et_get_record_first Gan_ErrorTrace   et_record
 

Returns pointer to first non-spare error record from et_record.

Parameters:
et_record Pointer to error record in error trace for which error code is to be read.
Returns:
Error code of specified error record, or NULL if et_record is NULL, or no non-spare records found.
Returns pointer to first non-spare error record from and including et_record.

Gan_ErrorTrace* gan_et_get_record_next Gan_ErrorTrace   et_record
 

Returns pointer to next non-spare error record after et_record.

Parameters:
et_record Pointer to the Error record preceding the one that will be returned
Returns:
Returns pointer to next non-spare error record after et_record.
Warning:
If et_record is NULL, this function returns NULL.

Gan_ErrorTrace* gan_et_push Gan_ErrorTrace   et_top,
const char *    func_name,
int    err_code,
const char *    file_name,
int    line_number,
const char *    message
 

Pushes a new error recorded onto error trace.

Parameters:
et_top Pointer to top record of error trace
func_name Name of function in which error occurs
err_code Numeric code of error
file_name Name of file in which error occurs
line_number Line in file at which error occurs
message Message string describing error
Returns:
Pointer to new top of list.
Note:
A memory error may occur inside gan_et_push() because this function calls malloc(): this is called a deep error. Two records are reserved at the top of the trace to register the occurrence of a deep error (top) and to register the error (second to top) that identified by the error code (GAN_EC_DFT +.

A deep error is treated no differently from any other error, except that the reserved records are used. Therefore, even if the trace registers a deep error, gan_et_push() will attempt to register subsequent errors if memory allows. Each time a deep error occurs, gan_et_push() will attempt to register a deep error. Deep error that follow a normal error will always succeed in being registered. A deep error that follows a deep error may not succeed in being registered because of memory constraints -- however, the top of the trace will nevertheless show that the most recent error was a deep error. Errors requested to be registered while no system memory exists will be lost permanently.

The oldest two records of the LIFO stack are statically allocated. This ensures that at any time a deep error can be registered.

gan_et_push() or any other function in the exception handling module makes no attempt to free memory for the purpose of avoid a deep error. Memory management firmly rest with an external component (i.e. library or application). Such behaviour is consistent with the policy that the application (or library) is the master and the exception handling module is the slave. The role of the exception module is to provide full error information to the application, so that the application has the opportunity to handle the error in a contextually meaningful way.

The psuedo code for handling deep errors is as follows:

-----------------------------------------------------------------------

gan_et_push() Have 2 records spare? yes: register_error no: try to allocate records so that we have 2 spare on error: deep_error register_error

-----------------------------------------------------------------------

register_error() (into second spare) do the best to furnish info into 2nd spare record on error: leave the error message part blank deep_error() mark 2nd record as 'not spare' allocate a new record and put at top of stack on error: deep_error()

-----------------------------------------------------------------------

deep_error() Have 1 spare record (in which to write deep error) yes: write deep error into spare record no : do nothing, return


Generated on Mon Oct 13 16:14:41 2003 by doxygen1.3-rc1