Top


定義場所(file name)

hotspot/src/os/linux/vm/os_linux.cpp

名前(function name)

void os::PlatformEvent::park() {       // AKA "down()"

本体部(body)

  {- -------------------------------------------
  (1) (コメントによると
       os::PlatformEvent::park() を呼び出していいのは
       この os::PlatformEvent オブジェクトに関連付いているスレッドだけ.
       それを確かめる為の assert を入れたい, とのこと)
      ---------------------------------------- -}

      // Invariant: Only the thread associated with the Event/PlatformEvent
      // may call park().
      // TODO: assert that _Assoc != NULL or _Assoc == Self

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

      int v ;

  {- -------------------------------------------
  (1) Atomic::cmpxchg() で _Event フィールドの値を 1デクリメントする.
      (Atomic::cmpxchg() は失敗することもあるが, 成功するまで繰り返す)
      ---------------------------------------- -}

      for (;;) {
          v = _Event ;
          if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ;
      }

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

      guarantee (v >= 0, "invariant") ;

  {- -------------------------------------------
  (1) もし変更前の _Event フィールドの値が 0 だった場合は, 
      pthread_cond_wait() を呼んで
      誰かが unpark() してくれるまで眠りにつく.

      (なお, 以下の処理は _mutex で排他された critical section 内で行う)

      (間違って起きてしまうこともあるので, 
       目が覚めた後で _Event フィールドもチェックしている.
       _Event フィールドが負値のままであれば, 
       0 以上の値になるまで pthread_cond_wait() を呼び続ける.)

      (なお, 眠っているスレッドがいることを unpark() する側に伝えるために, 
       眠りにつく前に _nParked フィールドの値をインクリメントし, 
       unpark() されたら _nParked フィールドの値を戻している.)

      (unpark() されて待機が解けたら, _Event フィールドの値は 0 にしている.
       なお, この _Event フィールドのクリア処理は critical section 内で行っているが, 
       これは pthread_mutex_unlock() の後ろに回すとメモリバリアを置く必要があるから, との理由らしい.)
      ---------------------------------------- -}

      if (v == 0) {
         // Do this the hard way by blocking ...
         int status = pthread_mutex_lock(_mutex);
         assert_status(status == 0, status, "mutex_lock");
         guarantee (_nParked == 0, "invariant") ;
         ++ _nParked ;
         while (_Event < 0) {
            status = pthread_cond_wait(_cond, _mutex);
            // for some reason, under 2.7 lwp_cond_wait() may return ETIME ...
            // Treat this the same as if the wait was interrupted
            if (status == ETIME) { status = EINTR; }
            assert_status(status == 0 || status == EINTR, status, "cond_wait");
         }
         -- _nParked ;

        // In theory we could move the ST of 0 into _Event past the unlock(),
        // but then we'd need a MEMBAR after the ST.
        _Event = 0 ;
         status = pthread_mutex_unlock(_mutex);
         assert_status(status == 0, status, "mutex_unlock");
      }

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

      guarantee (_Event >= 0, "invariant") ;
    }

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