Bug #5439
closedBug #5350: WeakRef で謎の NoMethodError
r33361以降sample/test.rb:systemがFになる
Description
r33361の変更により、ccでコンパイルすると、プログラム終了時にfinalizerが呼ばれなくなり、sample/test.rb:system にFが出ます。
(Solaris 10, sparc, Sun Studio 11 にて確認)
% make test
(中略)
sample/test.rb:eval .............................
sample/test.rb:system .FFFF.F.
sample/test.rb:const .....
(中略)
sample/test.rb:path .......................
sample/test.rb:gc ....make: *** [yes-test-sample] Error 1
Fが出ているテストの1つは以下です。
test_ok(./miniruby -e 'print "foobar"' == 'foobar')
r33361の変更で、以下の文が2か所に追加されています。
if (ATOMIC_SET(finalizing, 1)) return;
マクロ ATOMIC_SET() は、gccの場合(ただしWindows以外)、
define ATOMIC_SET(var, val) __sync_lock_test_and_set(&(var), (val))¶
に展開され、http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html によるとこの関数は
returns the previous contents of *ptr.
つまり、その変数に以前セットされていた値を返しますが、
gccおよびWIN32以外(Solarisのccなど)では、
define ATOMIC_SET(var, val) ((var) = (val))¶
に展開される、つまり、新しく代入した値を返すため、
if (ATOMIC_SET(finalizing, 1)) return;
は、ATOMIC_SET(finalizing, 1)が必ず1を返すため、常にreturnしてしまいます。
このため、多くのfinalizerが呼ばれないままプログラムが終了し、rb_io_fptr_finalizeなどで行われているバッファのフラッシュも行われないためFになったと推測します。
        
           Updated by shyouhei (Shyouhei Urabe) about 14 years ago
          Updated by shyouhei (Shyouhei Urabe) about 14 years ago
          
          
        
        
      
      その他のコンパイラの場合はそれはそれで修正すべきと思いますが、sparc上のccにはatomic test and setみたいなインストラクション(があるのか存じ上げませんが)を生成する方法はないのでしょうか? あるのならそちらを使うようにするのが筋という気がします。
        
           Updated by kosaki (Motohiro KOSAKI) about 14 years ago
          Updated by kosaki (Motohiro KOSAKI) about 14 years ago
          
          
        
        
      
      代入前の値を知りたいときは ATOMIC_EXCHANGE 使わないとダメ。
やらないといけないことが3つあって
1.ATOMIC_SETに void キャストいれて、戻り値使おうとしたらコンパイルエラーになるようにする
2.指摘されてる間違った ATOMIC_SEC を ATOMIC_EXCHANGEに変換
3.いまatomicに対応してるのはgccとVCだけなので、#if defined(__SUNPRO_CC) だったら
http://www.unix.com/man-page/OpenSolaris/9f/atomic_ops/
の命令つかって、atomicに動くように実装する
1と2はこちらでさっくり出来そうですが、3はこちらではコンパイルテストすら出来ないので
協力していただけると助かります
        
           Updated by ngoto (Naohisa Goto) about 14 years ago
          Updated by ngoto (Naohisa Goto) about 14 years ago
          
          
        
        
      
      3.いまatomicに対応してるのはgccとVCだけなので、#if defined(__SUNPRO_CC) だったら http://www.unix.com/man-page/OpenSolaris/9f/atomic_ops/ の命令つかって、atomicに動くように実装する
Solaris10ではヘッダの場所が #include <atomic.h> となっているのがOpenSolarisと違いますが、関数の仕様は同じのようです。(もっとも、Solaris10 の atomic.h を覗いたら、単に #include <sys/atomic.h> しているだけでしたが)
https://sites.google.com/a/diviware.com/unix/unix-page/solaris-page/solaris-man-pages/3c/atomic_ops
NetBSDなど他のOSにも同等/類似の関数があるようですので、configureで判別するほうが幸せかもしれません。
http://www.daemon-systems.org/man/atomic_ops.3.html
        
           Updated by nobu (Nobuyoshi Nakada) about 14 years ago
          Updated by nobu (Nobuyoshi Nakada) about 14 years ago
          
          
        
        
      
      - Status changed from Open to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r33460.
Naohisa, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- gc.c (rb_gc_finalize_deferred, rb_objspace_call_finalizer):
 should use ATOMIC_EXCHANGE() to check the previous value.
 [ruby-dev:44596] [Bug #5439]