Skip to content

Commit

Permalink
[Wisp] Fix dead loop when killing threads waiting for objectmonitor.
Browse files Browse the repository at this point in the history
Summary: Threads waiting for objectmonitor will skip calling
WispTask::park when async exception is pending, so mannualy
clear exception before WispThread::park

Test Plan: jtreg test/jdk/com/alibaba/rcm/TestDeadLoopKillObjectMonitor.java

Reviewed-by: yulei

Issue:
dragonwell-project#146
  • Loading branch information
ZhaiMo15 committed Aug 30, 2023
1 parent d986772 commit a6a2ff1
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/hotspot/share/runtime/coroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,15 @@ void WispThread::park(long millis, const ObjectWaiter* ow) {
JavaThread* jt = ((WispThread*) ow->_thread)->thread();
assert(jt == Thread::current(), "current");

assert (!jt->has_pending_exception(), "should not have any pending exception");
if (jt->has_async_exception_condition()) {
assert(UseWisp2 && Wisp2ThreadStop, "pre-condition");
assert(jt->has_aync_thread_death_exception(), "must be wisp_thread_death_exception");
// JavaCalls will be skipped if current thread has a pending exception
// mannually clear all async exceptions before calling into java
jt->clear_aync_thread_death_exception();
}

if (ow->_timeout > 0) {
millis = ow->_timeout;
assert(!ow->_using_wisp_park, "invariant");
Expand Down Expand Up @@ -821,6 +830,14 @@ void WispThread::unpark(int task_id, bool using_wisp_park, bool proxy_unpark, Pa
return;
}

if (jt->has_async_exception_condition()) {
assert(UseWisp2 && Wisp2ThreadStop, "pre-condition");
assert(jt->has_aync_thread_death_exception(), "must be wisp_thread_death_exception");
// JavaCalls will be skipped if current thread has a pending exception
// mannually clear all async exceptions before calling into java
jt->clear_aync_thread_death_exception();
}

wisp_thread->_unpark_status = WispThread::_wisp_unpark_begin;
JavaValue result(T_VOID);
JavaCallArguments args;
Expand Down
15 changes: 15 additions & 0 deletions src/hotspot/share/runtime/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,21 @@ JavaThread* JavaThread::active() {
}
}

bool JavaThread::has_aync_thread_death_exception() {
assert(EnableCoroutine && Wisp2ThreadStop, "pre-condition");
return _pending_async_exception == Universe::wisp_thread_death_exception();
}

void JavaThread::clear_aync_thread_death_exception() {
assert(UseWisp2 && Wisp2ThreadStop, "pre-condition");
if (_pending_async_exception != NULL
&& _pending_async_exception == Universe::wisp_thread_death_exception()) {
_pending_async_exception = NULL;
set_async_exception_condition(_no_async_condition);
clear_suspend_flag(_has_async_exception);
}
}

bool JavaThread::is_lock_owned(address adr) const {
if (Thread::is_lock_owned(adr)) return true;

Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/runtime/thread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1643,6 +1643,9 @@ class JavaThread: public Thread {
bool has_attached_via_jni() const { return is_attaching_via_jni() || _jni_attach_state == _attached_via_jni; }
inline void set_done_attaching_via_jni();

bool has_aync_thread_death_exception();
void clear_aync_thread_death_exception();

// Stack dump assistance:
// Track the class we want to initialize but for which we have to wait
// on its init_lock() because it is already being initialized.
Expand Down
74 changes: 74 additions & 0 deletions test/jdk/com/alibaba/rcm/TestDeadLoopKillObjectMonitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* @test
* @library /test/lib
* @build TestDeadLoopKillObjectMonitor RcmUtils
* @summary test RCM TestKillThreads
* @modules java.base/com.alibaba.wisp.engine:+open
* @modules java.base/com.alibaba.rcm.internal:+open
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseWisp2 -XX:+Wisp2ThreadStop -XX:ActiveProcessorCount=1 TestDeadLoopKillObjectMonitor
*/

import com.alibaba.rcm.Constraint;
import com.alibaba.rcm.ResourceContainer;
import com.alibaba.rcm.ResourceType;
import com.alibaba.rcm.internal.RCMUnsafe;
import com.alibaba.wisp.engine.WispResourceContainerFactory;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class TestDeadLoopKillObjectMonitor {

private static Object obj = new Object();

public static void main(String[] args) throws Exception {
ResourceContainer container = RcmUtils.createContainer(Collections.singletonList(
ResourceType.CPU_PERCENT.newConstraint(100)));

CountDownLatch latch = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
try {
Thread.sleep(1000);
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
latch.countDown();
}
});
t2.setDaemon(true);
t2.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
t1.setDaemon(true);
t1.start();

Thread.sleep(100);
container.run(() -> {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true)
synchronized (obj) {
System.out.println("rr");
}
}
});
t.start();
});

Thread.sleep(100);
RCMUnsafe.killThreads(container);
}

}

0 comments on commit a6a2ff1

Please sign in to comment.