Skip to content

8265754: Move suspend/resume API from HandshakeState #25407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b4846e8
8265754: Refactoring suspend/resume in the HandshakeState away
toxaart May 22, 2025
79c0d32
Merge remote-tracking branch 'origin/master' into JDK-8265754
toxaart May 23, 2025
c3b4a60
8265754: More work.
toxaart May 23, 2025
0f684ca
8265754: Fixed whitespaces errors.
toxaart May 23, 2025
dbf8728
8265754: Fixed indentation and lost newline.
toxaart May 23, 2025
c44616a
8265754: Fixed indentation
toxaart May 23, 2025
4bca21b
8265754: Fixed indentation.
toxaart May 23, 2025
fcdf8f2
8265754: Refactoring to static methods.
toxaart May 23, 2025
b852ba9
Merge remote-tracking branch 'origin/master' into JDK-8265754
toxaart May 26, 2025
0ee1abf
Merge remote-tracking branch 'origin/master' into JDK-8265754
toxaart May 26, 2025
3b0fffa
Merge remote-tracking branch 'origin/master' into JDK-8265754
toxaart Jun 2, 2025
d19b204
8265754: Refactoring
toxaart Jun 2, 2025
e621551
8265754: Refactoring.
toxaart Jun 3, 2025
5b3eac7
8265754: Refactoring.
toxaart Jun 3, 2025
715f996
8265754: Refactoring.
toxaart Jun 3, 2025
4545fb7
8265754: Refactoring.
toxaart Jun 3, 2025
2f6a26d
8265754: Refactoring.
toxaart Jun 3, 2025
425ec18
8265754: Refactoring.
toxaart Jun 3, 2025
46cf909
8265754: Refactoring.
toxaart Jun 4, 2025
93b87cf
8265754: Refactoring into separate file.
toxaart Jun 4, 2025
bb81d13
8265754: Fixing spaces.
toxaart Jun 4, 2025
4c984b2
8265754: Fixed typo.
toxaart Jun 4, 2025
4205a53
8265754: Fixed build problem
toxaart Jun 4, 2025
9a3005a
Merge remote-tracking branch 'origin/master' into JDK-8265754
toxaart Jun 5, 2025
c07b29e
8265754: Added a comment.
toxaart Jun 5, 2025
272b029
8265754: Changed handshakee to target.
toxaart Jun 5, 2025
8d24cd7
Merge remote-tracking branch 'origin/master' into JDK-8265754
toxaart Jun 10, 2025
1d34f5a
8265754: Addressed reviewers comments.
toxaart Jun 10, 2025
00a9faa
8265754: Fixed date in copyright comment.
toxaart Jun 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 2 additions & 124 deletions src/hotspot/share/runtime/handshake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,7 @@ HandshakeState::HandshakeState(JavaThread* target) :
_queue(),
_lock(Monitor::nosafepoint, "HandshakeState_lock"),
_active_handshaker(),
_async_exceptions_blocked(false),
_suspended(false),
_async_suspend_handshake(false) {
_async_exceptions_blocked(false) {
}

HandshakeState::~HandshakeState() {
Expand Down Expand Up @@ -699,128 +697,8 @@ HandshakeState::ProcessResult HandshakeState::try_process(HandshakeOperation* ma
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(bool register_vthread_SR) {
assert(_handshakee->threadObj() != nullptr, "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, register_vthread_SR);
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, register_vthread_SR);
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 _register_vthread_SR;
bool _did_suspend;
public:
SuspendThreadHandshake(bool register_vthread_SR) : HandshakeClosure("SuspendThread"),
_register_vthread_SR(register_vthread_SR), _did_suspend(false) {}
void do_thread(Thread* thr) {
JavaThread* target = JavaThread::cast(thr);
_did_suspend = target->handshake_state()->suspend_with_handshake(_register_vthread_SR);
}
bool did_suspend() { return _did_suspend; }
};

bool HandshakeState::suspend(bool register_vthread_SR) {
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, register_vthread_SR);
do_self_suspend();
return true;
} else {
SuspendThreadHandshake st(register_vthread_SR);
Handshake::execute(&st, _handshakee);
return st.did_suspend();
}
}

bool HandshakeState::resume(bool register_vthread_SR) {
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, register_vthread_SR);
_lock.notify();
return true;
}

void HandshakeState::set_suspended(bool is_suspend, bool register_vthread_SR) {
#if INCLUDE_JVMTI
if (register_vthread_SR) {
assert(_handshakee->is_vthread_mounted(), "sanity check");
if (is_suspend) {
JvmtiVTSuspender::register_vthread_suspend(_handshakee->vthread());
} else {
JvmtiVTSuspender::register_vthread_resume(_handshakee->vthread());
}
}
#endif
Atomic::store(&_suspended, is_suspend);
}

void HandshakeState::handle_unsafe_access_error() {
if (is_suspended()) {
if (_handshakee->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
Expand Down
34 changes: 2 additions & 32 deletions src/hotspot/share/runtime/handshake.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, 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
Expand Down Expand Up @@ -35,8 +35,6 @@
class HandshakeOperation;
class AsyncHandshakeOperation;
class JavaThread;
class SuspendThreadHandshake;
class ThreadSelfSuspensionHandshake;
class UnsafeAccessErrorHandshake;
class ThreadsListHandle;

Expand Down Expand Up @@ -88,8 +86,6 @@ class JvmtiRawMonitor;
// operation is only done by either VMThread/Handshaker on behalf of the
// JavaThread or by the target JavaThread itself.
class HandshakeState {
friend ThreadSelfSuspensionHandshake;
friend SuspendThreadHandshake;
friend UnsafeAccessErrorHandshake;
friend JavaThread;
// This a back reference to the JavaThread,
Expand All @@ -98,7 +94,7 @@ class HandshakeState {
// The queue containing handshake operations to be performed on _handshakee.
FilterQueue<HandshakeOperation*> _queue;
// Provides mutual exclusion to this state and queue. Also used for
// JavaThread suspend/resume operations.
// JavaThread suspend/resume operations performed by SuspendResumeManager.
Monitor _lock;
// Set to the thread executing the handshake operation.
Thread* volatile _active_handshaker;
Expand Down Expand Up @@ -160,31 +156,5 @@ class HandshakeState {
bool async_exceptions_blocked() { return _async_exceptions_blocked; }
void set_async_exceptions_blocked(bool b) { _async_exceptions_blocked = b; }
void handle_unsafe_access_error();

// Suspend/resume support
private:
// This flag is true when the thread owning this
// HandshakeState (the _handshakee) is suspended.
volatile bool _suspended;
// This flag is true while there is async handshake (trap)
// on queue. Since we do only need one, we can reuse it if
// thread gets suspended again (after a resume)
// and we have not yet processed it.
bool _async_suspend_handshake;

// Called from the suspend handshake.
bool suspend_with_handshake(bool register_vthread_SR);
// Called from the async handshake (the trap)
// to stop a thread from continuing execution when suspended.
void do_self_suspend();

bool is_suspended() { return Atomic::load(&_suspended); }
void set_suspended(bool to, bool register_vthread_SR);
bool has_async_suspend_handshake() { return _async_suspend_handshake; }
void set_async_suspend_handshake(bool to) { _async_suspend_handshake = to; }

bool suspend(bool register_vthread_SR);
bool resume(bool register_vthread_SR);
};

#endif // SHARE_RUNTIME_HANDSHAKE_HPP
5 changes: 3 additions & 2 deletions src/hotspot/share/runtime/javaThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ JavaThread::JavaThread(MemTag mem_tag) :
_pending_interrupted_exception(false),

_handshake(this),
_suspend_resume_manager(this, &_handshake._lock),

_popframe_preserved_args(nullptr),
_popframe_preserved_args_size(0),
Expand Down Expand Up @@ -1200,13 +1201,13 @@ bool JavaThread::java_suspend(bool register_vthread_SR) {

guarantee(Thread::is_JavaThread_protected(/* target */ this),
"target JavaThread is not protected in calling context.");
return this->handshake_state()->suspend(register_vthread_SR);
return this->suspend_resume_manager()->suspend(register_vthread_SR);
}

bool JavaThread::java_resume(bool register_vthread_SR) {
guarantee(Thread::is_JavaThread_protected_by_TLH(/* target */ this),
"missing ThreadsListHandle in calling context.");
return this->handshake_state()->resume(register_vthread_SR);
return this->suspend_resume_manager()->resume(register_vthread_SR);
}

// Wait for another thread to perform object reallocation and relocking on behalf of
Expand Down
7 changes: 6 additions & 1 deletion src/hotspot/share/runtime/javaThread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "runtime/safepointMechanism.hpp"
#include "runtime/stackWatermarkSet.hpp"
#include "runtime/stackOverflow.hpp"
#include "runtime/suspendResumeManager.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadHeapSampler.hpp"
#include "runtime/threadIdentifier.hpp"
Expand Down Expand Up @@ -694,9 +695,13 @@ class JavaThread: public Thread {

// Suspend/resume support for JavaThread
// higher-level suspension/resume logic called by the public APIs
private:
SuspendResumeManager _suspend_resume_manager;
public:
bool java_suspend(bool register_vthread_SR);
bool java_resume(bool register_vthread_SR);
bool is_suspended() { return _handshake.is_suspended(); }
bool is_suspended() { return _suspend_resume_manager.is_suspended(); }
SuspendResumeManager* suspend_resume_manager() { return &_suspend_resume_manager; }

// Check for async exception in addition to safepoint.
static void check_special_condition_for_native_trans(JavaThread *thread);
Expand Down
Loading