Top


定義場所(file name)

hotspot/src/os/solaris/vm/os_solaris.cpp

名前(function name)

void os::PlatformEvent::unpark() {

本体部(body)

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

      int v, AnyWaiters;

  {- -------------------------------------------
  (1) _Event の値が 0 より大きければ (= つまり 1 であれば), ここでリターンする.
      (なお, このプロセッサの store buffer 内の値を見てしまう恐れがあるので, 
       OrderAccess::fence() を張って確認している)

      そうでなければ Atomic::cmpxchg() で _Event の値を 1 増加させておく.
      (Atomic::cmpxchg() が失敗した場合は, 成功するまで以上の処理を繰り返す)

      (なお, コメントには他の実装方法も幾つか書かれている.
       Swap でもいい, とか, CAS でもいい, とか.)
      ---------------------------------------- -}

      // Increment _Event.
      // Another acceptable implementation would be to simply swap 1
      // into _Event:
      //   if (Swap (&_Event, 1) < 0) {
      //      mutex_lock (_mutex) ; AnyWaiters = nParked; mutex_unlock (_mutex) ;
      //      if (AnyWaiters) cond_signal (_cond) ;
      //   }

      for (;;) {
        v = _Event ;
        if (v > 0) {
           // The LD of _Event could have reordered or be satisfied
           // by a read-aside from this processor's write buffer.
           // To avoid problems execute a barrier and then
           // ratify the value.  A degenerate CAS() would also work.
           // Viz., CAS (v+0, &_Event, v) == v).
           OrderAccess::fence() ;
           if (_Event == v) return ;
           continue ;
        }
        if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
      }

  {- -------------------------------------------
  (1) 変更前の _Event の値が負値だった場合は
      park() で待機しているスレッドがいる(かもしれない)ので, 
      os::Solaris::cond_signal() で起こしてやる.

      (ただし, _nParked フィールドが 0 の場合は起床処理は行わない.
       本当に寝ているスレッドがいる場合には _nParked フィールドが 1 以上になっているはずなので.
       See: os::PlatformEvent::park()

       ついでに, この _nParked フィールドの読み取りは 
       _mutex で保護された critical section 内で行う)
      ---------------------------------------- -}

      // If the thread associated with the event was parked, wake it.
      if (v < 0) {
         int status ;
         // Wait for the thread assoc with the PlatformEvent to vacate.
         status = os::Solaris::mutex_lock(_mutex);
         assert_status(status == 0, status, "mutex_lock");
         AnyWaiters = _nParked ;
         status = os::Solaris::mutex_unlock(_mutex);
         assert_status(status == 0, status, "mutex_unlock");
         guarantee (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
         if (AnyWaiters != 0) {
           // We intentional signal *after* dropping the lock
           // to avoid a common class of futile wakeups.
           status = os::Solaris::cond_signal(_cond);
           assert_status(status == 0, status, "cond_signal");
         }
      }
    }

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