[ 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..