From: Yoshinori Toki Date: 1999-05-05T20:11:05+09:00 Subject: [ruby-list:14133] Thread safe eRuby ----Next_Part(Wed_May__5_20:12:25_1999_809)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit 土岐です。 連休中、shttpsrv-1.0.4 に [ruby-list:11253] と [ruby-list:13043] のパッ チを当てて servlet & eRuby サーバにして色々試していたら、どうやら erb.rb ([ruby-list:13998]) はスレッドセーフになっていないようだったの で、スレッドセーフになるようにちょっといじってみました。 添付のパッチで erb.rb に以下の修正を加えます。 1. クラスメソッドの ERb::StringIO::as_stdout がスレッドセーフになるように 修正しました。 2. クラスメソッドとして呼び出されているモジュール関数の ERb::compile がス レッドセーフでなかったので、ERb#initialize の中で ERb#setup_compiler, ERb#compile をインスタンスメソッドとして呼び出すようにしました。 ---------------------------------------------------------------------------- 土岐 仁謙 神戸大学物理高エネ研 M2 URL: http://www3.phys.sci.kobe-u.ac.jp/~toki/index.html PGP fingerprint = D0 A8 90 AB 73 F8 34 FE CE CA DB BF 01 30 C0 35 ----Next_Part(Wed_May__5_20:12:25_1999_809)-- Content-Type: Text/Plain; charset=iso-2022-jp Content-Disposition: attachment; filename=erb.diff-19990504 Content-Transfer-Encoding: 7bit *** /usr/local/lib/ruby/site_ruby/erb.rb Sat May 1 11:16:53 1999 --- erb.rb Wed May 5 17:00:23 1999 *************** *** 4,9 **** --- 4,10 ---- # Copyright (c) 1999 Masatoshi SEKI require 'enumre.rb' # http://www2a.biglobe.ne.jp/%7Eseki/ruby/enumre.rb + require 'thread.rb' class ERb Revision = '$Date: 1999/03/27 20:21:15 $' *************** *** 13,63 **** end module_function :version ! class StringIO ! def initialize(str='') ! @str = str.to_s ! end ! attr :str ! def print (*arg) ! if $, ! sep = $, ! else ! sep = '' ! end ! write(arg.join(sep)) ! end ! def write(str) ! @str.concat(str) ! end ! def as_stdout(&proc) ! begin ! writer = self.new ! save = $> ! $> = writer ! proc.call ! writer.str ! ensure ! $> = save if save ! end ! end ! module_function :as_stdout ! def as_stdout_safe(safe, &proc) ! begin ! writer = self.new ! save = $> ! $> = writer ! th = Thread.start { ! $SAFE = safe ! proc.call ! writer.str ! } ! Thread.join th ! th.value ! ensure ! $> = save if save end end ! module_function :as_stdout_safe end def pre_compile(s) --- 14,80 ---- end module_function :version ! module StringIO ! @m = Mutex.new ! @count = 0 ! @context = {} ! @saved_out = nil ! OUT = Object.new ! ! class << self ! def as_stdout(safe=nil) ! Thread.new{ ! $SAFE = safe if safe ! ! out = "" ! @m.synchronize do ! if (@count == 0) then ! @saved_out = $> ! $> = OUT ! end ! @count += 1 ! @context[Thread::current()] = out ! end ! ! begin ! yield ! ensure ! @m.synchronize do ! @context[Thread::current()] = nil ! @count -= 1 ! if (@count == 0) then ! $> = @saved_out ! @saved_out = nil ! end ! end ! end ! out ! }.value ! end ! ! def write(str) ! @m.synchronize do ! if (out = @context[Thread::current()]) then ! out.concat(str) ! str.length ! else ! if (@saved_out) then ! @saved_out.write(str) ! else ! $<.write(str) ! end ! end ! end end end ! ! def OUT.write(str) ! StringIO::write(str) ! end ! ! def OUT.print(*args) ! write(args.join(if ($,) then $, else "" end)) ! end end def pre_compile(s) *************** *** 140,146 **** private :setup_compiler def initialize(str, safe_level=nil) ! @src = ERb.compile(str) @safe_level = safe_level end attr :src --- 157,164 ---- private :setup_compiler def initialize(str, safe_level=nil) ! setup_compiler ! @src = compile(str) @safe_level = safe_level end attr :src *************** *** 158,168 **** # 実行し、結果を文字列で返す def result(b=TOPLEVEL_BINDING) ! if @safe_level ! StringIO.as_stdout_safe(@safe_level) { eval(@src, b) } ! else ! StringIO.as_stdout { eval(@src, b) } ! end end end --- 176,182 ---- # 実行し、結果を文字列で返す def result(b=TOPLEVEL_BINDING) ! StringIO.as_stdout(@safe_level) { eval(@src, b) } end end ----Next_Part(Wed_May__5_20:12:25_1999_809)----