[#43467] [Q] thread->interrupt_flag が適切に排他制御されていないように見える — KOSAKI Motohiro <kosaki.motohiro@...>

kosakiです

15 messages 2011/05/08
[#43482] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — SASADA Koichi <ko1@...> 2011/05/08

 ささだです.

[#43486] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — KOSAKI Motohiro <kosaki.motohiro@...> 2011/05/09

>  ささだです.

[#43487] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — SASADA Koichi <ko1@...> 2011/05/09

 ささだです.

[#43488] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — KOSAKI Motohiro <kosaki.motohiro@...> 2011/05/09

>  ささだです.

[#43489] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — KOSAKI Motohiro <kosaki.motohiro@...> 2011/05/09

自己解決しました

[#43500] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — SASADA Koichi <ko1@...> 2011/05/09

 ささだです.

[#43501] Re: [Q] thread->interrupt_flag が適切に排他制御されていないように見える — KOSAKI Motohiro <kosaki.motohiro@...> 2011/05/09

>> ということは危ないのは RUBY_VM_SET_INTERRUPT() がロストしたときに、タイムアウトなしの

[#43468] Re: [ruby-changes:19438] Ruby:r31478 (trunk): * test/date/*.rb: use skip /w messages. — KOSAKI Motohiro <kosaki.motohiro@...>

2011/5/8 tadf <[email protected]>:

8 messages 2011/05/08

[#43476] [Ruby 1.9 - Feature #4653][Open] [PATCH 1/1] new method Enumerable#rude_map — Shyouhei Urabe <shyouhei@...>

16 messages 2011/05/08

[#43493] [Ruby 1.9 - Feature #4657][Open] add option to hide skip messages on unit/test — Shota Fukumori <sorah@...>

11 messages 2011/05/09

[#43502] draft schedule of Ruby 1.9.3 — "Yuki Sonoda (Yugui)" <yugui@...>

-----BEGIN PGP SIGNED MESSAGE-----

23 messages 2011/05/09
[#43505] Re: draft schedule of Ruby 1.9.3 — "U.Nakamura" <usa@...> 2011/05/10

Hello,

[#43513] Re: draft schedule of Ruby 1.9.3 — KOSAKI Motohiro <kosaki.motohiro@...> 2011/05/10

(ruby-coreはずしました)

[#43587] [Ruby 1.9 - Feature #4788][Open] resolv.rb refactoring — Makoto Kishimoto <redmine@...>

15 messages 2011/05/27

[ruby-dev:43554] [Ruby 1.9 - Bug #4696][Assigned] thread.c#lock_func() が spurious wakeup unsafe

From: Motohiro KOSAKI <kosaki.motohiro@...>
Date: 2011-05-15 07:22:19 UTC
List: ruby-dev #43554
Issue #4696 has been reported by Motohiro KOSAKI.

----------------------------------------
Bug #4696: thread.c#lock_func() が spurious wakeup unsafe
http://redmine.ruby-lang.org/issues/4696

Author: Motohiro KOSAKI
Status: Assigned
Priority: Low
Assignee: Motohiro KOSAKI
Category: core
Target version: 1.9.3
ruby -v: ruby 1.9.3dev (2011-05-13 trunk 31548) [x86_64-linux]


レビューをしていて、気づいたので起票します。
現在の lock_func (ie Mutex.lockの実体)は以下のような構造になっています
(本質的ではない部分をカットしてあります)

------------------------------------------------------------------------
static int
lock_func(rb_thread_t *th, mutex_t *mutex, int timeout_ms)
{
    for (;;) {
        if (!mutex->th) {
            mutex->th = th;
            break;
        }

        mutex->cond_waiting++;
        if (timeout_ms) {
            ret = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout);
            if (ret == ETIMEDOUT) {
                interrupted = 2;
                mutex->cond_waiting--;
                break;
            }
        }
        else {
            native_cond_wait(&mutex->cond, &mutex->lock);
        }
        mutex->cond_notified--;

        if (RUBY_VM_INTERRUPTED(th)) {
            interrupted = 1;
            break;
        }
    }
    return interrupted;
}

------------------------------------------------------------------------

以下の2つの問題点があります。

1) native_cond_wait() が spurious wakeupで起床したばあい、誰もnative_cond_signal()を
   呼んでいないにもかかわらず cond_notified がデクリメントされてしまう。
   結果、以後デッドロックチェックが誤動作する

2) pthread_cond_timedwait()で寝ているスレッドが、pthread_cond_signal()にて起床させられ、
   *かつ*、コンテキススイッチやらなにやらしている間にタイムアウト時間も過ぎてしまった場合
   戻り値が0になるかETIMEOUTになるかはプラットフォーム依存。この場合にETIMEOUTを返す
   プラットフォーム上で、復帰値のETIMEOUTを信用するとやはり mutex->cond_waiting がずれてしまう。
   対策としては、さきにcond waitが暗に持っているpredicate(この場合は mutex->th と
   RUBY_VM_INTERRUPTED のチェックを最初におこない、それが終わってからETIMEOUTチェックを
   することで、プラットフォームの影響を避けられます。

(1)は deadlock checkマージ時からの障害なんですが、YARVマージ時点ですでに
mutex->cond_waiting がずれる問題はあって、それを顕在化させる方法がなかったという理解
(2)はpthread_cond_timedwitを使うようにした r31373 からの障害


結局最大の問題はspurious wakeupがある以上、native_cond_signal()を呼ぶ回数とwakeupの回数は
一致する保証はないのだから、カウンタをcond_signal時に+1してwakeupしたときに-1する設計は
無理があるということです。

で、さらによくよく考えてみるとdeadlockの設計はもっと簡単に出来ることが分かりました。
lock_func内でunlock待ちで滞留しているスレッドの数は簡単にカウントできるのだから、
mutex->thがNULLで滞留スレッドが0じゃなければ、過度期状態ということでしょう。

パッチを作ってみたところ、添付のようにかなり小さい修正で対応できることが分かったので
取り込み可能と思いますが、1−2週間まってささださんやまめさんが反対するなら流産にさせようと
思います。


なお、軽く各プラットフォームの状況を聞いたり調べた感じだと以下のような状況
 
・Linux
  pthread_cond_wait()がglibc内でspurious wakeup対応があるので、アプリケーションからは
  spurious wakeupは見えない。linux thread だとシグナル受けるとEINTRで復帰してしまうバグが
  あるが、それは thread_pthread.c#native_cond_wait() で塞いである(r31482)ので影響を与えない。
  pthread_cond_timedwait()の復帰値はバージョンによって異なり、初期のglibcは0を返したが
  最近のはわざわざシステムコールから復帰したあとに、clock_gettime()で時間をチェックして
  時間超過していた場合は復帰値をETIMEOUTに差し替える処理が追加されており問題が起こる
  (余計なことを・・・)

・NetBSD
  上記状況で、pthread_cond_timedwait()がETIMEOUTを返す仕様であると、聞いたことがあります。

・Mac
  なんと、スレッドがシグナルと受けると cond_wait()が0を復帰値にして返ってくると言う
  トンデモ仕様だそうです。




-- 
http://redmine.ruby-lang.org

In This Thread

Prev Next