Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  stackWatermark.cpp   Sprache: C

 
/*
 * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */


#include "precompiled.hpp"
#include "logging/log.hpp"
#include "runtime/atomic.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/osThread.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/stackFrameStream.inline.hpp"
#include "runtime/stackWatermark.inline.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"

class StackWatermarkFramesIterator : public CHeapObj<mtThread> {
  JavaThread* _jt;
  uintptr_t _caller;
  uintptr_t _callee;
  StackFrameStream _frame_stream;
  StackWatermark& _owner;
  bool _is_done;

  void set_watermark(uintptr_t sp);
  RegisterMap& register_map();
  frame& current();
  void next();

public:
  StackWatermarkFramesIterator(StackWatermark& owner);
  uintptr_t caller() const { return _caller; }
  uintptr_t callee() const { return _callee; }
  void process_one(void* context);
  void process_all(void* context);
  bool has_next() const;
};

void StackWatermarkFramesIterator::set_watermark(uintptr_t sp) {
  if (!has_next()) {
    return;
  }

  if (_callee == 0) {
    _callee = sp;
  } else if (_caller == 0) {
    _caller = sp;
  } else {
    _callee = _caller;
    _caller = sp;
  }
}

// This class encapsulates various marks we need to deal with calling the
// frame processing code from arbitrary points in the runtime. It is mostly
// due to problems that we might want to eventually clean up inside of the
// frame processing code, such as creating random handles even though there
// is no safepoint to protect against, and fiddling around with exceptions.
class StackWatermarkProcessingMark {
  ResetNoHandleMark _rnhm;
  HandleMark _hm;
  PreserveExceptionMark _pem;
  ResourceMark _rm;

public:
  StackWatermarkProcessingMark(Thread* thread) :
      _rnhm(),
      _hm(thread),
      _pem(thread),
      _rm(thread) { }
};

void StackWatermarkFramesIterator::process_one(void* context) {
  StackWatermarkProcessingMark swpm(Thread::current());
  while (has_next()) {
    frame f = current();
    uintptr_t sp = reinterpret_cast<uintptr_t>(f.sp());
    bool frame_has_barrier = StackWatermark::has_barrier(f);
    _owner.process(f, register_map(), context);
    next();
    if (frame_has_barrier) {
      set_watermark(sp);
      break;
    }
  }
}

void StackWatermarkFramesIterator::process_all(void* context) {
  const uintptr_t frames_per_poll_gc = 5;

  ResourceMark rm;
  log_info(stackbarrier)("Processing whole stack for tid %d",
                         _jt->osthread()->thread_id());
  uint i = 0;
  while (has_next()) {
    frame f = current();
    uintptr_t sp = reinterpret_cast<uintptr_t>(f.sp());
    assert(sp >= _caller, "invariant");
    bool frame_has_barrier = StackWatermark::has_barrier(f);
    _owner.process(f, register_map(), context);
    next();
    if (frame_has_barrier) {
      set_watermark(sp);
      if (++i == frames_per_poll_gc) {
        // Yield every N frames so mutator can progress faster.
        i = 0;
        _owner.yield_processing();
      }
    }
  }
}

StackWatermarkFramesIterator::StackWatermarkFramesIterator(StackWatermark& owner) :
    _jt(owner._jt),
    _caller(0),
    _callee(0),
    _frame_stream(owner._jt, true /* update_registers */, false /* process_frames */),
    _owner(owner),
    _is_done(_frame_stream.is_done()) {
}

frame& StackWatermarkFramesIterator::current() {
  return *_frame_stream.current();
}

RegisterMap& StackWatermarkFramesIterator::register_map() {
  return *_frame_stream.register_map();
}

bool StackWatermarkFramesIterator::has_next() const {
  return !_is_done;
}

void StackWatermarkFramesIterator::next() {
  _frame_stream.next();
  _is_done = _frame_stream.is_done();
}

StackWatermark::StackWatermark(JavaThread* jt, StackWatermarkKind kind, uint32_t epoch) :
    _state(StackWatermarkState::create(epoch, true /* is_done */)),
    _watermark(0),
    _next(NULL),
    _jt(jt),
    _iterator(NULL),
    _lock(Mutex::stackwatermark, "StackWatermark_lock"),
    _kind(kind),
    _linked_watermarks() {
}

StackWatermark::~StackWatermark() {
  delete _iterator;
}

#ifdef ASSERT
void StackWatermark::assert_is_frame_safe(const frame& f) {
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  assert(is_frame_safe(f), "Frame must be safe");
}
#endif

// A frame is "safe" if it *and* its caller have been processed. This is the invariant
// that allows exposing a frame, and for that frame to directly access its caller frame
// without going through any hooks.
bool StackWatermark::is_frame_safe(const frame& f) {
  assert(_lock.owned_by_self(), "Must be locked");
  uint32_t state = Atomic::load(&_state);
  if (!processing_started(state)) {
    return false;
  }
  if (processing_completed(state)) {
    return true;
  }
  return reinterpret_cast<uintptr_t>(f.sp()) < _iterator->caller();
}

void StackWatermark::start_processing_impl(void* context) {
  log_info(stackbarrier)("Starting stack processing for tid %d",
                         _jt->osthread()->thread_id());
  delete _iterator;
  if (_jt->has_last_Java_frame()) {
    _iterator = new StackWatermarkFramesIterator(*this);
    // Always process three frames when starting an iteration.
    //
    // The three frames corresponds to:
    // 1) The callee frame
    // 2) The caller frame
    // This allows a callee to always be able to read state from its caller
    // without needing any special barriers.
    //
    // 3) An extra frame to deal with unwinding safepointing on the way out.
    // Sometimes, we also call into the runtime to on_unwind(), but then
    // hit a safepoint poll on the way out from the runtime.
    _iterator->process_one(context);
    _iterator->process_one(context);
    _iterator->process_one(context);
  } else {
    _iterator = NULL;
  }
  update_watermark();
}

void StackWatermark::yield_processing() {
  update_watermark();
  MutexUnlocker mul(&_lock, Mutex::_no_safepoint_check_flag);
}

void StackWatermark::update_watermark() {
  assert(_lock.owned_by_self(), "invariant");
  if (_iterator != NULL && _iterator->has_next()) {
    assert(_iterator->callee() != 0, "sanity");
    Atomic::release_store(&_watermark, _iterator->callee());
    Atomic::release_store(&_state, StackWatermarkState::create(epoch_id(), false /* is_done */)); // release watermark w.r.t. epoch
  } else {
    Atomic::release_store(&_watermark, uintptr_t(0)); // Release stack data modifications w.r.t. watermark
    Atomic::release_store(&_state, StackWatermarkState::create(epoch_id(), true /* is_done */)); // release watermark w.r.t. epoch
    log_info(stackbarrier)("Finished stack processing iteration for tid %d",
                           _jt->osthread()->thread_id());
  }
}

void StackWatermark::process_one() {
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  if (!processing_started()) {
    start_processing_impl(NULL /* context */);
  } else if (!processing_completed()) {
    _iterator->process_one(NULL /* context */);
    update_watermark();
  }
}

void StackWatermark::push_linked_watermark(StackWatermark* watermark) {
  assert(JavaThread::current() == _jt, "This code is not thread safe");
  _linked_watermarks.push(watermark);
}

void StackWatermark::pop_linked_watermark() {
  assert(JavaThread::current() == _jt, "This code is not thread safe");
  assert(_linked_watermarks.length() > 0, "Mismatched push and pop?");
  _linked_watermarks.pop();
}

uintptr_t StackWatermark::watermark() {
  return Atomic::load_acquire(&_watermark);
}

uintptr_t StackWatermark::last_processed() {
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  if (!processing_started()) {
    // Stale state; no last processed
    return 0;
  }
  if (processing_completed()) {
    // Already processed all; no last processed
    return 0;
  }
  return _iterator->caller();
}

bool StackWatermark::processing_started() const {
  return processing_started(Atomic::load(&_state));
}

bool StackWatermark::processing_started_acquire() const {
  return processing_started(Atomic::load_acquire(&_state));
}

bool StackWatermark::processing_completed() const {
  return processing_completed(Atomic::load(&_state));
}

bool StackWatermark::processing_completed_acquire() const {
  return processing_completed(Atomic::load_acquire(&_state));
}

void StackWatermark::process_linked_watermarks() {
  assert(JavaThread::current() == _jt, "This code is not thread safe");

  // Finish processing all linked stack watermarks
  for (StackWatermark* watermark : _linked_watermarks) {
    watermark->finish_processing(NULL /* context */);
  }
}

void StackWatermark::on_safepoint() {
  start_processing();

  // If the thread waking up from a safepoint expected certain other
  // stack watermarks (potentially from different threads) are processed,
  // then we have to perform processing of said linked watermarks here.
  process_linked_watermarks();
}

void StackWatermark::start_processing() {
  if (!processing_started_acquire()) {
    MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
    if (!processing_started()) {
      start_processing_impl(NULL /* context */);
    }
  }
}

void StackWatermark::finish_processing(void* context) {
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  if (!processing_started()) {
    start_processing_impl(context);
  }
  if (!processing_completed()) {
    _iterator->process_all(context);
    update_watermark();
  }
}

95%


¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge