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