products/sources/formale Sprachen/Java/openjdk-20-36_src/src/hotspot/share/runtime image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: jvmciObject.hpp   Sprache: C

/*
 * Copyright (c) 2017, 2022, 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 "classfile/javaClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "jvm_io.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/globals.hpp"
#include "runtime/handshake.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/osThread.hpp"
#include "runtime/stackWatermarkSet.hpp"
#include "runtime/task.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/formatBuffer.hpp"
#include "utilities/filterQueue.inline.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/preserveException.hpp"
#include "utilities/systemMemoryBarrier.hpp"

class HandshakeOperation : public CHeapObj<mtThread> {
  friend class HandshakeState;
 protected:
  HandshakeClosure*   _handshake_cl;
  // Keeps track of emitted and completed handshake operations.
  // Once it reaches zero all handshake operations have been performed.
  int32_t             _pending_threads;
  JavaThread*         _target;
  Thread*             _requester;

  // Must use AsyncHandshakeOperation when using AsyncHandshakeClosure.
  HandshakeOperation(AsyncHandshakeClosure* cl, JavaThread* target, Thread* requester) :
    _handshake_cl(cl),
    _pending_threads(1),
    _target(target),
    _requester(requester) {}

 public:
  HandshakeOperation(HandshakeClosure* cl, JavaThread* target, Thread* requester) :
    _handshake_cl(cl),
    _pending_threads(1),
    _target(target),
    _requester(requester) {}
  virtual ~HandshakeOperation() {}
  void prepare(JavaThread* current_target, Thread* executing_thread);
  void do_handshake(JavaThread* thread);
  bool is_completed() {
    int32_t val = Atomic::load(&_pending_threads);
    assert(val >= 0, "_pending_threads=%d cannot be negative", val);
    return val == 0;
  }
  void add_target_count(int count) { Atomic::add(&_pending_threads, count); }
  int32_t pending_threads()        { return Atomic::load(&_pending_threads); }
  const char* name()               { return _handshake_cl->name(); }
  bool is_async()                  { return _handshake_cl->is_async(); }
  bool is_suspend()                { return _handshake_cl->is_suspend(); }
  bool is_async_exception()        { return _handshake_cl->is_async_exception(); }
};

class AsyncHandshakeOperation : public HandshakeOperation {
 private:
  jlong _start_time_ns;
 public:
  AsyncHandshakeOperation(AsyncHandshakeClosure* cl, JavaThread* target, jlong start_ns)
    : HandshakeOperation(cl, target, NULL), _start_time_ns(start_ns) {}
  virtual ~AsyncHandshakeOperation() { delete _handshake_cl; }
  jlong start_time() const           { return _start_time_ns; }
};

// Performing handshakes requires a custom yielding strategy because without it
// there is a clear performance regression vs plain spinning. We keep track of
// when we last saw progress by looking at why each targeted thread has not yet
// completed its handshake. After spinning for a while with no progress we will
// yield, but as long as there is progress, we keep spinning. Thus we avoid
// yielding when there is potential work to be done or the handshake is close
// to being finished.
class HandshakeSpinYield : public StackObj {
 private:
  jlong _start_time_ns;
  jlong _last_spin_start_ns;
  jlong _spin_time_ns;

  int _result_count[2][HandshakeState::_number_states];
  int _prev_result_pos;

  int current_result_pos() { return (_prev_result_pos + 1) & 0x1; }

  void wait_raw(jlong now) {
    // We start with fine-grained nanosleeping until a millisecond has
    // passed, at which point we resort to plain naked_short_sleep.
    if (now - _start_time_ns < NANOSECS_PER_MILLISEC) {
      os::naked_short_nanosleep(10 * (NANOUNITS / MICROUNITS));
    } else {
      os::naked_short_sleep(1);
    }
  }

  void wait_blocked(JavaThread* self, jlong now) {
    ThreadBlockInVM tbivm(self);
    wait_raw(now);
  }

  bool state_changed() {
    for (int i = 0; i < HandshakeState::_number_states; i++) {
      if (_result_count[0][i] != _result_count[1][i]) {
        return true;
      }
    }
    return false;
  }

  void reset_state() {
    _prev_result_pos++;
    for (int i = 0; i < HandshakeState::_number_states; i++) {
      _result_count[current_result_pos()][i] = 0;
    }
  }

 public:
  HandshakeSpinYield(jlong start_time) :
    _start_time_ns(start_time), _last_spin_start_ns(start_time),
    _spin_time_ns(0), _result_count(), _prev_result_pos(0) {

    const jlong max_spin_time_ns = 100 /* us */ * (NANOUNITS / MICROUNITS);
    int free_cpus = os::active_processor_count() - 1;
    _spin_time_ns = (5 /* us */ * (NANOUNITS / MICROUNITS)) * free_cpus; // zero on UP
    _spin_time_ns = _spin_time_ns > max_spin_time_ns ? max_spin_time_ns : _spin_time_ns;
  }

  void add_result(HandshakeState::ProcessResult pr) {
    _result_count[current_result_pos()][pr]++;
  }

  void process() {
    jlong now = os::javaTimeNanos();
    if (state_changed()) {
      reset_state();
      // We spin for x amount of time since last state change.
      _last_spin_start_ns = now;
      return;
    }
    jlong wait_target = _last_spin_start_ns + _spin_time_ns;
    if (wait_target < now) {
      // On UP this is always true.
      Thread* self = Thread::current();
      if (self->is_Java_thread()) {
        wait_blocked(JavaThread::cast(self), now);
      } else {
        wait_raw(now);
      }
      _last_spin_start_ns = os::javaTimeNanos();
    }
    reset_state();
  }
};

static void handle_timeout(HandshakeOperation* op, JavaThread* target) {
  JavaThreadIteratorWithHandle jtiwh;

  log_error(handshake)("Handshake timeout: %s(" INTPTR_FORMAT "), pending threads: " INT32_FORMAT,
                       op->name(), p2i(op), op->pending_threads());

  if (target == NULL) {
    for ( ; JavaThread* thr = jtiwh.next(); ) {
      if (thr->handshake_state()->operation_pending(op)) {
        log_error(handshake)("JavaThread " INTPTR_FORMAT " has not cleared handshake op: " INTPTR_FORMAT, p2i(thr), p2i(op));
        // Remember the last one found for more diagnostics below.
        target = thr;
      }
    }
  } else {
    log_error(handshake)("JavaThread " INTPTR_FORMAT " has not cleared handshake op: " INTPTR_FORMAT, p2i(target), p2i(op));
  }

  if (target != NULL) {
    if (os::signal_thread(target, SIGILL, "cannot be handshaked")) {
      // Give target a chance to report the error and terminate the VM.
      os::naked_sleep(3000);
    }
  } else {
    log_error(handshake)("No thread with an unfinished handshake op(" INTPTR_FORMAT ") found.", p2i(op));
  }
  fatal("Handshake timeout");
}

static void check_handshake_timeout(jlong start_time, HandshakeOperation* op, JavaThread* target = NULL) {
  // Check if handshake operation has timed out
  jlong timeout_ns = millis_to_nanos(HandshakeTimeout);
  if (timeout_ns > 0) {
    if (os::javaTimeNanos() >= (start_time + timeout_ns)) {
      handle_timeout(op, target);
    }
  }
}

static void log_handshake_info(jlong start_time_ns, const char* name, int targets, int emitted_handshakes_executed, const char* extra = NULL) {
  if (log_is_enabled(Info, handshake)) {
    jlong completion_time = os::javaTimeNanos() - start_time_ns;
    log_info(handshake)("Handshake \"%s\", Targeted threads: %d, Executed by requesting thread: %d, Total completion time: " JLONG_FORMAT " ns%s%s",
                        name, targets,
                        emitted_handshakes_executed,
                        completion_time,
                        extra != NULL ? ", " : "",
                        extra != NULL ? extra : "");
  }
}

class VM_HandshakeAllThreads: public VM_Operation {
  HandshakeOperation* const _op;
 public:
  VM_HandshakeAllThreads(HandshakeOperation* op) : _op(op) {}

  bool evaluate_at_safepoint() const { return false; }

  void doit() {
    jlong start_time_ns = os::javaTimeNanos();

    JavaThreadIteratorWithHandle jtiwh;
    int number_of_threads_issued = 0;
    for (JavaThread* thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) {
      thr->handshake_state()->add_operation(_op);
      number_of_threads_issued++;
    }
    if (UseSystemMemoryBarrier) {
      SystemMemoryBarrier::emit();
    }

    if (number_of_threads_issued < 1) {
      log_handshake_info(start_time_ns, _op->name(), 0, 0, "no threads alive");
      return;
    }
    // _op was created with a count == 1 so don't double count.
    _op->add_target_count(number_of_threads_issued - 1);

    log_trace(handshake)("Threads signaled, begin processing blocked threads by VMThread");
    HandshakeSpinYield hsy(start_time_ns);
    // Keeps count on how many of own emitted handshakes
    // this thread execute.
    int emitted_handshakes_executed = 0;
    do {
      // Check if handshake operation has timed out
      check_handshake_timeout(start_time_ns, _op);

      // Have VM thread perform the handshake operation for blocked threads.
      // Observing a blocked state may of course be transient but the processing is guarded
      // by mutexes and we optimistically begin by working on the blocked threads
      jtiwh.rewind();
      for (JavaThread* thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) {
        // A new thread on the ThreadsList will not have an operation,
        // hence it is skipped in handshake_try_process.
        HandshakeState::ProcessResult pr = thr->handshake_state()->try_process(_op);
        hsy.add_result(pr);
        if (pr == HandshakeState::_succeeded) {
          emitted_handshakes_executed++;
        }
      }
      hsy.process();
    } while (!_op->is_completed());

    // This pairs up with the release store in do_handshake(). It prevents future
    // loads from floating above the load of _pending_threads in is_completed()
    // and thus prevents reading stale data modified in the handshake closure
    // by the Handshakee.
    OrderAccess::acquire();

    log_handshake_info(start_time_ns, _op->name(), number_of_threads_issued, emitted_handshakes_executed);
  }

  VMOp_Type type() const { return VMOp_HandshakeAllThreads; }
};

void HandshakeOperation::prepare(JavaThread* current_target, Thread* executing_thread) {
  if (current_target->is_terminated()) {
    // Will never execute any handshakes on this thread.
    return;
  }
  if (current_target != executing_thread) {
    // Only when the target is not executing the handshake itself.
    StackWatermarkSet::start_processing(current_target, StackWatermarkKind::gc);
  }
  if (_requester != NULL && _requester != executing_thread && _requester->is_Java_thread()) {
    // The handshake closure may contain oop Handles from the _requester.
    // We must make sure we can use them.
    StackWatermarkSet::start_processing(JavaThread::cast(_requester), StackWatermarkKind::gc);
  }
}

void HandshakeOperation::do_handshake(JavaThread* thread) {
  jlong start_time_ns = 0;
  if (log_is_enabled(Debug, handshake, task)) {
    start_time_ns = os::javaTimeNanos();
  }

  // Only actually execute the operation for non terminated threads.
  if (!thread->is_terminated()) {
    _handshake_cl->do_thread(thread);
  }

  if (start_time_ns != 0) {
    jlong completion_time = os::javaTimeNanos() - start_time_ns;
    log_debug(handshake, task)("Operation: %s for thread " PTR_FORMAT ", is_vm_thread: %s, completed in " JLONG_FORMAT " ns",
                               name(), p2i(thread), BOOL_TO_STR(Thread::current()->is_VM_thread()), completion_time);
  }

  // Inform VMThread/Handshaker that we have completed the operation.
  // When this is executed by the Handshakee we need a release store
  // here to make sure memory operations executed in the handshake
  // closure are visible to the VMThread/Handshaker after it reads
  // that the operation has completed.
  Atomic::dec(&_pending_threads);
  // Trailing fence, used to make sure removal of the operation strictly
  // happened after we completed the operation.

  // It is no longer safe to refer to 'this' as the VMThread/Handshaker may have destroyed this operation
}

void Handshake::execute(HandshakeClosure* hs_cl) {
  HandshakeOperation cto(hs_cl, NULL, Thread::current());
  VM_HandshakeAllThreads handshake(&cto);
  VMThread::execute(&handshake);
}

void Handshake::execute(HandshakeClosure* hs_cl, JavaThread* target) {
  // tlh == nullptr means we rely on a ThreadsListHandle somewhere
  // in the caller's context (and we sanity check for that).
  Handshake::execute(hs_cl, nullptr, target);
}

void Handshake::execute(HandshakeClosure* hs_cl, ThreadsListHandle* tlh, JavaThread* target) {
  JavaThread* self = JavaThread::current();
  HandshakeOperation op(hs_cl, target, Thread::current());

  jlong start_time_ns = os::javaTimeNanos();

  guarantee(target != nullptr, "must be");
  if (tlh == nullptr) {
    guarantee(Thread::is_JavaThread_protected_by_TLH(target),
              "missing ThreadsListHandle in calling context.");
    target->handshake_state()->add_operation(&op);
  } else if (tlh->includes(target)) {
    target->handshake_state()->add_operation(&op);
  } else {
    char buf[128];
    jio_snprintf(buf, sizeof(buf),  "(thread= " INTPTR_FORMAT " dead)", p2i(target));
    log_handshake_info(start_time_ns, op.name(), 0, 0, buf);
    return;
  }

  // Separate the arming of the poll in add_operation() above from
  // the read of JavaThread state in the try_process() call below.
  if (UseSystemMemoryBarrier) {
    SystemMemoryBarrier::emit();
  }

  // Keeps count on how many of own emitted handshakes
  // this thread execute.
  int emitted_handshakes_executed = 0;
  HandshakeSpinYield hsy(start_time_ns);
  while (!op.is_completed()) {
    HandshakeState::ProcessResult pr = target->handshake_state()->try_process(&op);
    if (pr == HandshakeState::_succeeded) {
      emitted_handshakes_executed++;
    }
    if (op.is_completed()) {
      break;
    }

    // Check if handshake operation has timed out
    check_handshake_timeout(start_time_ns, &op, target);

    hsy.add_result(pr);
    // Check for pending handshakes to avoid possible deadlocks where our
    // target is trying to handshake us.
    if (SafepointMechanism::should_process(self)) {
      // Will not suspend here.
      ThreadBlockInVM tbivm(self);
    }
    hsy.process();
  }

  // This pairs up with the release store in do_handshake(). It prevents future
  // loads from floating above the load of _pending_threads in is_completed()
  // and thus prevents reading stale data modified in the handshake closure
  // by the Handshakee.
  OrderAccess::acquire();

  log_handshake_info(start_time_ns, op.name(), 1, emitted_handshakes_executed);
}

void Handshake::execute(AsyncHandshakeClosure* hs_cl, JavaThread* target) {
  jlong start_time_ns = os::javaTimeNanos();
  AsyncHandshakeOperation* op = new AsyncHandshakeOperation(hs_cl, target, start_time_ns);

  guarantee(target != nullptr, "must be");

  Thread* current = Thread::current();
  if (current != target) {
    // Another thread is handling the request and it must be protecting
    // the target.
    guarantee(Thread::is_JavaThread_protected_by_TLH(target),
              "missing ThreadsListHandle in calling context.");
  }
  // Implied else:
  // The target is handling the request itself so it can't be dead.

  target->handshake_state()->add_operation(op);
}

// Filters
static bool non_self_executable_filter(HandshakeOperation* op) {
  return !op->is_async();
}
static bool no_async_exception_filter(HandshakeOperation* op) {
  return !op->is_async_exception();
}
static bool async_exception_filter(HandshakeOperation* op) {
  return op->is_async_exception();
}
static bool no_suspend_no_async_exception_filter(HandshakeOperation* op) {
  return !op->is_suspend() && !op->is_async_exception();
}
static bool all_ops_filter(HandshakeOperation* op) {
  return true;
}

HandshakeState::HandshakeState(JavaThread* target) :
  _handshakee(target),
  _queue(),
  _lock(Monitor::nosafepoint, "HandshakeState_lock"),
  _active_handshaker(),
  _async_exceptions_blocked(false),
  _suspended(false),
  _async_suspend_handshake(false) {
}

HandshakeState::~HandshakeState() {
  while (has_operation()) {
    HandshakeOperation* op = _queue.pop(all_ops_filter);
    guarantee(op->is_async(), "Only async operations may still be present on queue");
    delete op;
  }
}

void HandshakeState::add_operation(HandshakeOperation* op) {
  // Adds are done lock free and so is arming.
  _queue.push(op);
  SafepointMechanism::arm_local_poll_release(_handshakee);
}

bool HandshakeState::operation_pending(HandshakeOperation* op) {
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  MatchOp mo(op);
  return _queue.contains(mo);
}

HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend, bool check_async_exception) {
  assert(_handshakee == Thread::current(), "Must be called by self");
  assert(_lock.owned_by_self(), "Lock must be held");
  assert(allow_suspend || !check_async_exception, "invalid case");
  if (!allow_suspend) {
    return _queue.peek(no_suspend_no_async_exception_filter);
  } else if (check_async_exception && !_async_exceptions_blocked) {
    return _queue.peek();
  } else {
    return _queue.peek(no_async_exception_filter);
  }
}

bool HandshakeState::has_operation(bool allow_suspend, bool check_async_exception) {
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  return get_op_for_self(allow_suspend, check_async_exception) != NULL;
}

bool HandshakeState::has_async_exception_operation() {
  if (!has_operation()) return false;
  MutexLocker ml(_lock.owned_by_self() ? NULL :  &_lock, Mutex::_no_safepoint_check_flag);
  return _queue.peek(async_exception_filter) != NULL;
}

void HandshakeState::clean_async_exception_operation() {
  while (has_async_exception_operation()) {
    MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
    HandshakeOperation* op;
    op = _queue.peek(async_exception_filter);
    remove_op(op);
    delete op;
  }
}

bool HandshakeState::have_non_self_executable_operation() {
  assert(_handshakee != Thread::current(), "Must not be called by self");
  assert(_lock.owned_by_self(), "Lock must be held");
  return _queue.contains(non_self_executable_filter);
}

HandshakeOperation* HandshakeState::get_op() {
  assert(_handshakee != Thread::current(), "Must not be called by self");
  assert(_lock.owned_by_self(), "Lock must be held");
  return _queue.peek(non_self_executable_filter);
};

void HandshakeState::remove_op(HandshakeOperation* op) {
  assert(_lock.owned_by_self(), "Lock must be held");
  MatchOp mo(op);
  HandshakeOperation* ret = _queue.pop(mo);
  assert(ret == op, "Popped op must match requested op");
};

bool HandshakeState::process_by_self(bool allow_suspend, bool check_async_exception) {
  assert(Thread::current() == _handshakee, "should call from _handshakee");
  assert(!_handshakee->is_terminated(), "should not be a terminated thread");

  _handshakee->frame_anchor()->make_walkable();
  // Threads shouldn't block if they are in the middle of printing, but...
  ttyLocker::break_tty_lock_for_safepoint(os::current_thread_id());

  while (has_operation()) {
    // Handshakes cannot safely safepoint. The exceptions to this rule are
    // the asynchronous suspension and unsafe access error handshakes.
    MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);

    HandshakeOperation* op = get_op_for_self(allow_suspend, check_async_exception);
    if (op != NULL) {
      assert(op->_target == NULL || op->_target == Thread::current(), "Wrong thread");
      bool async = op->is_async();
      log_trace(handshake)("Proc handshake %s " INTPTR_FORMAT " on " INTPTR_FORMAT " by self",
                           async ? "asynchronous" : "synchronous", p2i(op), p2i(_handshakee));
      op->prepare(_handshakee, _handshakee);
      if (!async) {
        HandleMark hm(_handshakee);
        PreserveExceptionMark pem(_handshakee);
        op->do_handshake(_handshakee); // acquire, op removed after
        remove_op(op);
      } else {
        // An asynchronous handshake may put the JavaThread in blocked state (safepoint safe).
        // The destructor ~PreserveExceptionMark touches the exception oop so it must not be executed,
        // since a safepoint may be in-progress when returning from the async handshake.
        remove_op(op);
        op->do_handshake(_handshakee);
        log_handshake_info(((AsyncHandshakeOperation*)op)->start_time(), op->name(), 1, 0, "asynchronous");
        delete op;
        return true// Must check for safepoints
      }
    } else {
      return false;
    }
  }
  return false;
}

bool HandshakeState::can_process_handshake() {
  // handshake_safe may only be called with polls armed.
  // Handshaker controls this by first claiming the handshake via claim_handshake().
  return SafepointSynchronize::handshake_safe(_handshakee);
}

bool HandshakeState::possibly_can_process_handshake() {
  // Note that this method is allowed to produce false positives.
  if (_handshakee->is_terminated()) {
    return true;
  }
  switch (_handshakee->thread_state()) {
  case _thread_in_native:
    // native threads are safe if they have no java stack or have walkable stack
    return !_handshakee->has_last_Java_frame() || _handshakee->frame_anchor()->walkable();

  case _thread_blocked:
    return true;

  default:
    return false;
  }
}

bool HandshakeState::claim_handshake() {
  if (!_lock.try_lock()) {
    return false;
  }
  // Operations are added lock free and then the poll is armed.
  // If all handshake operations for the handshakee are finished and someone
  // just adds an operation we may see it here. But if the handshakee is not
  // armed yet it is not safe to proceed.
  if (have_non_self_executable_operation()) {
    OrderAccess::loadload(); // Matches the implicit storestore in add_operation()
    if (SafepointMechanism::local_poll_armed(_handshakee)) {
      return true;
    }
  }
  _lock.unlock();
  return false;
}

HandshakeState::ProcessResult HandshakeState::try_process(HandshakeOperation* match_op) {
  if (!has_operation()) {
    // JT has already cleared its handshake
    return HandshakeState::_no_operation;
  }

  if (!possibly_can_process_handshake()) {
    // JT is observed in an unsafe state, it must notice the handshake itself
    return HandshakeState::_not_safe;
  }

  // Claim the mutex if there still an operation to be executed.
  if (!claim_handshake()) {
    return HandshakeState::_claim_failed;
  }

  // If we own the mutex at this point and while owning the mutex we
  // can observe a safe state the thread cannot possibly continue without
  // getting caught by the mutex.
  if (!can_process_handshake()) {
    _lock.unlock();
    return HandshakeState::_not_safe;
  }

  Thread* current_thread = Thread::current();

  HandshakeOperation* op = get_op();

  assert(op != NULL, "Must have an op");
  assert(SafepointMechanism::local_poll_armed(_handshakee), "Must be");
  assert(op->_target == NULL || _handshakee == op->_target, "Wrong thread");

  log_trace(handshake)("Processing handshake " INTPTR_FORMAT " by %s(%s)", p2i(op),
                       op == match_op ? "handshaker" : "cooperative",
                       current_thread->is_VM_thread() ? "VM Thread" : "JavaThread");

  op->prepare(_handshakee, current_thread);

  set_active_handshaker(current_thread);
  op->do_handshake(_handshakee); // acquire, op removed after
  set_active_handshaker(NULL);
  remove_op(op);

  _lock.unlock();

  log_trace(handshake)("%s(" INTPTR_FORMAT ") executed an op for JavaThread: " INTPTR_FORMAT " %s target op: " INTPTR_FORMAT,
                       current_thread->is_VM_thread() ? "VM Thread" : "JavaThread",
                       p2i(current_thread), p2i(_handshakee),
                       op == match_op ? "including" : "excluding", p2i(match_op));

  return op == match_op ? HandshakeState::_succeeded : HandshakeState::_processed;
}

void HandshakeState::do_self_suspend() {
  assert(Thread::current() == _handshakee, "should call from _handshakee");
  assert(_lock.owned_by_self(), "Lock must be held");
  assert(!_handshakee->has_last_Java_frame() || _handshakee->frame_anchor()->walkable()"should have walkable stack");
  assert(_handshakee->thread_state() == _thread_blocked, "Caller should have transitioned to _thread_blocked");

  while (is_suspended()) {
    log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended", p2i(_handshakee));
    _lock.wait_without_safepoint_check();
  }
  log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " resumed", p2i(_handshakee));
}

// This is the closure that prevents a suspended JavaThread from
// escaping the suspend request.
class ThreadSelfSuspensionHandshake : public AsyncHandshakeClosure {
 public:
  ThreadSelfSuspensionHandshake() : AsyncHandshakeClosure("ThreadSelfSuspensionHandshake") {}
  void do_thread(Thread* thr) {
    JavaThread* current = JavaThread::cast(thr);
    assert(current == Thread::current(), "Must be self executed.");
    JavaThreadState jts = current->thread_state();

    current->set_thread_state(_thread_blocked);
    current->handshake_state()->do_self_suspend();
    current->set_thread_state(jts);
    current->handshake_state()->set_async_suspend_handshake(false);
  }
  virtual bool is_suspend() { return true; }
};

bool HandshakeState::suspend_with_handshake() {
  assert(_handshakee->threadObj() != NULL, "cannot suspend with a NULL threadObj");
  if (_handshakee->is_exiting()) {
    log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " exiting", p2i(_handshakee));
    return false;
  }
  if (has_async_suspend_handshake()) {
    if (is_suspended()) {
      // Target is already suspended.
      log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " already suspended", p2i(_handshakee));
      return false;
    } else {
      // Target is going to wake up and leave suspension.
      // Let's just stop the thread from doing that.
      log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " re-suspended", p2i(_handshakee));
      set_suspended(true);
      return true;
    }
  }
  // no suspend request
  assert(!is_suspended(), "cannot be suspended without a suspend request");
  // Thread is safe, so it must execute the request, thus we can count it as suspended
  // from this point.
  set_suspended(true);
  set_async_suspend_handshake(true);
  log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended, arming ThreadSuspension", p2i(_handshakee));
  ThreadSelfSuspensionHandshake* ts = new ThreadSelfSuspensionHandshake();
  Handshake::execute(ts, _handshakee);
  return true;
}

// This is the closure that synchronously honors the suspend request.
class SuspendThreadHandshake : public HandshakeClosure {
  bool _did_suspend;
public:
  SuspendThreadHandshake() : HandshakeClosure("SuspendThread"), _did_suspend(false) {}
  void do_thread(Thread* thr) {
    JavaThread* target = JavaThread::cast(thr);
    _did_suspend = target->handshake_state()->suspend_with_handshake();
  }
  bool did_suspend() { return _did_suspend; }
};

bool HandshakeState::suspend() {
  JVMTI_ONLY(assert(!_handshakee->is_in_VTMS_transition(), "no suspend allowed in VTMS transition");)
  JavaThread* self = JavaThread::current();
  if (_handshakee == self) {
    // If target is the current thread we can bypass the handshake machinery
    // and just suspend directly
    ThreadBlockInVM tbivm(self);
    MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
    set_suspended(true);
    do_self_suspend();
    return true;
  } else {
    SuspendThreadHandshake st;
    Handshake::execute(&st, _handshakee);
    return st.did_suspend();
  }
}

bool HandshakeState::resume() {
  if (!is_suspended()) {
    return false;
  }
  MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  if (!is_suspended()) {
    assert(!_handshakee->is_suspended(), "cannot be suspended without a suspend request");
    return false;
  }
  // Resume the thread.
  set_suspended(false);
  _lock.notify();
  return true;
}

void HandshakeState::handle_unsafe_access_error() {
  if (is_suspended()) {
    // A suspend handshake was added to the queue after the
    // unsafe access error. Since the suspender has already
    // considered this JT as suspended and assumes it won't go
    // back to Java until resumed we cannot create the exception
    // object yet. Add a new unsafe access error operation to
    // the end of the queue and try again in the next attempt.
    Handshake::execute(new UnsafeAccessErrorHandshake(), _handshakee);
    log_info(handshake)("JavaThread " INTPTR_FORMAT " skipping unsafe access processing due to suspend.", p2i(_handshakee));
    return;
  }
  // Release the handshake lock before constructing the oop to
  // avoid deadlocks since that can block. This will allow the
  // JavaThread to execute normally as if it was outside a handshake.
  // We will reacquire the handshake lock at return from ~MutexUnlocker.
  MutexUnlocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  // We may be at method entry which requires we save the do-not-unlock flag.
  UnlockFlagSaver fs(_handshakee);
  Handle h_exception = Exceptions::new_exception(_handshakee, vmSymbols::java_lang_InternalError(), "a fault occurred in an unsafe memory access operation");
  if (h_exception()->is_a(vmClasses::InternalError_klass())) {
    java_lang_InternalError::set_during_unsafe_access(h_exception());
  }
  _handshakee->handle_async_exception(h_exception());
}

¤ Dauer der Verarbeitung: 0.54 Sekunden  (vorverarbeitet)  ¤





Druckansicht
unsichere Verbindung
Druckansicht
sprechenden Kalenders

in der Quellcodebibliothek suchen




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.


Bot Zugriff