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

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
154 changes: 77 additions & 77 deletions src/hotspot/share/runtime/handshake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,19 +699,6 @@ 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 {
Expand All @@ -723,44 +710,13 @@ class ThreadSelfSuspensionHandshake : public AsyncHandshakeClosure {
JavaThreadState jts = current->thread_state();

current->set_thread_state(_thread_blocked);
current->handshake_state()->do_self_suspend();
HandshakeSuspender::do_self_suspend(current->handshake_state());
current->set_thread_state(jts);
current->handshake_state()->set_async_suspend_handshake(false);
HandshakeSuspender::set_async_suspend_handshake(current->handshake_state(), 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;
Expand All @@ -770,41 +726,11 @@ class SuspendThreadHandshake : public HandshakeClosure {
_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);
_did_suspend = HandshakeSuspender::suspend_with_handshake(target->handshake_state(), _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) {
Expand Down Expand Up @@ -844,3 +770,77 @@ void HandshakeState::handle_unsafe_access_error() {
}
_handshakee->handle_async_exception(h_exception());
}

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

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

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

while (is_suspended(state)) {
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended", p2i(get_handshakee(state)));
get_lock_ptr(state)->wait_without_safepoint_check();
}
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " resumed", p2i(get_handshakee(state)));
}

bool HandshakeSuspender::suspend_with_handshake(HandshakeState* state, bool register_vthread_SR) {
assert(get_handshakee(state)->threadObj() != nullptr, "cannot suspend with a null threadObj");
if (get_handshakee(state)->is_exiting()) {
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " exiting", p2i(get_handshakee(state)));
return false;
}
if (has_async_suspend_handshake(state)) {
if (is_suspended(state)) {
// Target is already suspended.
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " already suspended", p2i(get_handshakee(state)));
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(get_handshakee(state)));
set_suspended(state, true, register_vthread_SR);
return true;
}
}
// no suspend request
assert(!is_suspended(state), "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(state, true, register_vthread_SR);
set_async_suspend_handshake(state, true);
log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended, arming ThreadSuspension", p2i(get_handshakee(state)));
ThreadSelfSuspensionHandshake* ts = new ThreadSelfSuspensionHandshake();
Handshake::execute(ts, get_handshakee(state));
return true;
}
53 changes: 45 additions & 8 deletions src/hotspot/share/runtime/handshake.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class SuspendThreadHandshake;
class ThreadSelfSuspensionHandshake;
class UnsafeAccessErrorHandshake;
class ThreadsListHandle;
class HandshakeSuspender;

// A handshake closure is a callback that is executed for a JavaThread
// while it is in a safepoint/handshake-safe state. Depending on the
Expand Down Expand Up @@ -92,6 +93,7 @@ class HandshakeState {
friend SuspendThreadHandshake;
friend UnsafeAccessErrorHandshake;
friend JavaThread;
friend HandshakeSuspender;
// This a back reference to the JavaThread,
// the target for all operation in the queue.
JavaThread* _handshakee;
Expand Down Expand Up @@ -172,19 +174,54 @@ class HandshakeState {
// 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; }
};

class HandshakeSuspender {
friend SuspendThreadHandshake;
friend ThreadSelfSuspensionHandshake;
friend JavaThread;

private:

static bool suspend(HandshakeState* state, bool register_vthread_SR);
static bool resume(HandshakeState* state, bool register_vthread_SR);

// Called from the async handshake (the trap)
// to stop a thread from continuing execution when suspended.
static void do_self_suspend(HandshakeState* state);

// Called from the suspend handshake.
static bool suspend_with_handshake(HandshakeState* state, bool register_vthread_SR);

static JavaThread* get_handshakee(HandshakeState* state) {
return state->_handshakee;
}

static void set_suspended(HandshakeState* state, bool to, bool register_vthread_SR) {
state->set_suspended(to, register_vthread_SR);
}

static bool is_suspended(HandshakeState* state) {
return state->is_suspended();
}

static Monitor* get_lock_ptr(HandshakeState* state) {
return &state->_lock;
}

static bool has_async_suspend_handshake(HandshakeState* state) {
return state->has_async_suspend_handshake();
}

static void set_async_suspend_handshake(HandshakeState* state, bool to) {
state->set_async_suspend_handshake(to);
}

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

#endif // SHARE_RUNTIME_HANDSHAKE_HPP
4 changes: 2 additions & 2 deletions src/hotspot/share/runtime/javaThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1201,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 HandshakeSuspender::suspend(this->handshake_state(), 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 HandshakeSuspender::resume(this->handshake_state(), register_vthread_SR);
}

// Wait for another thread to perform object reallocation and relocking on behalf of
Expand Down