Get rid of setjmp/longjmp for error handling in favor of exceptions.

Fatalerror now maps to throwing an exception. Requires a full
recompile.
This commit is contained in:
Aaron Giles 2010-01-04 07:05:53 +00:00
parent 7e88358737
commit 200b21dff7
4 changed files with 167 additions and 120 deletions

View File

@ -20,6 +20,7 @@
#include "romload.h" #include "romload.h"
#include "sound/samples.h" #include "sound/samples.h"
#include <new>
#include <ctype.h> #include <ctype.h>
#ifdef MESS #ifdef MESS
@ -111,67 +112,89 @@ static const options_entry cli_options[] =
int cli_execute(int argc, char **argv, const options_entry *osd_options) int cli_execute(int argc, char **argv, const options_entry *osd_options)
{ {
core_options *options; core_options *options = NULL;
astring *gamename = astring_alloc(); astring *gamename = astring_alloc();
astring *exename = astring_alloc(); astring *exename = astring_alloc();
const char *gamename_option; const char *gamename_option;
const game_driver *driver; const game_driver *driver;
int result; int result = MAMERR_FATALERROR;
/* initialize the options manager and add the CLI-specific options */ try
options = mame_options_init(osd_options);
options_add_entries(options, cli_options);
/* parse the command line first; if we fail here, we're screwed */
if (options_parse_command_line(options, argc, argv, OPTION_PRIORITY_CMDLINE))
{ {
result = MAMERR_INVALID_CONFIG; /* initialize the options manager and add the CLI-specific options */
goto error; options = mame_options_init(osd_options);
options_add_entries(options, cli_options);
/* parse the command line first; if we fail here, we're screwed */
if (options_parse_command_line(options, argc, argv, OPTION_PRIORITY_CMDLINE))
{
result = MAMERR_INVALID_CONFIG;
goto error;
}
/* parse the simple commmands before we go any further */
core_filename_extract_base(exename, argv[0], TRUE);
result = execute_simple_commands(options, astring_c(exename));
if (result != -1)
goto error;
/* find out what game we might be referring to */
gamename_option = options_get_string(options, OPTION_GAMENAME);
core_filename_extract_base(gamename, gamename_option, TRUE);
driver = driver_get_name(astring_c(gamename));
/* execute any commands specified */
result = execute_commands(options, astring_c(exename), driver);
if (result != -1)
goto error;
/* if we don't have a valid driver selected, offer some suggestions */
if (strlen(gamename_option) > 0 && driver == NULL)
{
const game_driver *matches[10];
int drvnum;
/* get the top 10 approximate matches */
driver_list_get_approx_matches(drivers, gamename_option, ARRAY_LENGTH(matches), matches);
/* print them out */
fprintf(stderr, "\n\"%s\" approximately matches the following\n"
"supported " GAMESNOUN " (best match first):\n\n", gamename_option);
for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++)
if (matches[drvnum] != NULL)
fprintf(stderr, "%-18s%s\n", matches[drvnum]->name, matches[drvnum]->description);
/* exit with an error */
result = MAMERR_NO_SUCH_GAME;
goto error;
}
/* run the game */
result = mame_execute(options);
} }
catch (emu_fatalerror &fatal)
/* parse the simple commmands before we go any further */
core_filename_extract_base(exename, argv[0], TRUE);
result = execute_simple_commands(options, astring_c(exename));
if (result != -1)
goto error;
/* find out what game we might be referring to */
gamename_option = options_get_string(options, OPTION_GAMENAME);
core_filename_extract_base(gamename, gamename_option, TRUE);
driver = driver_get_name(astring_c(gamename));
/* execute any commands specified */
result = execute_commands(options, astring_c(exename), driver);
if (result != -1)
goto error;
/* if we don't have a valid driver selected, offer some suggestions */
if (strlen(gamename_option) > 0 && driver == NULL)
{ {
const game_driver *matches[10]; fprintf(stderr, "%s\n", fatal.string());
int drvnum; if (fatal.exitcode() != 0)
result = fatal.exitcode();
/* get the top 10 approximate matches */ }
driver_list_get_approx_matches(drivers, gamename_option, ARRAY_LENGTH(matches), matches); catch (emu_exception &exception)
{
/* print them out */ fprintf(stderr, "Caught unhandled emulator exception\n");
fprintf(stderr, "\n\"%s\" approximately matches the following\n" }
"supported " GAMESNOUN " (best match first):\n\n", gamename_option); catch (std::bad_alloc &)
for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++) {
if (matches[drvnum] != NULL) fprintf(stderr, "Out of memory!\n");
fprintf(stderr, "%-18s%s\n", matches[drvnum]->name, matches[drvnum]->description); }
catch (...)
/* exit with an error */ {
result = MAMERR_NO_SUCH_GAME; fprintf(stderr, "Caught unhandled exception\n");
goto error;
} }
/* run the game */
result = mame_execute(options);
error: error:
/* free our options and exit */ /* free our options and exit */
options_free(options); if (options != NULL)
options_free(options);
astring_free(gamename); astring_free(gamename);
astring_free(exename); astring_free(exename);
return result; return result;

View File

@ -133,11 +133,11 @@ int config_load_settings(running_machine *machine)
astring_free(fname); astring_free(fname);
if (filerr != FILERR_NONE) if (filerr != FILERR_NONE)
fatalerror("Could not load controller file %s.cfg", controller); throw emu_fatalerror("Could not load controller file %s.cfg", controller);
/* load the XML */ /* load the XML */
if (!config_load_xml(machine, file, CONFIG_TYPE_CONTROLLER)) if (!config_load_xml(machine, file, CONFIG_TYPE_CONTROLLER))
fatalerror("Could not load controller file %s.cfg", controller); throw emu_fatalerror("Could not load controller file %s.cfg", controller);
mame_fclose(file); mame_fclose(file);
} }

View File

@ -19,7 +19,6 @@
mame_execute() [mame.c] mame_execute() [mame.c]
- calls mame_validitychecks() [validity.c] to perform validity checks on all compiled drivers - calls mame_validitychecks() [validity.c] to perform validity checks on all compiled drivers
- calls setjmp to prepare for deep error handling
- begins resource tracking (level 1) - begins resource tracking (level 1)
- calls create_machine [mame.c] to initialize the running_machine structure - calls create_machine [mame.c] to initialize the running_machine structure
- calls init_machine() [mame.c] - calls init_machine() [mame.c]
@ -87,8 +86,8 @@
#include "streams.h" #include "streams.h"
#include "debug/debugcon.h" #include "debug/debugcon.h"
#include <new>
#include <stdarg.h> #include <stdarg.h>
#include <setjmp.h>
#include <time.h> #include <time.h>
@ -153,10 +152,6 @@ struct _mame_private
region_info * regionlist; region_info * regionlist;
tagmap * regionmap; tagmap * regionmap;
/* error recovery and exiting */
jmp_buf fatal_error_jmpbuf;
int fatal_error_jmpbuf_valid;
/* random number seed */ /* random number seed */
UINT32 rand_seed; UINT32 rand_seed;
@ -298,10 +293,8 @@ int mame_execute(core_options *options)
init_resource_tracking(); init_resource_tracking();
/* use setjmp/longjmp for deep error recovery */ /* use try/catch for deep error recovery */
mame->fatal_error_jmpbuf_valid = TRUE; try
error = setjmp(mame->fatal_error_jmpbuf);
if (error == 0)
{ {
int settingsloaded; int settingsloaded;
@ -372,7 +365,23 @@ int mame_execute(core_options *options)
nvram_save(machine); nvram_save(machine);
config_save_settings(machine); config_save_settings(machine);
} }
mame->fatal_error_jmpbuf_valid = FALSE; catch (emu_fatalerror &fatal)
{
mame_printf_error("%s\n", fatal.string());
error = MAMERR_FATALERROR;
if (fatal.exitcode() != 0)
error = fatal.exitcode();
}
catch (emu_exception &exception)
{
mame_printf_error("Caught unhandled emulator exception\n");
error = MAMERR_FATALERROR;
}
catch (std::bad_alloc &)
{
mame_printf_error("Out of memory!\n");
error = MAMERR_FATALERROR;
}
/* call all exit callbacks registered */ /* call all exit callbacks registered */
for (cb = mame->exit_callback_list; cb; cb = cb->next) for (cb = mame->exit_callback_list; cb; cb = cb->next)
@ -1119,56 +1128,6 @@ void mame_printf_log(const char *format, ...)
MISCELLANEOUS MISCELLANEOUS
***************************************************************************/ ***************************************************************************/
/*-------------------------------------------------
fatalerror - print a message and escape back
to the OSD layer
-------------------------------------------------*/
DECL_NORETURN static void fatalerror_common(running_machine *machine, int exitcode, const char *buffer) ATTR_NORETURN;
static void fatalerror_common(running_machine *machine, int exitcode, const char *buffer)
{
/* output and return */
mame_printf_error("%s\n", giant_string_buffer);
/* break into the debugger if attached */
osd_break_into_debugger(giant_string_buffer);
/* longjmp back if we can; otherwise, exit */
if (machine != NULL && machine->mame_data != NULL && machine->mame_data->fatal_error_jmpbuf_valid)
longjmp(machine->mame_data->fatal_error_jmpbuf, exitcode);
else
exit(exitcode);
}
void CLIB_DECL fatalerror(const char *text, ...)
{
running_machine *machine = global_machine;
va_list arg;
/* dump to the buffer; assume no one writes >2k lines this way */
va_start(arg, text);
vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg);
va_end(arg);
fatalerror_common(machine, MAMERR_FATALERROR, giant_string_buffer);
}
void CLIB_DECL fatalerror_exitcode(running_machine *machine, int exitcode, const char *text, ...)
{
va_list arg;
/* dump to the buffer; assume no one writes >2k lines this way */
va_start(arg, text);
vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg);
va_end(arg);
fatalerror_common(machine, exitcode, giant_string_buffer);
}
/*------------------------------------------------- /*-------------------------------------------------
popmessage - pop up a user-visible message popmessage - pop up a user-visible message
-------------------------------------------------*/ -------------------------------------------------*/

View File

@ -17,6 +17,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <exception>
#include "osdcomm.h" #include "osdcomm.h"
#include "bitmap.h" #include "bitmap.h"
#include "coreutil.h" #include "coreutil.h"
@ -318,13 +320,76 @@ inline void operator--(type &value, int) { value = (type)((int)value - 1); }
/***************************************************************************
EXCEPTION CLASSES
***************************************************************************/
// emu_exception is the base class for all emu-related exceptions
class emu_exception : public std::exception
{
};
// emu_fatalerror is a generic fatal exception that provides an error string
class emu_fatalerror : public emu_exception
{
public:
emu_fatalerror(const char *format, ...)
: m_exitcode(0)
{
va_list ap;
va_start(ap, format);
sprintf(m_text, format, ap);
va_end(ap);
osd_break_into_debugger(m_text);
}
emu_fatalerror(const char *format, va_list ap)
: m_exitcode(0)
{
vsprintf(m_text, format, ap);
osd_break_into_debugger(m_text);
}
emu_fatalerror(int _exitcode, const char *format, va_list ap)
: m_exitcode(_exitcode)
{
vsprintf(m_text, format, ap);
osd_break_into_debugger(m_text);
}
const char *string() const { return m_text; }
int exitcode() const { return m_exitcode; }
private:
char m_text[1024];
int m_exitcode;
};
/*************************************************************************** /***************************************************************************
FUNCTION PROTOTYPES FUNCTION PROTOTYPES
***************************************************************************/ ***************************************************************************/
/* Used by assert(), so definition here instead of mame.h */ DECL_NORETURN void fatalerror(const char *format, ...) ATTR_PRINTF(1,2) ATTR_NORETURN;
DECL_NORETURN void CLIB_DECL fatalerror(const char *text, ...) ATTR_PRINTF(1,2) ATTR_NORETURN; DECL_NORETURN void fatalerror_exitcode(running_machine *machine, int exitcode, const char *format, ...) ATTR_PRINTF(3,4) ATTR_NORETURN;
DECL_NORETURN void CLIB_DECL fatalerror_exitcode(running_machine *machine, int exitcode, const char *text, ...) ATTR_PRINTF(3,4) ATTR_NORETURN;
inline void fatalerror(const char *format, ...)
{
va_list ap;
va_start(ap, format);
throw emu_fatalerror(format, ap);
va_end(ap);
}
inline void fatalerror_exitcode(running_machine *machine, int exitcode, const char *format, ...)
{
va_list ap;
va_start(ap, format);
throw emu_fatalerror(exitcode, format, ap);
va_end(ap);
}
@ -333,7 +398,7 @@ DECL_NORETURN void CLIB_DECL fatalerror_exitcode(running_machine *machine, int e
***************************************************************************/ ***************************************************************************/
/* population count */ /* population count */
INLINE int popcount(UINT32 val) inline int popcount(UINT32 val)
{ {
int count; int count;
@ -344,7 +409,7 @@ INLINE int popcount(UINT32 val)
/* convert a series of 32 bits into a float */ /* convert a series of 32 bits into a float */
INLINE float u2f(UINT32 v) inline float u2f(UINT32 v)
{ {
union { union {
float ff; float ff;
@ -356,7 +421,7 @@ INLINE float u2f(UINT32 v)
/* convert a float into a series of 32 bits */ /* convert a float into a series of 32 bits */
INLINE UINT32 f2u(float f) inline UINT32 f2u(float f)
{ {
union { union {
float ff; float ff;
@ -368,7 +433,7 @@ INLINE UINT32 f2u(float f)
/* convert a series of 64 bits into a double */ /* convert a series of 64 bits into a double */
INLINE double u2d(UINT64 v) inline double u2d(UINT64 v)
{ {
union { union {
double dd; double dd;
@ -380,7 +445,7 @@ INLINE double u2d(UINT64 v)
/* convert a double into a series of 64 bits */ /* convert a double into a series of 64 bits */
INLINE UINT64 d2u(double d) inline UINT64 d2u(double d)
{ {
union { union {
double dd; double dd;