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…
	
	Add table
		Add a link
		
	
		Reference in a new issue