Top


定義場所(file name)

hotspot/src/share/vm/runtime/thread.cpp

名前(function name)

void Thread::muxAcquire (volatile intptr_t * Lock, const char * LockName) {

本体部(body)

  {- -------------------------------------------
  (1) 引数で指定されたロック(Lock)に対して, CAS で 0 から 1(LOCKBIT) への書き換えを試みる (= ロックの確保を試みる).
      CAS が成功したら, ここでリターン.
      ---------------------------------------- -}

      intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
      if (w == 0) return ;

  {- -------------------------------------------
  (1) Lock が 0 ではないがロックされてもいない (単にスレッドのポインタが入っているだけ) のであれば, 
      ロックビットを立てるために, 再度 CAS を行ってみる.
      CAS が成功したら, ここでリターン.
      ---------------------------------------- -}

      if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
         return ;
      }

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

      TEVENT (muxAcquire - Contention) ;

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      ParkEvent * const Self = Thread::current()->_MuxEvent ;

  {- -------------------------------------------
  (1) (assert)
      ---------------------------------------- -}

      assert ((intptr_t(Self) & LOCKBIT) == 0, "invariant") ;

  {- -------------------------------------------
  (1) (ロックが取れるまで, 以下の for ループを繰り返す.
       この for ループ中では, スピンロックと park による待機が繰り返される.)
      ---------------------------------------- -}

      for (;;) {

    {- -------------------------------------------
  (1.1) まず, 適当な回数だけスピンロックを行う.
        (マルチプロセッサの場合は 101 回, そうでなければ 1 回).

        なお, スピンロック処理は以下のようなもの.
          引数で指定されたロック(Lock)がロックされておらず(= LOCKBIT が立っておらず), かつ
          CAS でロックビットを立てることに成功すれば, リターンする.
        ---------------------------------------- -}

         int its = (os::is_MP() ? 100 : 0) + 1 ;

         // Optional spin phase: spin-then-park strategy
         while (--its >= 0) {
           w = *Lock ;
           if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
              return ;
           }
         }

    {- -------------------------------------------
  (1.1) カレントスレッドの _MuxEvent フィールド(以下の Self) をリセットし, OnList フィールドに値を設定しておく.
        ---------------------------------------- -}

         Self->reset() ;
         Self->OnList = intptr_t(Lock) ;
         // The following fence() isn't _strictly necessary as the subsequent
         // CAS() both serializes execution and ratifies the fetched *Lock value.
         OrderAccess::fence();

    {- -------------------------------------------
  (1.1) 引数で指定されたロック(Lock)に対して,
        カレントスレッドの _MuxEvent フィールド(以下の Self)を登録し, 
        ロック待ちだと分かる状態にする.

        登録処理は, Lock に格納されているリストの先頭に Self を追加するだけ.
        この追加処理は CAS で行う.
        CAS は失敗することもあるため, 成功するまで以下の for ループを繰り返す.

        なお, リストに追加する前に Lock のロックが解放されるケースもありうる (以下の, "(w & LOCKBIT) == 0" のパス).
        その場合は CAS でロックの確保を試み, 
        成功すれば (リストへの追加処理は止めて) この時点でリターンすることにしている.
        ---------------------------------------- -}

         for (;;) {
            w = *Lock ;
            if ((w & LOCKBIT) == 0) {
                if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
                    Self->OnList = 0 ;   // hygiene - allows stronger asserts
                    return ;
                }
                continue ;      // Interference -- *Lock changed -- Just retry
            }
            assert (w & LOCKBIT, "invariant") ;
            Self->ListNext = (ParkEvent *) (w & ~LOCKBIT );
            if (Atomic::cmpxchg_ptr (intptr_t(Self)|LOCKBIT, Lock, w) == w) break ;
         }

    {- -------------------------------------------
  (1.1) カレントスレッドの _MuxEvent フィールド(以下の Self) の OnList がクリアされるまで, 
        os::PlatformEvent::park() で待機し続ける.
        (OnList は, Thread::muxRelease() 内でクリアされる.
         See: Thread::muxRelease())
        ---------------------------------------- -}

         while (Self->OnList != 0) {
            Self->park() ;
         }
      }
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.