Hi, my Ruby C extension use rb_protect() to rescue Ruby errors in the
Ruby blocks provided by the high user.
Basically, I run the user provided Ruby block as follows:
···
-------------------------------
rb_protect(wrapper_rb_funcall_0, block, &exception);
if (exception) {
// rb_errinfo() gives the current exception object in this thread.
rb_funcall(mMyModule, id_manage_exception, 1, rb_errinfo());
// Dissable the current thread exception.
rb_set_errinfo(Qnil);
}
---------------------------------
The problem is that rb_errinfo() captures not just "normal" exceptions
(RuntimeError, StandardError...), but also Interrupt or SystemExit. So
if the Ruby code calls exit() then that is "rescued" by my library,
which is of course wrong.
So maybe I need to check the object returned by rb_errinfo() prior to
"rescuing" it. In short, I need to know which exact exceptions are
captured by the standard "rescue" (without giving it an specific
exception class):
begin
SOME_ERROR
rescue => e
puts "Exception #{e.class} rescued"
end
AFAIK those exceptions are "StandardError" and the classes inheriting from it.
So I just need to check whether the VALUE object returned by
rb_errinfo() inherits from rb_eStandardError. Am I right? Thanks a
lot.
--
Iñaki Baz Castillo
<ibc@aliax.net>
Hi, I got it at 80%, just a single issue remains. This is the code
that tries to "imitate" the classic "begin-rescue-end" at C level:
rb_protect(my_wrapper_rb_funcall_0, block, &exception);
if (exception) {
// rb_errinfo() gives the current exception object in this thread.
VALUE exception = rb_errinfo();
if (rb_obj_is_kind_of(exception, rb_eStandardError) == Qtrue) {
rb_funcall(mMyModule, rb_intern("manage_exception", 1, exception);
// Dissable the current thread exception.
rb_set_errinfo(Qnil);
}
else {
// TODO: It's not a public Ruby function !!!
//rb_f_raise(0, NULL);
}
}
The only I need is to find how to raise the produced exception when
it's not a StandardError. In ruby land I just need to call "raise"
(with no arguments). In C land, rb_f_raise() is the C function used by
"raise", but it's not public !!
So what is the alternative? Note that exception variable holds the
exception instance, not a class, so I cannot use rb_raise.
Thanks a lot.
···
2012/5/2 Iñaki Baz Castillo <ibc@aliax.net>:
So I just need to check whether the VALUE object returned by
rb_errinfo() inherits from rb_eStandardError. Am I right? Thanks a
lot.
--
Iñaki Baz Castillo
<ibc@aliax.net>
Sorry, my fault: exception INT variable holds the integer given to
rb_protect, so if it's != 0 then I just need to do
rb_jump_tag(integer).
···
2012/5/2 Iñaki Baz Castillo <ibc@aliax.net>:
Hi, I got it at 80%, just a single issue remains. This is the code
that tries to "imitate" the classic "begin-rescue-end" at C level:
rb_protect(my_wrapper_rb_funcall_0, block, &exception);
if (exception) {
// rb_errinfo() gives the current exception object in this thread.
VALUE exception = rb_errinfo();
if (rb_obj_is_kind_of(exception, rb_eStandardError) == Qtrue) {
rb_funcall(mMyModule, rb_intern("manage_exception", 1, exception);
// Dissable the current thread exception.
rb_set_errinfo(Qnil);
}
else {
// TODO: It's not a public Ruby function !!!
//rb_f_raise(0, NULL);
}
}
The only I need is to find how to raise the produced exception when
it's not a StandardError. In ruby land I just need to call "raise"
(with no arguments). In C land, rb_f_raise() is the C function used by
"raise", but it's not public !!
So what is the alternative? Note that exception variable holds the
exception instance, not a class, so I cannot use rb_raise.
--
Iñaki Baz Castillo
<ibc@aliax.net>