From: Tanaka Akira Date: 2006-03-03T02:20:12+09:00 Subject: [ruby-dev:28417] make install may make other ruby processs SEGV. たまに、動いている ruby プロセスがあるときに make install し てしまうことがあるのですが、そのときにその ruby プロセスが segv になることがあります。 例えば、以下のようなプログラムを動かしている途中に他の window から make install-nodoc すると segv になります。 % ./ruby -rzlib -e ' loop { p Zlib::Deflate.deflate("a") sleep 1 }' "x\234K\004\000\000b\000b" "x\234K\004\000\000b\000b" "x\234K\004\000\000b\000b" "x\234K\004\000\000b\000b" "x\234K\004\000\000b\000b" zsh: segmentation fault ./ruby -rzlib -e ' loop { p Zlib::Deflate.deflate("a") sleep 1 }' % ./ruby -v ruby 1.9.0 (2006-03-02) [i686-linux] この問題は shared library を書き換えてしまうとプロセスが使っ ているコードが変わってしまうというところにあります。たぶん。 ところで、GNU cp には --remove-destination という、ファイル をコピーする前にコピー先を削除するというオプションがあります。 というわけで、FileUtils.cp_rf に :remove_destination という オプションを追加し、ext/extmk.rb でそれを使う、というふうに するといいんじゃないかとおもうんですがどうでしょう? Index: ext/extmk.rb =================================================================== RCS file: /src/ruby/ext/extmk.rb,v retrieving revision 1.86 diff -u -p -r1.86 extmk.rb --- ext/extmk.rb 20 Feb 2006 08:34:49 -0000 1.86 +++ ext/extmk.rb 2 Mar 2006 17:09:32 -0000 @@ -381,7 +381,7 @@ if $extout RbConfig.expand(extout = "#$extout", RbConfig::CONFIG.merge("topdir"=>$topdir)) if $install RbConfig.expand(dest = "#{$destdir}#{$rubylibdir}") - FileUtils.cp_r(extout+"/.", dest, :verbose => true, :noop => $dryrun) + FileUtils.cp_r(extout+"/.", dest, :remove_destination => true, :verbose => true, :noop => $dryrun) exit end unless $ignore Index: lib/fileutils.rb =================================================================== RCS file: /src/ruby/lib/fileutils.rb,v retrieving revision 1.69 diff -u -p -r1.69 fileutils.rb --- lib/fileutils.rb 19 Jan 2006 13:20:23 -0000 1.69 +++ lib/fileutils.rb 2 Mar 2006 17:09:33 -0000 @@ -392,7 +392,7 @@ module FileUtils OPT_TABLE['copy'] = %w( noop verbose preserve ) # - # Options: preserve noop verbose dereference_root + # Options: preserve noop verbose dereference_root remove_destination # # Copies +src+ to +dest+. If +src+ is a directory, this method copies # all its contents recursively. If +dest+ is a directory, copies @@ -415,11 +415,11 @@ module FileUtils # # but this doesn't. # def cp_r(src, dest, options = {}) - fu_check_options options, :preserve, :noop, :verbose, :dereference_root - fu_output_message "cp -r#{options[:preserve] ? 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] + fu_check_options options, :preserve, :noop, :verbose, :dereference_root, :remove_destination + fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose] return if options[:noop] fu_each_src_dest(src, dest) do |s, d| - copy_entry s, d, options[:preserve], options[:dereference_root] + copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination] end end module_function :cp_r @@ -440,9 +440,12 @@ module FileUtils # # If +dereference_root+ is true, this method dereference tree root. # - def copy_entry(src, dest, preserve = false, dereference_root = false) + # If +remove_destination+ is true, this method removes each destination file before copy. + # + def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) Entry_.new(src, nil, dereference_root).traverse do |ent| destent = Entry_.new(dest, ent.rel, false) + File.unlink destent.path if remove_destination && File.file?(destent.path) ent.copy destent.path ent.copy_metadata destent.path if preserve end -- Tanaka Akira