home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 3
/
AACD03.BIN
/
AACD
/
Programming
/
sofa
/
archive
/
SmallEiffel.lha
/
SmallEiffel
/
sys
/
runtime
/
exceptions.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-06-05
|
16KB
|
556 lines
/*
-- This file is free software, which comes along with SmallEiffel. This
-- software is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-- FITNESS FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You are allowed to redistribute it and sell it, alone or as a part of
-- another product.
-- Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
-- Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
-- http://www.loria.fr/SmallEiffel
--
*/
/*
This file (exception.c) is automatically included when exception handling
is used somewhere in the live code.
*/
/*
Miscellaneous Notes:
We are currently using the old signal() system call instead of
the prefered sigaction() call.
On Linux systems at least, signal() is implemented by sigaction()
so it doesn't really matter. Need to investigate this on other
Unix systems.
James Graves (ansible@xnet.com)
*/
/*
Top of the rescue context stack (or NULL if there is no current
context) :
*/
struct rescue_context *rescue_context_top = NULL;
/*
Set to nonzero if the exception was internally generated, as with an
assertion violation. It is Os_signal (11) for an OS signal.
*/
int internal_exception_number;
int original_internal_exception_number;
/*
Set to nonzero if the exception was a signal (external). It is 0
for an internal exception.
*/
int signal_exception_number;
/*
Used by some internal exceptions to print additional debugging
information when the exception is not handled and a dump is done.
*/
char *additional_error_message;
static void critical_error_exit(void) {
/* This is called whenever a critical error in the SmallEiffel
is encountered. This kind of error cannot be handled by the
exception handler.
For instance, this routine is called if there is an error in the
operation of the exception handler routines themselves.
*/
fprintf(stderr, "There was a critical error in the SmallEiffel runtime.\n");
exit(2);
}
void setup_signal_handler() {
/*
Sets up the reception of signals. If exception handling is enabled
(by the existance of a rescue clause somewhere), then all OS signals
now go to exception_handler instead of se_print_run_time_stack().
*/
#ifdef SIG_ERR
/* Check signal() call for errors. Posix compliant systems should
define SIG_ERR which is returned by signal() on an error. All Unix
signals are included except * for SIGKILL and SIGSTOP.
The other signals SmallEiffel traps for
other OSs (like SIGBREAK) are not included here, but are below
in the #else part, for non-Posix systems.
*/
# ifdef SIGHUP
if ( SIG_ERR == signal( SIGHUP, signal_exception_handler ) )
{
fprintf(stderr, "Error setting up signal handler for SIGHUP.\n");
critical_error_exit();
}
# endif
# ifdef SIGINT
if ( SIG_ERR == signal( SIGINT, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGINT.\n");
critical_error_exit();
}
# endif
# ifdef SIGQUIT
if ( SIG_ERR == signal( SIGQUIT, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGQUIT.\n");
critical_error_exit();
}
# endif
# ifdef SIGILL
if ( SIG_ERR == signal( SIGILL, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGILL.\n");
critical_error_exit();
}
# endif
# ifdef SIGTRAP
if ( SIG_ERR == signal( SIGTRAP, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGTRAP.\n");
critical_error_exit();
}
# endif
# ifdef SIGIOT
if ( SIG_ERR == signal( SIGIOT, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGIOT.\n");
critical_error_exit();
}
# endif
# ifdef SIGBUS
if ( SIG_ERR == signal( SIGBUS, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGBUS.\n");
critical_error_exit();
}
# endif
# ifdef SIGFPE
if ( SIG_ERR == signal( SIGFPE, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGFPE.\n");
critical_error_exit();
}
# endif
# ifdef SIGUSR1
if ( SIG_ERR == signal( SIGUSR1, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGUSR1.\n");
critical_error_exit();
}
# endif
# ifdef SIGSEGV
if ( SIG_ERR == signal( SIGSEGV, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGSEGV.\n");
critical_error_exit();
}
# endif
# ifdef SIGUSR2
if ( SIG_ERR == signal( SIGUSR2, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGUSR2.\n");
critical_error_exit();
}
# endif
# ifdef SIGPIPE
if ( SIG_ERR == signal( SIGPIPE, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGPIPE.\n");
critical_error_exit();
}
# endif
# ifdef SIGALRM
if ( SIG_ERR == signal( SIGALRM, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGALRM.\n");
critical_error_exit();
}
# endif
# ifdef SIGTERM
if ( SIG_ERR == signal( SIGTERM, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGTERM.\n");
critical_error_exit();
}
# endif
# ifdef SIGCHLD
if ( SIG_ERR == signal( SIGCHLD, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGCHLD.\n");
critical_error_exit();
}
# endif
# ifdef SIGCONT
if ( SIG_ERR == signal( SIGCONT, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGCONT.\n");
critical_error_exit();
}
# endif
# ifdef SIGTSTP
if ( SIG_ERR == signal( SIGTSTP, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGTSTP.\n");
critical_error_exit();
}
# endif
# ifdef SIGTTIN
if ( SIG_ERR == signal( SIGTTIN, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGTTIN.\n");
critical_error_exit();
}
# endif
# ifdef SIGTTOU
if ( SIG_ERR == signal( SIGTTOU, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGTTOU.\n");
critical_error_exit();
}
# endif
# ifdef SIGURG
if ( SIG_ERR == signal( SIGURG, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGURG.\n");
critical_error_exit();
}
# endif
# ifdef SIGXCPU
if ( SIG_ERR == signal( SIGXCPU, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGXCPU.\n");
critical_error_exit();
}
# endif
# ifdef SIGXFSZ
if ( SIG_ERR == signal( SIGXFSZ, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGXFSZ.\n");
critical_error_exit();
}
# endif
# ifdef SIGVTALRM
if ( SIG_ERR == signal( SIGVTALRM, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGVTALRM.\n");
critical_error_exit();
}
# endif
# ifdef SIGPROF
if ( SIG_ERR == signal( SIGPROF, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGPROF.\n");
critical_error_exit();
}
# endif
# ifdef SIGWINCH
if ( SIG_ERR == signal( SIGWINCH, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGWINCH.\n");
critical_error_exit();
}
# endif
# ifdef SIGIO
if ( SIG_ERR == signal( SIGIO, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGIO.\n");
critical_error_exit();
}
# endif
# ifdef SIGPWR
if ( SIG_ERR == signal( SIGPWR, signal_exception_handler ) ) {
fprintf(stderr, "Error setting up signal handler for SIGPWR.\n");
critical_error_exit();
}
# endif
#else /* SIG_ERR not defined, non-Posix system? */
/* These don't check return code for the signal() OS call. Bad practice,
but what can be done? */
# ifdef SIGBREAK
/* This signal does not exist on Unix systems. */
signal( SIGBREAK, signal_exception_handler );
# endif
# ifdef SIGHUP
signal( SIGHUP, signal_exception_handler );
# endif
# ifdef SIGINT
signal( SIGINT, signal_exception_handler );
# endif
# ifdef SIGQUIT
signal( SIGQUIT, signal_exception_handler );
# endif
# ifdef SIGILL
signal( SIGILL, signal_exception_handler );
# endif
# ifdef SIGTRAP
signal( SIGTRAP, signal_exception_handler );
# endif
# ifdef SIGIOT
signal( SIGIOT, signal_exception_handler );
# endif
# ifdef SIGBUS
signal( SIGBUS, signal_exception_handler );
# endif
# ifdef SIGFPE
signal( SIGFPE, signal_exception_handler );
# endif
# ifdef SIGKILL
/* This should silently fail on Unix systems, but is reported to work
on other non-Unix systems. You have been warned. */
signal( SIGKILL, signal_exception_handler );
# endif
# ifdef SIGUSR1
signal( SIGUSR1, signal_exception_handler );
# endif
# ifdef SIGSEGV
signal( SIGSEGV, signal_exception_handler );
# endif
# ifdef SIGUSR2
signal( SIGUSR2, signal_exception_handler );
# endif
# ifdef SIGPIPE
signal( SIGPIPE, signal_exception_handler );
# endif
# ifdef SIGALRM
signal( SIGALRM, signal_exception_handler );
# endif
# ifdef SIGTERM
signal( SIGTERM, signal_exception_handler );
# endif
# ifdef SIGCHLD
signal( SIGCHLD, signal_exception_handler );
# endif
# ifdef SIGCONT
signal( SIGCONT, signal_exception_handler );
# endif
# ifdef SIGSTOP
/* This should also silently fail on all Unix systems, but it may
be effective on other OSs. */
signal( SIGSTOP, signal_exception_handler );
# endif
# ifdef SIGTSTP
signal( SIGTSTP, signal_exception_handler );
# endif
# ifdef SIGTTIN
signal( SIGTTIN, signal_exception_handler );
# endif
# ifdef SIGTTOU
signal( SIGTTOU, signal_exception_handler );
# endif
# ifdef SIGURG
signal( SIGURG, signal_exception_handler );
# endif
# ifdef SIGXCPU
signal( SIGXCPU, signal_exception_handler );
# endif
# ifdef SIGXFSZ
signal( SIGXFSZ, signal_exception_handler );
# endif
# ifdef SIGTALRM
signal( SIGTALRM, signal_exception_handler );
# endif
# ifdef SIGPROF
signal( SIGPROF, signal_exception_handler );
# endif
# ifdef SIGWINCH
signal( SIGWINCH, signal_exception_handler );
# endif
# ifdef SIGIO
signal( SIGIO, signal_exception_handler );
# endif
# ifdef SIGPWR
signal( SIGPWR, signal_exception_handler );
# endif
#endif /* ifdef SIG_ERR */
}
void signal_exception_handler(int signal_number) {
/* Set up to be called whenever an OS signal has been received.
Checks to see if there is a rescue clause active (somewhere on the
call stack), and if so, transfer control to that.
*/
struct rescue_context *current_context;
#ifdef SIG_ERR
/* some OS implementations automatically block a signal while
* executing the signal handler, but some do not. */
if ( SIG_ERR == signal( signal_number, SIG_IGN ) ) {
fprintf(stderr, "In signal_exception_handler: ");
fprintf(stderr, "Error turning off signal %d.\n", signal_number );
critical_error_exit();
}
#else
signal( signal_number, SIG_IGN );
#endif
internal_exception_number = Os_signal;
original_internal_exception_number = 0;
signal_exception_number = signal_number;
if ( rescue_context_top != NULL ) {
current_context = rescue_context_top;
rescue_context_top = rescue_context_top->next;
/* now re-enable that signal */
#ifdef SIG_ERR
if ( SIG_ERR == signal( signal_number, signal_exception_handler ) ) {
fprintf(stderr, "In signal_exception_handler: ");
fprintf(stderr, "Error turning on signal %d.\n", signal_number );
critical_error_exit();
}
#else
signal( signal_number, signal_exception_handler );
#endif
LONGJMP( current_context->jb, internal_exception_number );
}
/* No current rescue clause, exit with a dump : */
print_exception();
se_print_run_time_stack();
exit(1);
}
void internal_exception_handler(int exception_number) {
/* Called whenever an internal (to SmallEiffel) exception is to
be raised (`raise' feature, assertion violation, etc.).
Checks to see if there is a current rescue clause (somewhere
in the call stack), and transfers control to it.
Else exit with a stack trace (if enabled).
*/
struct rescue_context *current_context;
/* If this is not a routine failure, clear out old exception
* information. */
if ( exception_number != Routine_failure ) {
internal_exception_number = exception_number;
original_internal_exception_number = 0;
signal_exception_number = 0;
}
else {
original_internal_exception_number = internal_exception_number;
}
if ( rescue_context_top != NULL ) {
current_context = rescue_context_top;
rescue_context_top = rescue_context_top->next;
LONGJMP( current_context->jb, exception_number );
}
/* No current rescue clause, exit with a dump : */
print_exception();
se_print_run_time_stack();
exit(1);
}
#ifdef SE_NO_CHECK
static void print_exception_case( int ex_num ) {
switch( ex_num ) {
case Check_instruction:
fprintf(SE_ERR, "Check instruction failed.\n");
break;
case Class_invariant:
fprintf(SE_ERR, "Class invariant not maintained.\n");
break;
case Developer_exception:
fprintf(SE_ERR, "Developer exception:\n");
break;
case Incorrect_inspect_value:
fprintf(SE_ERR, "Incorrect inspect value.\n");
break;
case Loop_invariant:
fprintf(SE_ERR, "Loop invariant failed.\n");
break;
case Loop_variant:
fprintf(SE_ERR, "Loop variant failed to decrease.\n");
break;
case No_more_memory:
fprintf(SE_ERR, "Failed to allocate additional memory.\n");
break;
case Postcondition:
fprintf(SE_ERR, "Postcondition (ensure clause) failed.\n");
break;
case Precondition:
fprintf(SE_ERR, "Precondition (require clause) failed.\n");
break;
case Routine_failure:
fprintf(SE_ERR, "Routine failure.\n");
break;
case Os_signal:
fprintf(SE_ERR, "OS Signal (%d) received.\n",
signal_exception_number );
break;
case Void_attached_to_expanded:
fprintf(SE_ERR, "A Void became attached to an expanded object.\n");
fprintf(SE_ERR, "Please report this problem to the SmallEiffel team.\n");
break;
case Void_call_target:
fprintf(SE_ERR, "Feature call attempted on a Void reference.\n");
break;
default:
fprintf(SE_ERR, "There was an unknown exception.\n");
fprintf(SE_ERR, "Please report this problem to the SmallEiffel team.\n");
}
}
#endif
void print_exception(void) {
/* Display some information about last not handled exception. */
#ifdef SE_NO_CHECK
fprintf(SE_ERR,"Exception number %d not handled.\n",internal_exception_number);
if ( internal_exception_number == Routine_failure ) {
fprintf(SE_ERR, "Routine failure. Original exception: \n");
print_exception_case( original_internal_exception_number );
}
else {
print_exception_case( internal_exception_number );
}
if ( additional_error_message != NULL ) {
fprintf(SE_ERR, "%s\n", additional_error_message );
}
#endif
}