From: Tietew Date: 2003-09-18T11:39:18+09:00 Subject: [ruby-dev:21394] Per-Thread stdout が欲しい Tietew です。 表題の通りなんですが,現状プロセスグローバルな $std{in,out,err} の,スレッドローカルな奴が欲しいのです。背景としては,同じプロセ ス上で互いに無関係な ruby スクリプトがスレッドを分けた上で同時に 実行され得るアプリ(Becky! のプラグインなんですが)を開発してい て,$stdout を切り替えたときにそれが(一時的でも)全体に波及する のを防ぎたいという意図です。 本当は $KCODE もスレッドローカルが欲しいんですけど,難しそうなの と,/re/[esn] でいちおう代用できるので,保留。 他のグローバル変数は「使うな」で逃げられるし,もう非推奨なのでパ ス。 後方互換性確保のために Thread#separated_stdio フラグが真になった スレッド(および派生スレッド)のみ分離 stdio になるようにするパッ チ。struct thread のメンバに _save が付いているのは,stdout 等が マクロの環境 (VC++) があるため。 --- eval.c.orig 2003-09-11 14:30:42.000000000 +0900 +++ eval.c 2003-09-17 16:23:15.000000000 +0900 @@ -7880,4 +7880,9 @@ struct thread { VALUE thread; + + int separated_stdio; + VALUE stdout_save; + VALUE stderr_save; + VALUE stdin_save; }; @@ -8089,4 +8094,8 @@ thread_mark(th) rb_mark_tbl(th->locals); + rb_gc_mark(th->stdout_save); + rb_gc_mark(th->stderr_save); + rb_gc_mark(th->stdin_save); + /* mark data in copied stack */ if (th == curr_thread) return; @@ -8249,4 +8258,13 @@ rb_thread_save_context(th) th->last_match = tval; th->safe = ruby_safe_level; + if(th->separated_stdio) { + th->stdout_save = rb_stdout; + th->stderr_save = rb_stderr; + th->stdin_save = rb_stdin; + } else { + main_thread->stdout_save = rb_stdout; + main_thread->stderr_save = rb_stderr; + main_thread->stdin_save = rb_stdin; + } th->node = ruby_current_node; @@ -8357,4 +8375,13 @@ rb_thread_restore_context(th, exit) rb_last_status = th->last_status; ruby_safe_level = th->safe; + if(th->separated_stdio) { + rb_stdout = th->stdout_save; + rb_stderr = th->stderr_save; + rb_stdin = th->stdin_save; + } else { + rb_stdout = main_thread->stdout_save; + rb_stderr = main_thread->stderr_save; + rb_stdin = main_thread->stdin_save; + } ruby_current_node = th->node; @@ -9259,4 +9286,28 @@ rb_thread_group(thread) } +static VALUE +rb_thread_separated_stdio(thread) + VALUE thread; +{ + rb_thread_t th; + + th = rb_thread_check(thread); + return th->separated_stdio ? Qtrue : Qfalse; +} + +static VALUE +rb_thread_separated_stdio_set(thread, sep) + VALUE thread, sep; +{ + rb_thread_t th; + + th = rb_thread_check(thread); + if(th->separated_stdio && !RTEST(sep) && curr_thread != main_thread) { + th->stdout_save = th->stderr_save = th->stdin_save = Qnil; + rb_stdout = main_thread->stdout_save; + rb_stderr = main_thread->stderr_save; + rb_stdin = main_thread->stdin_save; + } + th->separated_stdio = RTEST(sep); + return sep; +} + #ifdef __ia64__ # define IA64_INIT(x) x @@ -9305,4 +9356,8 @@ rb_thread_group(thread) th->thgroup = thgroup_default;\ th->locals = 0;\ + th->separated_stdio = 0;\ + th->stdout_save = Qnil;\ + th->stderr_save = Qnil;\ + th->stdin_save = Qnil;\ } while (0) @@ -9422,4 +9477,5 @@ rb_thread_start_0(fn, arg, th_arg) th->priority = curr_thread->priority; th->thgroup = curr_thread->thgroup; + th->separated_stdio = curr_thread->separated_stdio; } @@ -10104,4 +10160,7 @@ Init_Thread() rb_define_method(rb_cThread, "group", rb_thread_group, 0); + rb_define_method(rb_cThread, "separated_stdio", rb_thread_separated_stdio, 0); + rb_define_method(rb_cThread, "separated_stdio=", rb_thread_separated_stdio_set, 1); + rb_define_method(rb_cThread, "[]", rb_thread_aref, 1); rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2); —[ Tietew ]—————————————————————————— メ : tietew@tietew.net / tietew@raug.net / tietew@masuclub.net ホペ: http://www.tietew.net/ Tietew Windows Lab. http://www.masuclub.net/ 鱒倶楽部 指紋: 26CB 71BB B595 09C4 0153 81C4 773C 963A D51B 8CAA