#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_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. | |
int | gan_et_get_record_count (Gan_ErrorTrace *et_record) |
Counts number of records in trace from specified starting point. | |
Gan_ErrorTrace * | gan_et_get_record_next (Gan_ErrorTrace *et_record) |
Returns pointer to next non-spare error record after et_record. | |
Gan_ErrorTrace * | gan_et_get_record_first (Gan_ErrorTrace *et_record) |
Returns pointer to first non-spare error record from et_record. | |
Gan_ErrorTrace * | gan_et_flush_trace (Gan_ErrorTrace *et_record) |
Flush all errors in 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.
|
Flush all errors in error trace.
|
|
Counts number of records in trace from specified starting point.
|
|
Returns pointer to first non-spare error record from et_record.
|
|
Returns pointer to next non-spare error record after et_record.
|
|
Pushes a new error recorded onto error trace.
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 |