Top


定義場所(file name)

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

名前(function name)

void Thread::SpinAcquire (volatile int * adr, const char * LockName) {

本体部(body)

  {- -------------------------------------------
  (1) CAS により, 引数で指定されたアドレス(adr)の値を 1 に書き換えてみる 
      (元々の値は 0 と想定. つまりロックされていない状態と想定).
      書き換えが成功したら, ここでリターン.
      ---------------------------------------- -}

      if (Atomic::cmpxchg (1, adr, 0) == 0) {
         return ;   // normal fast-path return
      }

  {- -------------------------------------------
  (1) (以降はロックされていた場合(競合が起きた場合)の処理)
      ---------------------------------------- -}

      // Slow-path : We've encountered contention -- Spin/Yield/Block strategy.

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

      TEVENT (SpinAcquire - ctx) ;

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

      int ctr = 0 ;
      int Yields = 0 ;

  {- -------------------------------------------
  (1) adr の値が 0 になるまで以下の while ループ内で待機し, 
      0 になったら Atomic::cmpxchg() で 1 への書き換えを試みる.
      失敗したらまた while ループに戻る.
      以上の流れを, Atomic::cmpxchg() による書き換えが成功するまで続ける.

      なお, while ループ内での待機処理では, 以下のように処理を使い分けている.
      * マルチプロセッサでない場合 (= os::is_MP() が false の場合)
        * ループを始めてから 4回目以内 (= 以下の Yields が 5 未満の場合)
          os::NakedYield() で待機する.
        * 5 ループ目以降
          カレントスレッドの _ParkEvent に対して os::PlatformEvent::park() を呼び出して待機.
      * マルチプロセッサの場合 (= os::is_MP() が true の場合)
        * ループを始めてから 4095回目以内  (= 以下の ctr が 0xFFF 未満の場合)
          SpinPause() で待機する.
        * それ以降
          マルチプロセッサでない場合と同じ.
      ---------------------------------------- -}

      for (;;) {
         while (*adr != 0) {
            ++ctr ;
            if ((ctr & 0xFFF) == 0 || !os::is_MP()) {
               if (Yields > 5) {
                 // Consider using a simple NakedSleep() instead.
                 // Then SpinAcquire could be called by non-JVM threads
                 Thread::current()->_ParkEvent->park(1) ;
               } else {
                 os::NakedYield() ;
                 ++Yields ;
               }
            } else {
               SpinPause() ;
            }
         }
         if (Atomic::cmpxchg (1, adr, 0) == 0) return ;
      }
    }

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