mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* bug fix
* change mainloop_abort_on_no_widget_cmd => mainloop_abort_on_exception ( to avoid thread timing trouble on accessing destroyed widgets ) git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4217 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
38ac53f0c1
commit
a3dbb3c822
4 changed files with 89 additions and 55 deletions
|
@ -244,25 +244,24 @@ require "tcltklib"
|
|||
: 現在の loop_max と no_event_tick との値を返す.
|
||||
: ( see set_eventloop_wait )
|
||||
|
||||
mainloop_abort_on_no_widget_cmd=(bool)
|
||||
: Tk インタープリタ上で widget に対応するコマンドが存在しない
|
||||
: という例外を発生した際に,イベントループをエラー停止させる
|
||||
: かどうかを指定する.true を指定した場合はエラー停止するが,
|
||||
: false の場合は例外を無視してイベントループを継続する.
|
||||
: デフォルトでは false に設定されている.
|
||||
: これは,コールバック処理の消去を忘れたままに widget を破壊
|
||||
: してしまった場合のエラー停止の回避に役立つ.特に複数のイン
|
||||
: タープリタが同時に動作している場合には,それらを管理するイ
|
||||
: ベントループは 1 個であるため,いずれかのインタープリタが強
|
||||
: 制停止させられた際にコールバックの完全な消去に失敗する場合
|
||||
: がしばしば見られる.そのような場合でもエラーを無視してイベ
|
||||
: ントループが稼働を続けることで,残りのインタープリタが正常
|
||||
: に動作し続けることができる.
|
||||
mainloop_abort_on_exception=(bool)
|
||||
: Tk インタープリタ上で例外を発生した際に,イベントループを
|
||||
: エラー停止させるかどうかを指定する.true を指定した場合は
|
||||
: エラー停止するが,false の場合は例外を無視してイベントルー
|
||||
: プを継続する.さらに nil の場合は警告モードでない限りはエ
|
||||
: ラーメッセージの出力すら省略して,例外を無視する.
|
||||
: デフォルトでは true に設定されている.
|
||||
: 1個のインタープリタだけを使っている場合にはエラー時にその
|
||||
: まま停止しても通常は問題ないが,複数のインタープリタが同時
|
||||
: に動作している場合には,それらを管理するイベントループは1
|
||||
: 個だけであるため,いずれかのインタープリタのエラーが原因で,
|
||||
: 他のインタープリタの処理継続が不可能になることがある.その
|
||||
: ような場合でもエラーを無視してイベントループが稼働を続ける
|
||||
: ことで,他のインタープリタが正常に動作し続けることができる.
|
||||
|
||||
mainloop_abort_on_no_widget_cmd
|
||||
: Tk インタープリタ上で widget に対応するコマンドが存在しない
|
||||
: という例外を発生した際に,イベントループをエラー停止させる
|
||||
: かどうかを設定状態を true/false で得る.
|
||||
mainloop_abort_on_exception
|
||||
: Tk インタープリタ上で例外を発生した際に,イベントループをエ
|
||||
: ラー停止させるかどうかの設定状態を true/false で得る.
|
||||
|
||||
|
||||
クラス TclTkIp
|
||||
|
@ -339,10 +338,10 @@ require "tcltklib"
|
|||
get_eventloop_tick : 引数を含めて TclTkLib.get_eventloop_tick に同じ
|
||||
set_eventloop_weight : 引数を含めて TclTkLib.set_eventloop_weight に同じ
|
||||
get_eventloop_weight : 引数を含めて TclTkLib.set_eventloop_weight に同じ
|
||||
mainloop_abort_on_no_widget_cmd=
|
||||
: 引数を含めて TclTkLib.mainloop_abort_on_no_widget_cmd= に同じ
|
||||
mainloop_abort_on_no_widget_cmd
|
||||
: 引数を含めて TclTkLib.mainloop_abort_on_no_widget_cmd に同じ
|
||||
mainloop_abort_on_exception
|
||||
: 引数を含めて TclTkLib.mainloop_abort_on_exception に同じ
|
||||
mainloop_abort_on_exception=
|
||||
: 引数を含めて TclTkLib.mainloop_abort_on_exception= に同じ
|
||||
|
||||
クラス TkCallbackBreak < StandardError
|
||||
クラス TkCallbackContinue < StandardError
|
||||
|
|
|
@ -84,7 +84,7 @@ static int req_timer_tick = DEFAULT_TIMER_TICK;
|
|||
static int run_timer_flag = 0;
|
||||
|
||||
static int event_loop_wait_event = 0;
|
||||
static int event_loop_abort_no_cmd = 0;
|
||||
static int event_loop_abort_on_exc = 1;
|
||||
static int loop_counter = 0;
|
||||
|
||||
#if TCL_MAJOR_VERSION >= 8
|
||||
|
@ -206,19 +206,31 @@ get_eventloop_weight(self)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
rb_evloop_abort_no_cmd(self)
|
||||
rb_evloop_abort_on_exc(self)
|
||||
VALUE self;
|
||||
{
|
||||
return event_loop_abort_no_cmd? Qtrue: Qfalse;
|
||||
if (event_loop_abort_on_exc > 0) {
|
||||
return Qtrue;
|
||||
} else if (event_loop_abort_on_exc == 0) {
|
||||
return Qfalse;
|
||||
} else {
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_evloop_abort_no_cmd_set(self, val)
|
||||
rb_evloop_abort_on_exc_set(self, val)
|
||||
VALUE self, val;
|
||||
{
|
||||
rb_secure(4);
|
||||
event_loop_abort_no_cmd = (RTEST(val))? 1: 0;
|
||||
return rb_evloop_abort_no_cmd(self);
|
||||
if (RTEST(val)) {
|
||||
event_loop_abort_on_exc = 1;
|
||||
} else if (val == Qnil) {
|
||||
event_loop_abort_on_exc = -1;
|
||||
} else {
|
||||
event_loop_abort_on_exc = 0;
|
||||
}
|
||||
return rb_evloop_abort_on_exc(self);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -324,7 +336,7 @@ lib_mainloop_ensure(parent_evloop)
|
|||
DUMP2("mainloop-ensure: current-thread : %lx\n", rb_thread_current());
|
||||
DUMP2("mainloop-ensure: eventloop-thread : %lx\n", eventloop_thread);
|
||||
if (eventloop_thread == rb_thread_current()) {
|
||||
DUMP2("tcltklib: eventloop-thread -> %lx\n", parent_evloop);
|
||||
DUMP2("eventloop-thread -> %lx\n", parent_evloop);
|
||||
eventloop_thread = parent_evloop;
|
||||
}
|
||||
return Qnil;
|
||||
|
@ -394,19 +406,20 @@ lib_watchdog_core(check_rootwidget)
|
|||
|
||||
/* watchdog start */
|
||||
do {
|
||||
if (eventloop_thread == 0 || loop_counter == prev_val) {
|
||||
if (RTEST(rb_funcall(eventloop_thread, rb_intern("stop?"), 0))
|
||||
&& ++chance >= 3) {
|
||||
/* start new eventloop thread */
|
||||
DUMP2("eventloop thread %lx is sleeping or dead",
|
||||
eventloop_thread);
|
||||
evloop = rb_thread_create(lib_mainloop_launcher,
|
||||
(void*)&check_rootwidget);
|
||||
DUMP2("create new eventloop thread %lx", evloop);
|
||||
loop_counter = -1;
|
||||
chance = 0;
|
||||
rb_thread_run(evloop);
|
||||
}
|
||||
if (eventloop_thread == 0
|
||||
|| (loop_counter == prev_val
|
||||
&& RTEST(rb_funcall(eventloop_thread, rb_intern("stop?"), 0))
|
||||
&& ++chance >= 3 )
|
||||
) {
|
||||
/* start new eventloop thread */
|
||||
DUMP2("eventloop thread %lx is sleeping or dead",
|
||||
eventloop_thread);
|
||||
evloop = rb_thread_create(lib_mainloop_launcher,
|
||||
(void*)&check_rootwidget);
|
||||
DUMP2("create new eventloop thread %lx", evloop);
|
||||
loop_counter = -1;
|
||||
chance = 0;
|
||||
rb_thread_run(evloop);
|
||||
} else {
|
||||
loop_counter = prev_val;
|
||||
chance = 0;
|
||||
|
@ -919,11 +932,16 @@ ip_invoke_real(argc, argv, obj)
|
|||
|
||||
/* map from the command name to a C procedure */
|
||||
if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) {
|
||||
if (event_loop_abort_no_cmd || cmd[0] != '.')
|
||||
/* if (event_loop_abort_on_exc || cmd[0] != '.') { */
|
||||
if (event_loop_abort_on_exc > 0) {
|
||||
rb_raise(rb_eNameError, "invalid command name `%s'", cmd);
|
||||
else {
|
||||
} else {
|
||||
if (event_loop_abort_on_exc < 0) {
|
||||
rb_warning("invalid command name `%s' (ignore)", cmd);
|
||||
} else {
|
||||
rb_warn("invalid command name `%s' (ignore)", cmd);
|
||||
}
|
||||
Tcl_ResetResult(ptr->ip);
|
||||
rb_warning("invalid command name `%s' (ignore)", cmd);
|
||||
return rb_tainted_str_new2("");
|
||||
}
|
||||
}
|
||||
|
@ -1000,8 +1018,19 @@ ip_invoke_real(argc, argv, obj)
|
|||
TRAP_END;
|
||||
}
|
||||
|
||||
/* exception on mainloop */
|
||||
if (ptr->return_value == TCL_ERROR) {
|
||||
rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
|
||||
if (event_loop_abort_on_exc > 0) {
|
||||
rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
|
||||
} else {
|
||||
if (event_loop_abort_on_exc < 0) {
|
||||
rb_warning("%s (ignore)", ptr->ip->result);
|
||||
} else {
|
||||
rb_warn("%s (ignore)", ptr->ip->result);
|
||||
}
|
||||
Tcl_ResetResult(ptr->ip);
|
||||
return rb_tainted_str_new2("");
|
||||
}
|
||||
}
|
||||
|
||||
/* pass back the result (as string) */
|
||||
|
@ -1176,10 +1205,10 @@ Init_tcltklib()
|
|||
set_eventloop_weight, 2);
|
||||
rb_define_module_function(lib, "get_eventloop_weight",
|
||||
get_eventloop_weight, 0);
|
||||
rb_define_module_function(lib, "mainloop_abort_on_no_widget_cmd",
|
||||
rb_evloop_abort_no_cmd, 0);
|
||||
rb_define_module_function(lib, "mainloop_abort_on_no_widget_cmd=",
|
||||
rb_evloop_abort_no_cmd_set, 1);
|
||||
rb_define_module_function(lib, "mainloop_abort_on_exception",
|
||||
rb_evloop_abort_on_exc, 0);
|
||||
rb_define_module_function(lib, "mainloop_abort_on_exception=",
|
||||
rb_evloop_abort_on_exc_set, 1);
|
||||
|
||||
rb_define_alloc_func(ip, ip_alloc);
|
||||
rb_define_method(ip, "initialize", ip_init, -1);
|
||||
|
@ -1196,10 +1225,10 @@ Init_tcltklib()
|
|||
rb_define_method(ip, "mainloop", lib_mainloop, -1);
|
||||
rb_define_method(ip, "mainloop_watchdog", lib_mainloop_watchdog, -1);
|
||||
rb_define_method(ip, "do_one_event", lib_do_one_event, -1);
|
||||
rb_define_method(ip, "mainloop_abort_on no_widget_cmd",
|
||||
rb_evloop_abort_no_cmd, 0);
|
||||
rb_define_method(ip, "mainloop_abort_on_no_widget_cmd=",
|
||||
rb_evloop_abort_no_cmd_set, 1);
|
||||
rb_define_method(ip, "mainloop_abort_on_exception",
|
||||
rb_evloop_abort_on_exc, 0);
|
||||
rb_define_method(ip, "mainloop_abort_on_exception=",
|
||||
rb_evloop_abort_on_exc_set, 1);
|
||||
rb_define_method(ip, "set_eventloop_tick", set_eventloop_tick, 1);
|
||||
rb_define_method(ip, "get_eventloop_tick", get_eventloop_tick, 0);
|
||||
rb_define_method(ip, "set_no_event_wait", set_no_event_wait, 1);
|
||||
|
|
|
@ -25,6 +25,12 @@ MultiTkIp_OK.freeze
|
|||
################################################
|
||||
# methods for construction
|
||||
class MultiTkIp
|
||||
|
||||
# ignore exception on the mainloop
|
||||
TclTkLib.mainloop_abort_on_exception = false
|
||||
|
||||
######################################
|
||||
|
||||
SLAVE_IP_ID = ['slave'.freeze, '00000']
|
||||
|
||||
@@IP_TABLE = {}
|
||||
|
|
|
@ -3359,7 +3359,7 @@ class TkObject<TkKernel
|
|||
private :tk_trace_variable
|
||||
|
||||
def destroy
|
||||
tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
|
||||
tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if defined? @var_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue