* ext/tk/tkutil/tkutil.c (tk_conv_args): forget to revert

thread_critical and gc_disable when raise ArgumentError.
* ext/tk/lib/remote-tk.rb: RemoteTkIp doesn't need to include TkUtil.
* ext/tk/tcltklib.c: add TclTkIp#has_mainwindow? method.
* ext/tk/lib/tk.rb: add Tk.has_mainwindow? method.
* ext/tk/lib/multi-tk.rb: add MultiTkIp#has_mainwindow? method.
* ext/tk/lib/remote-tk.rb: add RemoteTkIp#has_mainwindow? method.
* ext/tk/lib/multi-tk.rb: slave IP fail to exit itself when $SAFE==4.
* ext/tk/lib/multi-tk.rb: remove constants from MultiTkIp module to
  avoid access from external.
* ext/tk/lib/multi-tk.rb: check_root flag is ignored on slave IPs'
  mainloop.
* ext/tk/lib/multi-tk.rb: hang-up Tk.mainloop called on a slave IP
  with $SAFE==4.
* ext/tk/lib/multi-tk.rb: MultiTkIp#bg_eval_proc doesn't work
  properly.
* ext/tk/lib/multi-tk.rb: add MultiTkIp#set_cb_error(proc) and
  cb_error(exc) to log errors at callbacks on safe slave IPs.
* ext/tk/lib/multi-tk.rb: fail to get an available slave IP object
  when call Tk.mainloop in the block which is given to new_* method,
  because cannot finish initialize while the root widget is alive.
* ext/tk/lib/multi-tk.rb: fail to control a slave IP when Tk.mainloop
  runs on the IP.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8818 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nagai 2005-07-21 22:05:04 +00:00
Родитель 0580cf2696
Коммит 17743ce0a8
8 изменённых файлов: 223 добавлений и 64 удалений

Просмотреть файл

@ -1,3 +1,42 @@
Fri Jul 22 07:01:42 2005 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/tkutil/tkutil.c (tk_conv_args): forget to revert
thread_critical and gc_disable when raise ArgumentError.
* ext/tk/lib/remote-tk.rb: RemoteTkIp doesn't need to include TkUtil.
* ext/tk/tcltklib.c: add TclTkIp#has_mainwindow? method.
* ext/tk/lib/tk.rb: add Tk.has_mainwindow? method.
* ext/tk/lib/multi-tk.rb: add MultiTkIp#has_mainwindow? method.
* ext/tk/lib/remote-tk.rb: add RemoteTkIp#has_mainwindow? method.
* ext/tk/lib/multi-tk.rb: slave IP fail to exit itself when $SAFE==4.
* ext/tk/lib/multi-tk.rb: remove constants from MultiTkIp module to
avoid access from external.
* ext/tk/lib/multi-tk.rb: check_root flag is ignored on slave IPs'
mainloop.
* ext/tk/lib/multi-tk.rb: hang-up Tk.mainloop called on a slave IP
with $SAFE==4.
* ext/tk/lib/multi-tk.rb: MultiTkIp#bg_eval_proc doesn't work
properly.
* ext/tk/lib/multi-tk.rb: add MultiTkIp#set_cb_error(proc) and
cb_error(exc) to log errors at callbacks on safe slave IPs.
* ext/tk/lib/multi-tk.rb: fail to get an available slave IP object
when call Tk.mainloop in the block which is given to new_* method,
because cannot finish initialize while the root widget is alive.
* ext/tk/lib/multi-tk.rb: fail to control a slave IP when Tk.mainloop
runs on the IP.
Thu Jul 21 01:00:00 2005 NARUSE, Yui <naruse@ruby-lang.org>
* ext/nkf/nkf-utf8/{nkf.c,utf8tbl.c,config.h}:

Просмотреть файл

@ -310,6 +310,11 @@ class TclTkIp
: Check whether the interpreter is already deleted.
: If deleted, returns true.
has_mainwindow?
: Check whether the interpreter has a MainWindow (root widget).
: If has, returns true. If doesn't, returns false.
: If IP is already deleted, returns nil.
restart
: Restart Tk part of the interpreter.
: Use this when you need Tk functions after destroying the

Просмотреть файл

@ -422,6 +422,11 @@ require "tcltklib"
: delete 済みでコマンドを受け付けない状態になっているならば
: true を返す.
has_mainwindow?
: Tcl/Tk インタープリタにメインウィンドウ (root widget) が
: 存在すれば true を,存在しなければ false を返す.
: インタープリタが既に delete 済みであれば nil を返す.
restart
: Tcl/Tk インタープリタの Tk 部分の初期化,再起動を行う.
: 一旦 root widget を破壊した後に再度 Tk の機能が必要と

Просмотреть файл

@ -7,7 +7,7 @@ require 'tkutil'
require 'thread'
if defined? Tk
fail RuntimeError, "'multi-tk' library must be required before requiring 'tk'"
fail RuntimeError,"'multi-tk' library must be required before requiring 'tk'"
end
################################################
@ -54,7 +54,7 @@ MultiTkIp_OK.freeze
################################################
# methods for construction
class MultiTkIp
SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
@@IP_TABLE = {}.taint unless defined?(@@IP_TABLE)
@ -86,9 +86,26 @@ class MultiTkIp
@ip.cb_eval(@cmd, *args)
rescue TkCallbackBreak, TkCallbackContinue => e
fail e
rescue SecurityError => e
# in 'exit', 'exit!', and 'abort' : security error --> delete IP
if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/
@ip.delete
elsif @ip.safe?
if @ip.respond_to?(:cb_error)
@ip.cb_error(e)
else
nil # ignore
end
else
fail e
end
rescue Exception => e
if @ip.safe?
nil # ignore
if @ip.respond_to?(:cb_error)
@ip.cb_error(e)
else
nil # ignore
end
else
fail e
end
@ -161,6 +178,18 @@ class MultiTkIp
######################################
def set_cb_error(cmd = Proc.new)
@cb_error_proc[0] = cmd
end
def cb_error(e)
if @cb_error_proc[0].respond_to?(:call)
@cb_error_proc[0].call(e)
end
end
######################################
def set_safe_level(safe)
if safe > @safe_level[0]
@safe_level[0] = safe
@ -192,7 +221,7 @@ class MultiTkIp
end
def running_mainloop?
@wait_on_mainloop[1]
@wait_on_mainloop[1] > 0
end
def _destroy_slaves_of_slaveIP(ip)
@ -442,13 +471,21 @@ class MultiTkIp
private :_receiver_eval_proc, :_receiver_eval_proc_core
def _receiver_mainloop(check_root)
Thread.new{
while !@interp.deleted?
inf = @interp._invoke_without_enc('info', 'command', '.')
break if !inf.kind_of?(String) || inf != '.'
sleep 0.5
end
}
if @evloop_thread[0] && @evloop_thread[0].alive?
@evloop_thread[0]
else
@evloop_thread[0] = Thread.new{
while !@interp.deleted?
#if check_root
# inf = @interp._invoke_without_enc('info', 'command', '.')
# break if !inf.kind_of?(String) || inf != '.'
#end
break if check_root && !@interp.has_mainwindow?
sleep 0.5
end
}
@evloop_thread[0]
end
end
def _create_receiver_and_watchdog(lvl = $SAFE)
@ -456,7 +493,7 @@ class MultiTkIp
# command-procedures receiver
receiver = Thread.new(lvl){|safe_level|
last_thread = nil
last_thread = {}
loop do
break if @interp.deleted?
@ -479,8 +516,9 @@ class MultiTkIp
else
# procedure
last_thread = _receiver_eval_proc(last_thread, safe_level,
thread, cmd, *args)
last_thread[thread] = _receiver_eval_proc(last_thread[thread],
safe_level, thread,
cmd, *args)
end
end
}
@ -539,6 +577,8 @@ class MultiTkIp
@slave_ip_top = {}.taint
@evloop_thread = [].taint
unless keys.kind_of? Hash
fail ArgumentError, "expecting a Hash object for the 2nd argument"
end
@ -548,7 +588,7 @@ class MultiTkIp
@system = Object.new
@wait_on_mainloop = [true, false]
@wait_on_mainloop = [true, 0].taint
@threadgroup = Thread.current.group
@ -657,7 +697,7 @@ class MultiTkIp
######################################
SAFE_OPT_LIST = [
@@SAFE_OPT_LIST = [
'accessPath'.freeze,
'statics'.freeze,
'nested'.freeze,
@ -676,7 +716,7 @@ class MultiTkIp
name = v
elsif k_str == 'safe'
safe = v
elsif SAFE_OPT_LIST.member?(k_str)
elsif @@SAFE_OPT_LIST.member?(k_str)
safe_opts[k_str] = v
else
tk_opts[k_str] = v
@ -692,8 +732,8 @@ class MultiTkIp
private :_parse_slaveopts
def _create_slave_ip_name
name = SLAVE_IP_ID.join('')
SLAVE_IP_ID[1].succ!
name = @@SLAVE_IP_ID.join('')
@@SLAVE_IP_ID[1].succ!
name
end
private :_create_slave_ip_name
@ -924,11 +964,15 @@ class MultiTkIp
@tk_table_list = []
@slave_ip_tbl = {}
@slave_ip_top = {}
@cb_error_proc = []
@evloop_thread = []
@tk_windows.taint unless @tk_windows.tainted?
@tk_table_list.taint unless @tk_table_list.tainted?
@slave_ip_tbl.taint unless @slave_ip_tbl.tainted?
@slave_ip_top.taint unless @slave_ip_top.tainted?
@cb_error_proc.taint unless @cb_error_proc.tainted?
@evloop_thread.taint unless @evloop_thread.tainted?
name, safe, safe_opts, tk_opts = _parse_slaveopts(keys)
@ -975,7 +1019,8 @@ class MultiTkIp
@system = Object.new
@wait_on_mainloop = [true, false]
@wait_on_mainloop = [true, 0].taint
# @wait_on_mainloop = [false, 0].taint
@threadgroup = ThreadGroup.new
@ -1088,7 +1133,10 @@ class << MultiTkIp
end
ip = __new(__getip, nil, keys)
ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
#ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
if block_given?
Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
end
ip
end
@ -1109,7 +1157,10 @@ class << MultiTkIp
end
ip = __new(__getip, false, keys)
ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
# ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
if block_given?
Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
end
ip
end
alias new_trusted_slave new_slave
@ -1127,7 +1178,10 @@ class << MultiTkIp
end
ip = __new(__getip, true, keys)
ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
# ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
if block_given?
Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
end
ip
end
alias new_safeTk new_safe_slave
@ -1504,7 +1558,11 @@ class MultiTkIp
backup_ip = current['callback_ip']
current['callback_ip'] = self
begin
eval_proc_core(false, cmd, safe_level, *args)
eval_proc_core(false,
proc{|safe, *params|
$SAFE=safe if $SAFE < safe
cmd.call(*params)
}, safe_level, *args)
ensure
current['callback_ip'] = backup_ip
end
@ -1514,7 +1572,7 @@ class MultiTkIp
$SAFE=safe if $SAFE < safe
Thread.new(*params, &cmd).value
},
*args)
safe_level, *args)
end
end
alias call eval_proc
@ -1528,15 +1586,19 @@ class MultiTkIp
end
end
Thread.new{
eval_proc(cmd, *args)
=begin
eval_proc_core(false,
proc{|safe, *params|
$SAFE=safe if $SAFE < safe
Thread.new(*params, &cmd).value
},
*args)
safe_level, *args)
=end
}
end
alias background_eval_proc bg_eval_proc
alias thread_eval_proc bg_eval_proc
alias bg_call bg_eval_proc
alias background_call bg_eval_proc
@ -1550,7 +1612,7 @@ class MultiTkIp
proc{|safe|
$SAFE=safe if $SAFE < safe
Kernel.eval(cmd, *eval_args)
})
}, safe_level)
end
alias eval_str eval_string
@ -1564,7 +1626,7 @@ class MultiTkIp
proc{|safe|
$SAFE=safe if $SAFE < safe
Kernel.eval(cmd, *eval_args)
})
}, safe_level)
}
end
alias background_eval_string bg_eval_string
@ -1679,6 +1741,10 @@ class << MultiTkIp
__getip.deleted?
end
def has_mainwindow?
__getip.has_mainwindow?
end
def invalid_namespace?
__getip.invalid_namespace?
end
@ -1860,22 +1926,24 @@ class MultiTkIp
if self != @@DEFAULT_MASTER
if @wait_on_mainloop[0]
begin
@wait_on_mainloop[1] = true
@cmd_queue.enq([@system, 'call_mainloop',
Thread.current, check_root])
Thread.stop
@wait_on_mainloop[1] += 1
if $SAFE >= 4
_receiver_mainloop(check_root).join
else
@cmd_queue.enq([@system, 'call_mainloop',
Thread.current, check_root])
Thread.stop
end
rescue MultiTkIp_OK => ret
# return value
@wait_on_mainloop[1] = false
if ret.value.kind_of?(Thread)
return ret.value.value
else
return ret.value
end
rescue SystemExit
rescue SystemExit => e
# exit IP
warn("Warning: " + $! + " on " + self.inspect) if $DEBUG
@wait_on_mainloop[1] = false
begin
self._eval_without_enc('exit')
rescue Exception
@ -1887,17 +1955,18 @@ class MultiTkIp
((e.message.length > 0)? ' "' + e.message + '"': '') +
" on " + self.inspect)
end
@wait_on_mainloop[1] = false
return e
rescue Exception => e
return e
ensure
@wait_on_mainloop[1] = false
@wait_on_mainloop[1] -= 1
end
end
return
end
unless restart_on_dead
@wait_on_mainloop[1] = true
@wait_on_mainloop[1] += 1
=begin
begin
@interp.mainloop(check_root)
@ -1909,11 +1978,13 @@ class MultiTkIp
end
end
=end
@interp.mainloop(check_root)
@wait_on_mainloop[1] = false
begin
@interp.mainloop(check_root)
ensure
@wait_on_mainloop[1] -= 1
end
else
loop do
@wait_on_mainloop[1] = true
break unless self.alive?
if check_root
begin
@ -1924,6 +1995,7 @@ class MultiTkIp
end
break if @interp.deleted?
begin
@wait_on_mainloop[1] += 1
@interp.mainloop(check_root)
rescue StandardError => e
if TclTkLib.mainloop_abort_on_exception != nil
@ -1948,7 +2020,7 @@ class MultiTkIp
=end
raise e
ensure
@wait_on_mainloop[1] = false
@wait_on_mainloop[1] -= 1
Thread.pass # avoid eventloop conflict
end
end
@ -2040,6 +2112,10 @@ class MultiTkIp
@interp.deleted?
end
def has_mainwindow?
@interp.has_mainwindow?
end
def invalid_namespace?
@interp.invalid_namespace?
end

Просмотреть файл

@ -60,8 +60,6 @@ class << RemoteTkIp
end
class RemoteTkIp
include TkUtil
def initialize(remote_ip, displayof=nil, timeout=5)
if $SAFE >= 4
fail SecurityError, "cannot access another interpreter at level #{$SAFE}"
@ -96,7 +94,7 @@ class RemoteTkIp
@safe_level = [$SAFE]
@wait_on_mainloop = [true, false]
@wait_on_mainloop = [true, 0]
@cmd_queue = Queue.new
@ -179,7 +177,7 @@ class RemoteTkIp
fail SecurityError, "cannot send tainted commands at level #{$SAFE}"
end
cmds = @interp._merge_tklist(*_conv_args([], enc_mode, *cmds))
cmds = @interp._merge_tklist(*TkUtil::_conv_args([], enc_mode, *cmds))
if @displayof
if async
@interp.__invoke('send', '-async', '-displayof', @displayof,
@ -283,6 +281,19 @@ class RemoteTkIp
end
end
def has_mainwindow?
begin
inf = @interp._invoke_without_enc('info', 'command', '.')
rescue Exception
return nil
end
if !inf.kind_of?(String) || inf != '.'
false
else
true
end
end
def invalid_namespace?
false
end
@ -343,25 +354,25 @@ class RemoteTkIp
def _get_variable(var_name, flag)
# ignore flag
_appsend(false, 'set', _get_eval_string(var_name))
_appsend(false, 'set', TkComm::_get_eval_string(var_name))
end
def _get_variable2(var_name, index_name, flag)
# ignore flag
_appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})")
_appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})")
end
def _set_variable(var_name, value, flag)
# ignore flag
_appsend(false, 'set', _get_eval_string(var_name), _get_eval_string(value))
_appsend(false, 'set', TkComm::_get_eval_string(var_name), TkComm::_get_eval_string(value))
end
def _set_variable2(var_name, index_name, value, flag)
# ignore flag
_appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})", _get_eval_string(value))
_appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})", TkComm::_get_eval_string(value))
end
def _unset_variable(var_name, flag)
# ignore flag
_appsend(false, 'unset', _get_eval_string(var_name))
_appsend(false, 'unset', TkComm::_get_eval_string(var_name))
end
def _unset_variable2(var_name, index_name, flag)
# ignore flag
@ -369,21 +380,21 @@ class RemoteTkIp
end
def _get_global_var(var_name)
_appsend(false, 'set', _get_eval_string(var_name))
_appsend(false, 'set', TkComm::_get_eval_string(var_name))
end
def _get_global_var2(var_name, index_name)
_appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})")
_appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})")
end
def _set_global_var(var_name, value)
_appsend(false, 'set', _get_eval_string(var_name), _get_eval_string(value))
_appsend(false, 'set', TkComm::_get_eval_string(var_name), TkComm::_get_eval_string(value))
end
def _set_global_var2(var_name, index_name, value)
_appsend(false, 'set', "#{_get_eval_string(var_name)}(#{_get_eval_string(index_name)})", _get_eval_string(value))
_appsend(false, 'set', "#{TkComm::_get_eval_string(var_name)}(#{TkComm::_get_eval_string(index_name)})", TkComm::_get_eval_string(value))
end
def _unset_global_var(var_name)
_appsend(false, 'unset', _get_eval_string(var_name))
_appsend(false, 'unset', TkComm::_get_eval_string(var_name))
end
def _unset_global_var2(var_name, index_name)
_appsend(false, 'unset', "#{var_name}(#{index_name})")

Просмотреть файл

@ -1833,6 +1833,10 @@ module Tk
code
end
def Tk.has_mainwindow?
INTERP.has_mainwindow?
end
def root
TkRoot.new
end
@ -4195,7 +4199,7 @@ end
#Tk.freeze
module Tk
RELEASE_DATE = '2005-07-19'.freeze
RELEASE_DATE = '2005-07-22'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'

Просмотреть файл

@ -4,7 +4,7 @@
* Oct. 24, 1997 Y. Matsumoto
*/
#define TCLTKLIB_RELEASE_DATE "2005-07-19"
#define TCLTKLIB_RELEASE_DATE "2005-07-22"
#include "ruby.h"
#include "rubysig.h"
@ -511,6 +511,7 @@ get_ip(self)
}
if (ptr->ip == (Tcl_Interp*)NULL) {
/* rb_raise(rb_eRuntimeError, "deleted IP"); */
return((struct tcltkip *)NULL);
}
return ptr;
}
@ -5293,6 +5294,22 @@ ip_is_deleted_p(self)
}
}
static VALUE
ip_has_mainwindow_p(self)
VALUE self;
{
struct tcltkip *ptr = get_ip(self);
if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL
|| Tcl_InterpDeleted(ptr->ip)) {
return Qnil;
} else if (Tk_MainWindow(ptr->ip) == (Tk_Window)NULL) {
return Qfalse;
} else {
return Qtrue;
}
}
static VALUE
#ifdef HAVE_STDARG_PROTOTYPES
@ -8557,6 +8574,7 @@ Init_tcltklib()
rb_define_method(ip, "allow_ruby_exit=", ip_allow_ruby_exit_set, 1);
rb_define_method(ip, "delete", ip_delete, 0);
rb_define_method(ip, "deleted?", ip_is_deleted_p, 0);
rb_define_method(ip, "has_mainwindow?", ip_has_mainwindow_p, 0);
rb_define_method(ip, "invalid_namespace?", ip_has_invalid_namespace_p, 0);
rb_define_method(ip, "_eval", ip_eval, 1);
rb_define_method(ip, "_toUTF8", ip_toUTF8, -1);

Просмотреть файл

@ -8,7 +8,7 @@
************************************************/
#define TKUTIL_RELEASE_DATE "2005-07-05"
#define TKUTIL_RELEASE_DATE "2005-07-22"
#include "ruby.h"
#include "rubysig.h"
@ -892,14 +892,14 @@ tk_conv_args(argc, argv, self)
int thr_crit_bup;
VALUE old_gc;
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
old_gc = rb_gc_disable();
if (argc < 2) {
rb_raise(rb_eArgError, "too few arguments");
}
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
old_gc = rb_gc_disable();
for(size = 0, idx = 2; idx < argc; idx++) {
if (TYPE(argv[idx]) == T_HASH) {
size += 2 * RHASH(argv[idx])->tbl->num_entries;
@ -1605,6 +1605,7 @@ Init_tkutil()
tk_get_eval_string, -1);
rb_define_singleton_method(mTK, "_get_eval_enc_str",
tk_get_eval_enc_str, 1);
rb_define_singleton_method(mTK, "_conv_args", tk_conv_args, -1);
rb_define_singleton_method(mTK, "bool", tcl2rb_bool, 1);
rb_define_singleton_method(mTK, "number", tcl2rb_number, 1);