// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/heap/safepoint.h"

#include "vm/thread.h"
#include "vm/thread_registry.h"

namespace dart {

DEFINE_FLAG(bool, trace_safepoint, false, "Trace Safepoint logic.");

SafepointOperationScope::SafepointOperationScope(Thread* T)
    : ThreadStackResource(T) {
  ASSERT(T != NULL);
  Isolate* I = T->isolate();
  ASSERT(I != NULL);

  SafepointHandler* handler = I->safepoint_handler();
  ASSERT(handler != NULL);

  // Signal all threads to get to a safepoint and wait for them to
  // get to a safepoint.
  handler->SafepointThreads(T);
}

SafepointOperationScope::~SafepointOperationScope() {
  Thread* T = thread();
  ASSERT(T != NULL);
  Isolate* I = T->isolate();
  ASSERT(I != NULL);

  // Resume all threads which are blocked for the safepoint operation.
  SafepointHandler* handler = I->safepoint_handler();
  ASSERT(handler != NULL);
  handler->ResumeThreads(T);
}

SafepointHandler::SafepointHandler(Isolate* isolate)
    : isolate_(isolate),
      safepoint_lock_(),
      number_threads_not_at_safepoint_(0),
      safepoint_operation_count_(0),
      owner_(NULL) {}

SafepointHandler::~SafepointHandler() {
  ASSERT(owner_ == NULL);
  ASSERT(safepoint_operation_count_ == 0);
  isolate_ = NULL;
}

void SafepointHandler::SafepointThreads(Thread* T) {
  ASSERT(T->no_safepoint_scope_depth() == 0);
  ASSERT(T->execution_state() == Thread::kThreadInVM);

  {
    // First grab the threads list lock for this isolate
    // and check if a safepoint is already in progress. This
    // ensures that two threads do not start a safepoint operation
    // at the same time.
    MonitorLocker sl(threads_lock());

    // Now check to see if a safepoint operation is already in progress
    // for this isolate, block if an operation is in progress.
    while (SafepointInProgress()) {
      // If we are recursively invoking a Safepoint operation then we
      // just increment the count and return, otherwise we wait for the
      // safepoint operation to be done.
      if (owner_ == T) {
        increment_safepoint_operation_count();
        return;
      }
      sl.WaitWithSafepointCheck(T);
    }

    // Set safepoint in progress state by this thread.
    SetSafepointInProgress(T);

    // Go over the active thread list and ensure that all threads active
    // in the isolate reach a safepoint.
    Thread* current = isolate()->thread_registry()->active_list();
    while (current != NULL) {
      MonitorLocker tl(current->thread_lock());
      if (!current->BypassSafepoints()) {
        if (current == T) {
          current->SetAtSafepoint(true);
        } else {
          uint32_t state = current->SetSafepointRequested(true);
          if (!Thread::IsAtSafepoint(state)) {
            // Thread is not already at a safepoint so try to
            // get it to a safepoint and wait for it to check in.
            if (current->IsMutatorThread()) {
              ASSERT(T->isolate() != NULL);
              current->ScheduleInterruptsLocked(Thread::kVMInterrupt);
            }
            MonitorLocker sl(&safepoint_lock_);
            ++number_threads_not_at_safepoint_;
          }
        }
      }
      current = current->next();
    }
  }
  // Now wait for all threads that are not already at a safepoint to check-in.
  {
    MonitorLocker sl(&safepoint_lock_);
    intptr_t num_attempts = 0;
    while (number_threads_not_at_safepoint_ > 0) {
      Monitor::WaitResult retval = sl.Wait(1000);
      if (retval == Monitor::kTimedOut) {
        num_attempts += 1;
        if (FLAG_trace_safepoint && num_attempts > 10) {
          // We have been waiting too long, start logging this as we might
          // have an issue where a thread is not checking in for a safepoint.
          OS::PrintErr("Attempt:%" Pd " waiting for %d threads to check in\n",
                       num_attempts, number_threads_not_at_safepoint_);
        }
      }
    }
  }
}

void SafepointHandler::ResumeThreads(Thread* T) {
  // First resume all the threads which are blocked for the safepoint
  // operation.
  MonitorLocker sl(threads_lock());

  // First check if we are in a recursive safepoint operation, in that case
  // we just decrement safepoint_operation_count and return.
  ASSERT(SafepointInProgress());
  if (safepoint_operation_count() > 1) {
    decrement_safepoint_operation_count();
    return;
  }
  Thread* current = isolate()->thread_registry()->active_list();
  while (current != NULL) {
    MonitorLocker tl(current->thread_lock());
    if (!current->BypassSafepoints()) {
      if (current == T) {
        current->SetAtSafepoint(false);
      } else {
        uint32_t state = current->SetSafepointRequested(false);
        if (Thread::IsBlockedForSafepoint(state)) {
          tl.Notify();
        }
      }
    }
    current = current->next();
  }
  // Now reset the safepoint_in_progress_ state and notify all threads
  // that are waiting to enter the isolate or waiting to start another
  // safepoint operation.
  ResetSafepointInProgress(T);
  sl.NotifyAll();
}

void SafepointHandler::EnterSafepointUsingLock(Thread* T) {
  MonitorLocker tl(T->thread_lock());
  T->SetAtSafepoint(true);
  if (T->IsSafepointRequested()) {
    MonitorLocker sl(&safepoint_lock_);
    ASSERT(number_threads_not_at_safepoint_ > 0);
    number_threads_not_at_safepoint_ -= 1;
    sl.Notify();
  }
}

void SafepointHandler::ExitSafepointUsingLock(Thread* T) {
  MonitorLocker tl(T->thread_lock());
  ASSERT(T->IsAtSafepoint());
  while (T->IsSafepointRequested()) {
    T->SetBlockedForSafepoint(true);
    tl.Wait();
    T->SetBlockedForSafepoint(false);
  }
  T->SetAtSafepoint(false);
}

void SafepointHandler::BlockForSafepoint(Thread* T) {
  ASSERT(!T->BypassSafepoints());
  MonitorLocker tl(T->thread_lock());
  if (T->IsSafepointRequested()) {
    T->SetAtSafepoint(true);
    {
      MonitorLocker sl(&safepoint_lock_);
      ASSERT(number_threads_not_at_safepoint_ > 0);
      number_threads_not_at_safepoint_ -= 1;
      sl.Notify();
    }
    while (T->IsSafepointRequested()) {
      T->SetBlockedForSafepoint(true);
      tl.Wait();
      T->SetBlockedForSafepoint(false);
    }
    T->SetAtSafepoint(false);
  }
}

}  // namespace dart
