[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: C++ and stack unwinding/destruction
From: |
Marco Maggi |
Subject: |
Re: C++ and stack unwinding/destruction |
Date: |
Sat, 17 Mar 2007 08:27:42 +0100 |
"David Fang" wrote:
> C++ relies heavily on constructor-destructor duality
> [...]
> The implementation of guile's C-style exceptions using
> setjmp/longjmp, however breaks this universal law.
> [...]
> In the event of scm_error_scm(), the destructors that
> *should* be called in the frame of this function are
> just skipped.
I do not have much time to dig into the list's archive,
so I do not know what is in the inconclusive thread;
anyway, you have to use 'scm_c_catch()' and the C++'s
'catch'.
You have to separate the Guile/C code from the C++ code:
* when calling C++ from Guile/C: put C++ code inside
a 'catch' and convert the C++ exception into the
Guile/C arguments to 'scm_error()';
* when calling Guile/C from C++: put the Guile/C code
into a separate function and use 'scm_c_catch()' in
the C++ function to invoke it.
I do it all the time when I register a Guile/C callback
into an external C library and I cannot let the dynwind
mechanism go through the foreign functions.
When I need to invoke a Scheme function from the callback
I use something like this:
typedef struct frame_t {
SCM s_function;
SCM s_data_to_function;
SCM s_error_key;
SCM s_error_args;
SCM s_error_stack;
} frame_t;
static SCM
catch_handler (void * data, SCM s_error_key,
SCM s_error_args)
{
frame_t * frame = data;
frame->s_error_key = s_error_key;
frame->s_error_args = s_error_args;
return SCM_BOOL_F;
}
static SCM
pre_unwind_handler (void * data, SCM s_dummy1,
SCM s_dummy2)
{
frame_t * frame = data;
frame->s_error_stack = scm_make_stack(SCM_BOOL_T,
SCM_EOL);
return SCM_BOOL_F;
}
static SCM
function_caller (void * params)
{
frame_t * frame = params;
SCM s_result;
s_result = scm_call_1(frame->s_function,
frame->s_data_to_function);
/* validate 's_result' here */
return s_result;
}
static type_t
callback_function (void * data, void * params)
{
frame_t * frame = params;
SCM s_result;
frame->s_error_key = SCM_UNSPECIFIED;
frame->s_error_args = SCM_UNSPECIFIED;
frame->s_error_stack = SCM_UNSPECIFIED;
frame->s_data_to_function = something_from(data);
s_result = scm_c_catch(SCM_BOOL_T,
function_caller, frame,
catch_handler, frame,
pre_unwind_handler, frame);
if (SCM_UNSPECIFIED != frame->s_error_key)
/* there was an error */
else
return type_from(s_result);
}
when I register the callback I allocate a 'frame_t' and
initialise the 's_function' field with the SCM procedure
SMOB.
If later I need to retrhow the Guile error I use:
void
gee_rethrow_error_with_stack (SCM s_error_stack,
SCM s_error_key,
SCM s_error_args,
const char * procname)
{
SCM s_port, s_string, s_stack, s_data;
size_t len;
s_stack = scm_make_stack(SCM_BOOL_T, SCM_EOL);
len =
scm_to_uint(scm_stack_length(s_error_stack)) -
scm_to_uint(scm_stack_length(s_stack)) - 1;
s_port = scm_open_output_string();
{
SCM s_message =
scm_list_ref(s_error_args,scm_from_uint(1));
SCM s_args =
scm_list_ref(s_error_args,scm_from_uint(2));
scm_simple_format(s_port, s_message,
(scm_is_eq(SCM_BOOL_F,s_args)?
SCM_EOL : s_args));
scm_newline(s_port);
scm_display_backtrace(s_error_stack, s_port,
scm_from_uint(len),
SCM_UNDEFINED);
s_string = scm_get_output_string(s_port);
}
scm_close_output_port(s_port);
s_data = scm_list_ref(s_error_args, scm_from_uint(3));
scm_error_scm(s_error_key,
scm_from_locale_string(procname),
s_string, SCM_BOOL_F, s_data);
}
HTH
--
Marco Maggi