< prev index next >

src/hotspot/share/runtime/handshake.cpp

Print this page
@@ -311,11 +311,11 @@
      start_time_ns = os::javaTimeNanos();
    }
  
    // Only actually execute the operation for non terminated threads.
    if (!thread->is_terminated()) {
-     NoSafepointVerifier nsv;
+     //NoSafepointVerifier nsv;
      _handshake_cl->do_thread(thread);
    }
  
    if (start_time_ns != 0) {
      jlong completion_time = os::javaTimeNanos() - start_time_ns;

@@ -408,10 +408,11 @@
  HandshakeState::HandshakeState(JavaThread* target) :
    _handshakee(target),
    _queue(),
    _lock(Monitor::nosafepoint, "HandshakeState_lock"),
    _active_handshaker(),
+   _caller(nullptr),
    _suspended(false),
    _async_suspend_handshake(false)
  {
  }
  

@@ -439,12 +440,15 @@
    } else {
      return _queue.peek(no_suspend_filter);
    }
  }
  
- static bool non_self_queue_filter(HandshakeOperation* op) {
-   return !op->is_async();
+ bool HandshakeState::non_self_queue_filter(HandshakeOperation* op) {
+   if (op->_handshake_cl->can_be_processed_by(Thread::current())) {
+     return !op->is_async();
+   }
+   return false;
  }
  
  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");

@@ -477,11 +481,11 @@
  
    ThreadInVMForHandshake tivm(_handshakee);
    // Handshakes cannot safely safepoint.
    // The exception to this rule is the asynchronous suspension handshake.
    // It by-passes the NSV by manually doing the transition.
-   NoSafepointVerifier nsv;
+   //NoSafepointVerifier nsv;
  
    while (has_operation()) {
      MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
  
      HandshakeOperation* op = get_op_for_self(allow_suspend);

@@ -612,11 +616,12 @@
    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()) {
+   while (is_suspended_or_blocked()) {
+     JVMTI_ONLY(assert(!_handshakee->is_in_VTMT(), "no suspend allowed in VTMT transition");)
      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));
  }

@@ -637,65 +642,84 @@
      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");
+ bool HandshakeState::suspend_with_handshake(JavaThread* caller) {
+   // This tested for _handshakee->threadObj() != NULL as well, but the test doesn't work
+   // for that.  TODO: can you suspend a thread during initialization ?
    if (_handshakee->is_exiting()) {
      log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " exiting", p2i(_handshakee));
      return false;
    }
+   bool should_block = caller != nullptr;
+   bool should_suspend = caller == nullptr;
+ 
    if (has_async_suspend_handshake()) {
-     if (is_suspended()) {
-       // Target is already suspended.
-       log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " already suspended", p2i(_handshakee));
+     if ((is_suspended() && should_suspend) || (is_blocked() && should_block)) {
+       log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " already suspended or blocked", p2i(_handshakee));
        return false;
-     } else {
+     } else if (should_suspend) {
        // 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;
+     } else {
+       assert(should_block, "should block");
+       // Target is going to wake up and leave blocking.
+       // Let's just stop the thread from doing that.
+       log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " re-blocked", p2i(_handshakee));
+       set_caller_thread(caller);
+       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);
+   // or blocked from this point.
+   if (should_suspend) {
+     // no suspend request
+     assert(!is_suspended(), "cannot be suspended without a request");
+     set_suspended(true);
+   } else {
+     assert(!is_blocked(), "cannot be blocked without a request");
+     set_caller_thread(caller);
+   }
+ 
    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;
+   JavaThread* _caller;
+   bool        _did_suspend;
  public:
-   SuspendThreadHandshake() : HandshakeClosure("SuspendThread"), _did_suspend(false) {}
+   SuspendThreadHandshake(JavaThread* caller) : HandshakeClosure("SuspendThread"), _caller(caller), _did_suspend(false) {}
    void do_thread(Thread* thr) {
      JavaThread* target = JavaThread::cast(thr);
-     _did_suspend = target->handshake_state()->suspend_with_handshake();
+     _did_suspend = target->handshake_state()->suspend_with_handshake(_caller);
    }
    bool did_suspend() { return _did_suspend; }
  };
  
  bool HandshakeState::suspend() {
+   JVMTI_ONLY(assert(!_handshakee->is_in_VTMT(), "no suspend allowed in VTMT 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;
+     SuspendThreadHandshake st(nullptr);
      Handshake::execute(&st, _handshakee);
      return st.did_suspend();
    }
  }
  

@@ -711,5 +735,35 @@
    // Resume the thread.
    set_suspended(false);
    _lock.notify();
    return true;
  }
+ 
+ // One thread blocks execution of another thread until it resumes it.  This is similar to
+ // suspend, and much of the code is shared but it's a separate state from being suspended.
+ // The commonality is that the thread is self-suspended and that thread waits for both
+ // conditions to clear.
+ bool HandshakeState::block_suspend(JavaThread* caller) {
+   assert(caller == JavaThread::current(), "caller must be current thread");
+ 
+   SuspendThreadHandshake st(caller);
+   Handshake::execute(&st, _handshakee);
+   bool suspended = st.did_suspend();
+   return suspended;
+ }
+ 
+ bool HandshakeState::continue_resume(JavaThread* caller) {
+   assert(caller == JavaThread::current(), "caller must be current thread");
+ 
+   // If caller is non-null only resume blocked thread if it's the caller
+   if (!is_blocked() || caller_thread() != caller) {
+     return false;
+   }
+   MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
+   assert(is_blocked() && caller_thread() == caller,
+          "this is the only thread that can continue this thread");
+ 
+   // Resume the thread.
+   set_caller_thread(nullptr); // !is_blocked()
+   _lock.notify();
+   return true;
+ }
< prev index next >