A Strolling Programmeraka なかだ

またの名を「風まかせ人まかせ力まかせ」日記

T D I A R Y T I M E S % fgrep -i '' *.td2
<< 2006/06/ 1 2 3 4 1. コールドベア新気球
5 6 1. 一日専業主夫
2. コマンドラインって何
7 8 9 10 11 1. make test
12 1. rb_protect
2. 反省点
3. Array[1,2,3,]がSyntaxError
13 14 1. rb_protect(2)
15 16 1. Symbol#to_proc が 1.9 に入ったけど、alist 対応じゃなかった件。
17 18 19 20 21 22 23 24 25 26 27 28 1. LLRing
29 1. 眼鏡
30 >>
«前の日記(2006-06-11) 最新 次の日記(2006-06-14)» 編集

2006-06-12 modified at Tue Jun 13 21:03:05 2006

* [ruby] rb_protect

えーと、[Kazehakase-devel 2623]の話と仮定しますが。

#0  0xffffe410 in __kernel_vsyscall ()
#1  0x40356b39 in raise () from /lib/libc.so.6
#2  0x403581b1 in abort () from /lib/libc.so.6
#3  0x418ea6cc in rb_bug () from /usr/lib/libruby18.so.1.8
#4  0x419559f6 in ruby_posix_signal () from /usr/lib/libruby18.so.1.8
#5  <signal handler called>
#6  0x418f53bf in rb_iter_break () from /usr/lib/libruby18.so.1.8
#7  0x418f55db in rb_exc_raise () from /usr/lib/libruby18.so.1.8
#8  0x418ebfde in rb_raise () from /usr/lib/libruby18.so.1.8
#9  0x418f5622 in rb_interrupt () from /usr/lib/libruby18.so.1.8
#10 0x41902fad in rb_thread_interrupt () from /usr/lib/libruby18.so.1.8
#11 0x4195590b in ruby_posix_signal () from /usr/lib/libruby18.so.1.8
#12 0x41955998 in ruby_posix_signal () from /usr/lib/libruby18.so.1.8
#13 <signal handler called>
#14 0xffffe410 in __kernel_vsyscall ()
#15 0x403dbd91 in select () from /lib/libc.so.6
#16 0x41901815 in rb_thread_select () from /usr/lib/libruby18.so.1.8
#17 0x41adf28a in exec_callback () from /usr/lib/ruby/site_ruby/1.8/i686-linux/gtk2.so
#18 0x40b791c1 in g_main_loop_get_context () from /usr/lib/libglib-2.0.so.0
#19 0x40b7883a in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#20 0x40b78e01 in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
#21 0x40630a17 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#22 0x0804b481 in main (argc=1, argv=0xbf8bfb14) at main.c:815

「rubyを組み込んだアプリケーションから組み込まれたrubyを呼び出す」というのは、 コールバックでも例外ではありません。 これは、「アプリとrubyの境界を越える大域ジャンプはあってはならない」といってもいいです。 rubyの例外や、アプリ側でのlongjmp()やC++の例外など全部含めて。

ということで

(1) signal_connectしたコールバック内では確実にrescueする

というのは方針としては正しいのですが、

  • (昨日いったように)rb_rescue()だけでは拾えないものもある
  • Ruby/GLib2のバグなので、個別に対応するよりもそちらを修正すべきである

という点が問題でしょう。

* [ruby] 反省点

申し訳ないです

とくに発表したわけでもないのに、我が物顔すぎたか。 弁当食っておとなしくデバッグしてればよかった。

* [ruby] Array[1,2,3,]がSyntaxError

「配列リテラルはともかく、メソッド呼び出しのほうは通さなくてもいいんじゃないか」 *1 というところで、まつもとさんとは話がついたんだけど。 まずいかな?

*1  というか、最初改行も置けなくなってた

本日のツッコミ(全2件) [ツッコミを入れる]
_ hisa (2006-06-13 15:26)

あー、そんなことないです。

_ kou (2006-06-13 21:03)

以下のスクリプトが例外で異常終了するならRuby/GLib2側で "signal_connectしたコールバック内では確実にrescueする"ように修正すればよいと思っています。

uire 'gtk2'

Gtk.init

action = Gtk::Action.new("Name", "Label")
action.signal_connect("activate") do
  raise "activate"
end

begin
  action.activate
  p :ignored
rescue
  p :handled
end

が、このスクリプトは:handledを出力して正常終了します。
なかださんがいう修正はこのスクリプトが:ignoredを出力して正常終了するようにするということですよね?

もちろん、以下のようなアプリケーション(コンパイルできません、ごめんなさい)の場合は上記のスクリプトが:ignoredを出力して正常終了するのがよいと思いますが、↑のスクリプトは今のままの(:handledを出力する)動作の方がユーザにとっては使い勝手がよさそうな気がします。


#include <rbgtk.h>

int
main(int argc, char **argv)
{
    VALUE rb_action;
    GtkAction *action;

    gtk_init(&argc, &argv);

    ruby_init();
    ruby_init_loadpath();
    ruby_script(argv[0]);
    ruby_set_argv(argc, argv);

    rb_action = rb_eval_string("require 'gtk2'\n"
                               "Gtk.init\n"
                               "action = Gtk::Action.new('Name', 'Label')\n"
                               "action.signal_connect('activate') do\n"
                               " raise 'activate'\n"
                               "end\n"
                               "action\n");
    action = RVAL2GOBJ(rb_action);
    gtk_action_activate(action);

    return 0;
}

Ruby/GLib2側で"大域ジャンプ"できるかどうかを判断できるのであれば、Ruby/GLib2側を修正すればよいと思いますが、できないのであれば、大域ジャンプできないところでは個別にrescueしないといけない気がします。
rescueでは拾えないものがあるという問題はありますが。。。

お名前:
E-mail:
コメント:

投稿する前にチェックボックスをチェックしてください

本日のPingbacks(全0件)
本日のリンク元
アンテナ
その他のリンク元
検索

Key fingerprint = 1E69 3ED2 C05B 6BA4 34B2 FC25 478B C08D 2772 58F6