[AD] 4.3 error handling

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


While playing around with the sound code again, I thought it'd be nice if it 
had some error handling abilities. I came up with this in about 15 to 30 
minutes. I was just wondering if this is a good direction to put it in, or if 
you wanted something else. Here's the main code:

/****** Quick'n'dirty error API ******/

#include <setjmp.h>
#include <signal.h>
#include <stdio.h>

/* public */
typedef enum {
	AL_NO_ERROR       = 0,
	AL_INVALID_PARAM  = 1,
	AL_INVALID_OBJECT = 2,

	AL_GENERIC_ERROR  = 256
} AL_ERROR_ENUM;

AL_ERROR_ENUM al_get_last_error();
void al_enable_error_throws();
void al_disable_error_throws();
void al_error_throw(AL_ERROR_ENUM code);
AL_ERROR_ENUM al_get_last_error();

#define al_error_try \
if(!setjmp(*_al_get_next_jump_point())	\
{

#define al_error_catch \
	_al_clear_last_error_point();	\
}	\
else


/* internal */
jmp_buf *_al_get_next_jump_point();
void _al_clear_last_error_point();


/* source only */
static __thread AL_ERROR_ENUM _al_errcode;

static __thread size_t _al_num_jump_points;
static __thread jmp_buf _al_jump_points[16];

static __thread bool _al_throw_errors = true;


static void _unhandled_allegro_error()
{
    /* This would obviously use system-specific methods (popup box, whatever),
       with more proper cleanup */
    fprintf(stderr, "An unhandled error (code: %d) was caught!\nAborting\n", 
al_get_last_error());
    raise(SIGABRT);
}

static jmp_buf *get_last_jump_point()
{
    if(_al_num_jump_points == 0)
        _unhandled_allegro_error();
    return &_al_jump_points[--_al_num_jump_points];
}

jmp_buf *_al_get_next_jump_point()
{
    if(_al_num_jump_points >= 16)
        al_error_throw(AL_GENERIC_ERROR);
    return &_al_jump_points[_al_num_jump_points++];
}

void _al_clear_last_error_point()
{
    if(_al_num_jump_points == 0)
        _unhandled_allegro_error();
    --_al_num_jump_points;
}

void al_enable_error_throws()
{
    _al_throw_errors = true;
}

void al_disable_error_throws()
{
    _al_throw_errors = false;
}

void al_error_throw(AL_ERROR_ENUM code)
{
    _al_errcode = code;
    if(_al_throw_errors)
        longjmp(*get_last_jump_point(), code);
}

AL_ERROR_ENUM al_get_last_error()
{
    AL_ERROR_ENUM err = _al_errcode;
    _al_errcode = AL_NO_ERROR;
    return err;
}

/*************/

C99 defines __thread, and Windows has a similar specifier. So as you can see, 
it uses TLS, meaning seperate threads erroring won't conflict with each 
other. To use it, you have these methods:

** Method #1 (the lazy/newbie approach):
sound_driver = al_audio_init_driver(NULL);
/* Allegro will have SIGABRT'd by now if there was a problem,
   we can continue assuming everything's okay */
..more game code..

** Method #2 (the C++ approach):
al_error_try (
   sound_driver = al_audio_init_driver(NULL);
   ..more related code..
}
al_error_catch {
   AL_ERROR_ENUM code = al_get_last_error();
   /* We only handle invalid parameter errors */
   if(code != AL_INVALID_PARAM)
      al_error_throw(code);
   show_my_error("Could not init sound!");
}
..more game code..

** Method #3 (the C approach):
al_error_disable_throws();

sound_driver = al_audio_init_driver(NULL);
if(!sound_driver)
{
   AL_ERROR_ENUM code = al_get_last_error();
   if(code != AL_INVALID_PARAM)
   {
      al_error_enable_throws();
      al_error_throw(code);
   }
   show_my_error("Could not init sound!");
}

al_error_enable_throws();
..more game code..


So, what do you think? I kinda like it, but it may be too hacky for some 
people's tastes. I believe it's logically sound though, so it shouldn't cause 
problems..




Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/