Skip to content

Commit

Permalink
8286830: ~HandshakeState should not touch oops
Browse files Browse the repository at this point in the history
Reviewed-by: dholmes, rehn
  • Loading branch information
pchilano committed Jun 2, 2022
1 parent bddef71 commit 5acac22
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 11 deletions.
10 changes: 10 additions & 0 deletions src/hotspot/share/runtime/handshake.cpp
Expand Up @@ -502,6 +502,16 @@ bool HandshakeState::has_async_exception_operation(bool ThreadDeath_only) {
}
}

void HandshakeState::clean_async_exception_operation() {
while (has_async_exception_operation(/* ThreadDeath_only */ false)) {
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");
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/runtime/handshake.hpp
Expand Up @@ -133,6 +133,7 @@ class HandshakeState {
bool has_operation() { return !_queue.is_empty(); }
bool has_operation(bool allow_suspend, bool check_async_exception);
bool has_async_exception_operation(bool ThreadDeath_only);
void clean_async_exception_operation();

bool operation_pending(HandshakeOperation* op);

Expand Down
30 changes: 19 additions & 11 deletions src/hotspot/share/runtime/thread.cpp
Expand Up @@ -1365,6 +1365,7 @@ static bool is_daemon(oop threadObj) {
// cleanup_failed_attach_current_thread as well.
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
assert(this == JavaThread::current(), "thread consistency check");
assert(!is_exiting(), "should not be exiting or terminated already");

elapsedTimer _timer_exit_phase1;
elapsedTimer _timer_exit_phase2;
Expand Down Expand Up @@ -1426,18 +1427,23 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
if (JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_end(this);
}

// The careful dance between thread suspension and exit is handled here.
// Since we are in thread_in_vm state and suspension is done with handshakes,
// we can just put in the exiting state and it will be correctly handled.
set_terminated(_thread_exiting);

ThreadService::current_thread_exiting(this, is_daemon(threadObj()));
} else {
assert(!is_terminated() && !is_exiting(), "must not be exiting");
// before_exit() has already posted JVMTI THREAD_END events
}

// Cleanup any pending async exception now since we cannot access oops after
// BarrierSet::barrier_set()->on_thread_detach() has been executed.
if (has_async_exception_condition()) {
handshake_state()->clean_async_exception_operation();
}

// The careful dance between thread suspension and exit is handled here.
// Since we are in thread_in_vm state and suspension is done with handshakes,
// we can just put in the exiting state and it will be correctly handled.
// Also, no more async exceptions will be added to the queue after this point.
set_terminated(_thread_exiting);
ThreadService::current_thread_exiting(this, is_daemon(threadObj()));

if (log_is_enabled(Debug, os, thread, timer)) {
_timer_exit_phase1.stop();
_timer_exit_phase2.start();
Expand Down Expand Up @@ -1529,7 +1535,8 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
}
#endif // INCLUDE_JVMCI

// Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread
// Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread.
// We call BarrierSet::barrier_set()->on_thread_detach() here so no touching of oops after this point.
Threads::remove(this, daemon);

if (log_is_enabled(Debug, os, thread, timer)) {
Expand Down Expand Up @@ -1699,8 +1706,9 @@ void JavaThread::handle_async_exception(oop java_throwable) {
}

void JavaThread::install_async_exception(AsyncExceptionHandshake* aeh) {
// Do not throw asynchronous exceptions against the compiler thread.
if (!can_call_java()) {
// Do not throw asynchronous exceptions against the compiler thread
// or if the thread is already exiting.
if (!can_call_java() || is_exiting()) {
delete aeh;
return;
}
Expand Down
23 changes: 23 additions & 0 deletions test/hotspot/jtreg/runtime/Thread/StopAtExit.java
Expand Up @@ -72,7 +72,30 @@ public static void main(String[] args) {
usage();
}
}
test(timeMax);

// Fire-up deamon that just creates new threads. This generates contention on
// Threads_lock while worker tries to exit, creating more places where target
// can be seen as handshake safe.
Thread threadCreator = new Thread() {
@Override
public void run() {
while (true) {
Thread dummyThread = new Thread(() -> {});
dummyThread.start();
try {
dummyThread.join();
} catch(InterruptedException ie) {
}
}
}
};
threadCreator.setDaemon(true);
threadCreator.start();
test(timeMax);
}

public static void test(int timeMax) {
System.out.println("About to execute for " + timeMax + " seconds.");

long count = 0;
Expand Down
23 changes: 23 additions & 0 deletions test/hotspot/jtreg/runtime/Thread/SuspendAtExit.java
Expand Up @@ -78,7 +78,30 @@ public static void main(String[] args) {
usage();
}
}
test(timeMax);

// Fire-up deamon that just creates new threads. This generates contention on
// Threads_lock while worker tries to exit, creating more places where target
// can be seen as handshake safe.
Thread threadCreator = new Thread() {
@Override
public void run() {
while (true) {
Thread dummyThread = new Thread(() -> {});
dummyThread.start();
try {
dummyThread.join();
} catch(InterruptedException ie) {
}
}
}
};
threadCreator.setDaemon(true);
threadCreator.start();
test(timeMax);
}

public static void test(int timeMax) {
System.out.println("About to execute for " + timeMax + " seconds.");

long count = 0;
Expand Down

1 comment on commit 5acac22

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.