Skip to content

Commit 5acac22

Browse files
committedJun 2, 2022
8286830: ~HandshakeState should not touch oops
Reviewed-by: dholmes, rehn
1 parent bddef71 commit 5acac22

File tree

5 files changed

+76
-11
lines changed

5 files changed

+76
-11
lines changed
 

‎src/hotspot/share/runtime/handshake.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,16 @@ bool HandshakeState::has_async_exception_operation(bool ThreadDeath_only) {
502502
}
503503
}
504504

505+
void HandshakeState::clean_async_exception_operation() {
506+
while (has_async_exception_operation(/* ThreadDeath_only */ false)) {
507+
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
508+
HandshakeOperation* op;
509+
op = _queue.peek(async_exception_filter);
510+
remove_op(op);
511+
delete op;
512+
}
513+
}
514+
505515
bool HandshakeState::have_non_self_executable_operation() {
506516
assert(_handshakee != Thread::current(), "Must not be called by self");
507517
assert(_lock.owned_by_self(), "Lock must be held");

‎src/hotspot/share/runtime/handshake.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class HandshakeState {
133133
bool has_operation() { return !_queue.is_empty(); }
134134
bool has_operation(bool allow_suspend, bool check_async_exception);
135135
bool has_async_exception_operation(bool ThreadDeath_only);
136+
void clean_async_exception_operation();
136137

137138
bool operation_pending(HandshakeOperation* op);
138139

‎src/hotspot/share/runtime/thread.cpp

+19-11
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ static bool is_daemon(oop threadObj) {
13651365
// cleanup_failed_attach_current_thread as well.
13661366
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
13671367
assert(this == JavaThread::current(), "thread consistency check");
1368+
assert(!is_exiting(), "should not be exiting or terminated already");
13681369

13691370
elapsedTimer _timer_exit_phase1;
13701371
elapsedTimer _timer_exit_phase2;
@@ -1426,18 +1427,23 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
14261427
if (JvmtiExport::should_post_thread_life()) {
14271428
JvmtiExport::post_thread_end(this);
14281429
}
1429-
1430-
// The careful dance between thread suspension and exit is handled here.
1431-
// Since we are in thread_in_vm state and suspension is done with handshakes,
1432-
// we can just put in the exiting state and it will be correctly handled.
1433-
set_terminated(_thread_exiting);
1434-
1435-
ThreadService::current_thread_exiting(this, is_daemon(threadObj()));
14361430
} else {
1437-
assert(!is_terminated() && !is_exiting(), "must not be exiting");
14381431
// before_exit() has already posted JVMTI THREAD_END events
14391432
}
14401433

1434+
// Cleanup any pending async exception now since we cannot access oops after
1435+
// BarrierSet::barrier_set()->on_thread_detach() has been executed.
1436+
if (has_async_exception_condition()) {
1437+
handshake_state()->clean_async_exception_operation();
1438+
}
1439+
1440+
// The careful dance between thread suspension and exit is handled here.
1441+
// Since we are in thread_in_vm state and suspension is done with handshakes,
1442+
// we can just put in the exiting state and it will be correctly handled.
1443+
// Also, no more async exceptions will be added to the queue after this point.
1444+
set_terminated(_thread_exiting);
1445+
ThreadService::current_thread_exiting(this, is_daemon(threadObj()));
1446+
14411447
if (log_is_enabled(Debug, os, thread, timer)) {
14421448
_timer_exit_phase1.stop();
14431449
_timer_exit_phase2.start();
@@ -1529,7 +1535,8 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
15291535
}
15301536
#endif // INCLUDE_JVMCI
15311537

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

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

17011708
void JavaThread::install_async_exception(AsyncExceptionHandshake* aeh) {
1702-
// Do not throw asynchronous exceptions against the compiler thread.
1703-
if (!can_call_java()) {
1709+
// Do not throw asynchronous exceptions against the compiler thread
1710+
// or if the thread is already exiting.
1711+
if (!can_call_java() || is_exiting()) {
17041712
delete aeh;
17051713
return;
17061714
}

‎test/hotspot/jtreg/runtime/Thread/StopAtExit.java

+23
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,30 @@ public static void main(String[] args) {
7272
usage();
7373
}
7474
}
75+
test(timeMax);
76+
77+
// Fire-up deamon that just creates new threads. This generates contention on
78+
// Threads_lock while worker tries to exit, creating more places where target
79+
// can be seen as handshake safe.
80+
Thread threadCreator = new Thread() {
81+
@Override
82+
public void run() {
83+
while (true) {
84+
Thread dummyThread = new Thread(() -> {});
85+
dummyThread.start();
86+
try {
87+
dummyThread.join();
88+
} catch(InterruptedException ie) {
89+
}
90+
}
91+
}
92+
};
93+
threadCreator.setDaemon(true);
94+
threadCreator.start();
95+
test(timeMax);
96+
}
7597

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

78101
long count = 0;

‎test/hotspot/jtreg/runtime/Thread/SuspendAtExit.java

+23
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,30 @@ public static void main(String[] args) {
7878
usage();
7979
}
8080
}
81+
test(timeMax);
82+
83+
// Fire-up deamon that just creates new threads. This generates contention on
84+
// Threads_lock while worker tries to exit, creating more places where target
85+
// can be seen as handshake safe.
86+
Thread threadCreator = new Thread() {
87+
@Override
88+
public void run() {
89+
while (true) {
90+
Thread dummyThread = new Thread(() -> {});
91+
dummyThread.start();
92+
try {
93+
dummyThread.join();
94+
} catch(InterruptedException ie) {
95+
}
96+
}
97+
}
98+
};
99+
threadCreator.setDaemon(true);
100+
threadCreator.start();
101+
test(timeMax);
102+
}
81103

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

84107
long count = 0;

0 commit comments

Comments
 (0)
Please sign in to comment.