Top


定義場所(file name)

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

説明(description)

// Wake up all threads, so they are ready to resume execution after the safepoint
// operation has been carried out

名前(function name)

void SafepointSynchronize::end() {

本体部(body)

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

      assert(Threads_lock->owned_by_self(), "must hold Threads_lock");
      assert((_safepoint_counter & 0x1) == 1, "must be odd");

  {- -------------------------------------------
  (1) _safepoint_counter カウンタをインクリメントしておく.

      (これは JNI による高速フィールドアクセスのための処理.
       See: [here](no305911u.html) for details)
      ---------------------------------------- -}

      _safepoint_counter ++;
      // memory fence isn't required here since an odd _safepoint_counter
      // value can do no harm and a fence is issued below anyway.

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

      DEBUG_ONLY(Thread* myThread = Thread::current();)
      assert(myThread->is_VM_thread(), "Only VM thread can execute a safepoint");

  {- -------------------------------------------
  (1) (プロファイル情報の記録) & (プロファイル情報の出力)
      (See: SafepointSynchronize::end_statistics())
      ---------------------------------------- -}

      if (PrintSafepointStatistics) {
        end_statistics(os::javaTimeNanos());
      }

  {- -------------------------------------------
  (1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
      ---------------------------------------- -}

    #ifdef ASSERT
      // A pending_exception cannot be installed during a safepoint.  The threads
      // may install an async exception after they come back from a safepoint into
      // pending_exception after they unblock.  But that should happen later.
      for(JavaThread *cur = Threads::first(); cur; cur = cur->next()) {
        assert (!(cur->has_pending_exception() &&
                  cur->safepoint_state()->is_at_poll_safepoint()),
                "safepoint installed a pending exception");
      }
    #endif // ASSERT

  {- -------------------------------------------
  (1) Safepoint Polling page をアクセス不可にしていた場合は, 
      os::make_polling_page_readable() を呼んでアクセス可能な状態に戻しておく.

      (なお, PageArmed は Safepoint Polling page をアクセス不可にした場合に 1 になる変数.
       See: SafepointSynchronize::begin())
      ---------------------------------------- -}

      if (PageArmed) {
        // Make polling safepoint aware
        os::make_polling_page_readable();
        PageArmed = 0 ;
      }

  {- -------------------------------------------
  (1) Interpreter::ignore_safepoints() (またはそれをサブクラスがオーバーライドしたもの) を呼んで, 
      インタープリタの dispatch table を通常時用のものに戻す.

      (なお, SafepointSynchronize::begin() 内で呼ばれる Interpreter::notice_safepoints() と同様, 
      これは Template Interpreter の場合に必要となる処理.
      C++ Interpreter の場合は特に何もする必要は無い)
      ---------------------------------------- -}

      // Remove safepoint check from interpreter
      Interpreter::ignore_safepoints();

  {- -------------------------------------------
  (1) 以下のブロック内で, 停止している JavaThread を起床させる.
      なお, この処理は Safepoint_lock で排他した状態で行う.
      ---------------------------------------- -}

      {
        MutexLocker mu(Safepoint_lock);

    {- -------------------------------------------
  (1.1) (assert)
        ---------------------------------------- -}

        assert(_state == _synchronized, "must be synchronized before ending safepoint synchronization");

    {- -------------------------------------------
  (1.1) SafepointSynchronize::_state を _not_synchronized に戻す.
        順序も大事なので, OrderAccess::fence() でメモリバリアも張っている.
        ---------------------------------------- -}

        // Set to not synchronized, so the threads will not go into the signal_thread_blocked method
        // when they get restarted.
        _state = _not_synchronized;
        OrderAccess::fence();

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

        if (TraceSafepoint) {
           tty->print_cr("Leaving safepoint region");
        }

    {- -------------------------------------------
  (1.1) 全ての JavaThread を起床させる.
        (起床処理は, ThreadSafepointState::restart() を呼び出すことで行う)


        (なお, VMThreadHintNoPreempt オプションが指定されている場合には, 
         os::hint_no_preempt() を呼んで
         VM Thread に time slice を多めに与えてくれるよう, OS に要望を出している.

         コメントによると, これは, Solaris において 
         (この時点では VMThread が一番 CPU 使用時間が長いので)
         起床処理の途中で VMThread がデスケジューリングされて
         性能が悪くなっていたかららしい.

         ただし, このコメントには追記があり, 
         現在はそうではないので, この処理には意味が無いとのこと.)
        ---------------------------------------- -}

        // Start suspended threads
        for(JavaThread *current = Threads::first(); current; current = current->next()) {
          // A problem occurring on Solaris is when attempting to restart threads
          // the first #cpus - 1 go well, but then the VMThread is preempted when we get
          // to the next one (since it has been running the longest).  We then have
          // to wait for a cpu to become available before we can continue restarting
          // threads.
          // FIXME: This causes the performance of the VM to degrade when active and with
          // large numbers of threads.  Apparently this is due to the synchronous nature
          // of suspending threads.
          //
          // TODO-FIXME: the comments above are vestigial and no longer apply.
          // Furthermore, using solaris' schedctl in this particular context confers no benefit
          if (VMThreadHintNoPreempt) {
            os::hint_no_preempt();
          }
          ThreadSafepointState* cur_state = current->safepoint_state();
          assert(cur_state->type() != ThreadSafepointState::_running, "Thread not suspended at safepoint");
          cur_state->restart();
          assert(cur_state->is_running(), "safepoint state has not been reset");
        }

    {- -------------------------------------------
  (1.1) (DTrace のフック点) 及び 
        (プロファイル情報の記録)(JMM 用) ("sun.rt.safepointTime")

        (See: RuntimeService::record_safepoint_end())
        ---------------------------------------- -}

        RuntimeService::record_safepoint_end();

    {- -------------------------------------------
  (1.1) Safepoint 処理が終わったので, Threads_lock のロックを解除する.
        (これは SafepointSynchronize::begin() 内で取得したロック.
         See: SafepointSynchronize::begin())
        ---------------------------------------- -}

        // Release threads lock, so threads can be created/destroyed again. It will also starts all threads
        // blocked in signal_thread_blocked
        Threads_lock->unlock();

      }

  {- -------------------------------------------
  (1) #TODO
      (CMS や G1GC 向けの処理.
       concurrent thread を再開させる処理??)
      ---------------------------------------- -}

    #ifndef SERIALGC
      // If there are any concurrent GC threads resume them.
      if (UseConcMarkSweepGC) {
        ConcurrentMarkSweepThread::desynchronize(false);
      } else if (UseG1GC) {
        ConcurrentGCThread::safepoint_desynchronize();
      }
    #endif // SERIALGC

  {- -------------------------------------------
  (1) 現在時刻を _end_of_last_safepoint フィールドに記録しておく.

      (この情報は, 以下の関数から参照されている.
       See: SafepointSynchronize::last_non_safepoint_interval(), SafepointSynchronize::end_of_last_safepoint())
      ---------------------------------------- -}

      // record this time so VMThread can keep track how much time has elasped
      // since last safepoint.
      _end_of_last_safepoint = os::javaTimeMillis();
    }

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