Skip to content

Commit

Permalink
Merge pull request #17639 from JasonFengJ9/criuparkstm-v0.40.0
Browse files Browse the repository at this point in the history
(v0.40.0-release) CRIU throws JVMCRIUException in single threaded mode if parks no timeout
  • Loading branch information
tajila authored Jun 23, 2023
2 parents 2684cbb + 93ce515 commit efe6ee2
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 51 deletions.
2 changes: 1 addition & 1 deletion runtime/oti/vm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4772,7 +4772,7 @@ prepareClass(J9VMThread *currentThread, J9Class *clazz);
void
initializeClass(J9VMThread *currentThread, J9Class *clazz);

/* -------------------- threadpark.c ------------ */
/* -------------------- threadpark.cpp ------------ */

/**
* @param[in] vmThread the current thread
Expand Down
2 changes: 1 addition & 1 deletion runtime/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ set(main_sources
stringhelpers.cpp
swalk.c
threadhelp.cpp
threadpark.c
threadpark.cpp
throwexception.c
UpcallExceptionHandler.cpp
UpcallThunkMem.cpp
Expand Down
20 changes: 20 additions & 0 deletions runtime/vm/threadpark.c → runtime/vm/threadpark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@
#include "omrthread.h"
#include "ut_j9vm.h"

#include "VMHelpers.hpp"

#include <string.h>

extern "C" {

void
threadParkImpl(J9VMThread *vmThread, BOOLEAN timeoutIsEpochRelative, I_64 timeout)
{
Expand Down Expand Up @@ -62,6 +66,20 @@ threadParkImpl(J9VMThread *vmThread, BOOLEAN timeoutIsEpochRelative, I_64 timeou
}
thrstate |= J9_PUBLIC_FLAGS_THREAD_TIMED;
}
#if defined(J9VM_OPT_CRIU_SUPPORT)
else {
/* timeoutIsEpochRelative is false and timeout = 0 */
if (J9_IS_SINGLE_THREAD_MODE(vm)
&& VM_VMHelpers::threadCanRunJavaCode(vmThread)
&& (vmThread == vm->checkpointState.checkpointThread)
&& J9_ARE_NO_BITS_SET(vmThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_FOR_CHECKPOINT)
) {
/* This is the checkpoint/restore thread, can't park indefinitely. */
setCRIUSingleThreadModeJVMCRIUException(vmThread, 0, 0);
return;
}
}
#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */

#ifdef J9VM_OPT_SIDECAR
/* Increment the wait count even if the deadline is past. */
Expand Down Expand Up @@ -141,3 +159,5 @@ threadUnparkImpl(J9VMThread *vmThread, j9object_t threadObject)
}
}
}

}
17 changes: 12 additions & 5 deletions test/functional/cmdLineTests/criu/criu_nonPortable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,12 @@

<test id="Create Criu Checkpoint Image once and no restore - TestSingleThreadModeCheckpointException">
<command>bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$" $MAINCLASS_SINGLETHREADMODE_CHECKPOINT$ 1 1 true</command>
<output type="success" caseSensitive="yes" regex="no">TestSingleThreadModeCheckpointException: PASSED</output>
<output type="required" caseSensitive="yes" regex="no">Pre-checkpoint</output>
<output type="failure" caseSensitive="no" regex="no">TestSingleThreadModeCheckpointException: FAILED</output>
<output type="success" caseSensitive="yes" regex="no">testSingleThreadModeCheckpointExceptionJUCLock: PASSED</output>
<output type="success" caseSensitive="yes" regex="no">testSingleThreadModeCheckpointExceptionSynMonitor: PASSED</output>
<output type="required" caseSensitive="yes" regex="no">Pre-checkpoint JUC LOCK</output>
<output type="required" caseSensitive="yes" regex="no">Pre-checkpoint synchronization</output>
<output type="failure" caseSensitive="no" regex="no">testSingleThreadModeCheckpointExceptionJUCLock: FAILED</output>
<output type="failure" caseSensitive="no" regex="no">testSingleThreadModeCheckpointExceptionSynMonitor: FAILED</output>
<output type="failure" caseSensitive="no" regex="no">Killed</output>
<output type="failure" caseSensitive="yes" regex="no">CRIU is not enabled</output>
<output type="failure" caseSensitive="yes" regex="no">Operation not permitted</output>
Expand All @@ -197,9 +200,13 @@

<test id="Create and Restore Criu Checkpoint Image once - TestSingleThreadModeRestoreException">
<command>bash $SCRIPPATH$ $TEST_RESROOT$ $JAVA_COMMAND$ "$JVM_OPTIONS$" $MAINCLASS_SINGLETHREADMODE_RESTORE$ 1 1 false</command>
<output type="success" caseSensitive="yes" regex="no">org.eclipse.openj9.criu.JVMRestoreException: Exception thrown when running user post-restore</output>
<output type="success" caseSensitive="yes" regex="no">testSingleThreadModeRestoreExceptionJUCLock: PASSED</output>
<output type="success" caseSensitive="yes" regex="no">testSingleThreadModeRestoreExceptionSynLock: PASSED</output>
<output type="required" caseSensitive="yes" regex="no">Pre-checkpoint JUC LOCK</output>
<output type="required" caseSensitive="yes" regex="no">Pre-checkpoint synchronization</output>
<output type="failure" caseSensitive="no" regex="no">testSingleThreadModeRestoreExceptionJUCLock: FAILED</output>
<output type="failure" caseSensitive="no" regex="no">testSingleThreadModeRestoreExceptionSynLock: FAILED</output>
<output type="required" caseSensitive="no" regex="no">Killed</output>
<output type="required" caseSensitive="yes" regex="no">Pre-checkpoint</output>
<output type="failure" caseSensitive="yes" regex="no">CRIU is not enabled</output>
<output type="failure" caseSensitive="yes" regex="no">Operation not permitted</output>
<!-- If CRIU can't acquire the original thread IDs, this test will fail. Nothing can be done about this failure. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,63 +26,130 @@

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestSingleThreadModeCheckpointException {

private static final Object lock = new Object();
private static final Lock jucLock = new ReentrantLock();
private static final Object synLock = new Object();

public static void main(String[] args) {
new TestSingleThreadModeCheckpointException().testSingleThreadModeCheckpointException();
new TestSingleThreadModeCheckpointException().testAll();
}

Thread doCheckpoint() {
void testAll() {
testSingleThreadModeCheckpointExceptionJUCLock();
testSingleThreadModeCheckpointExceptionSynLock();
}

Thread doCheckpointJUCLock(CRIUSupport criu) {
Thread t = new Thread(new Runnable() {
public void run() {
boolean result = false;
Path imagePath = Paths.get("cpData");
CRIUTestUtils.deleteCheckpointDirectory(imagePath);
CRIUTestUtils.createCheckpointDirectory(imagePath);
CRIUSupport criu = new CRIUSupport(imagePath);
criu.registerPreCheckpointHook(new Runnable() {
public void run() {
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() before synchronized on " + lock);
synchronized (lock) {
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() within synchronized on " + lock);
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() before ReentrantLock.lock()");
jucLock.lock();
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() within ReentrantLock");
jucLock.unlock();
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() after ReentrantLock.unlock()");
}
});

try {
System.out.println("Pre-checkpoint JUC LOCK");
CRIUTestUtils.checkPointJVMNoSetup(criu, CRIUTestUtils.imagePath, false);
} catch (JVMCheckpointException jvmce) {
result = true;
}
if (result) {
System.out.println("testSingleThreadModeCheckpointExceptionJUCLock: PASSED.");
} else {
System.out.println("testSingleThreadModeCheckpointExceptionJUCLock: FAILED.");
}
}
});
return t;
}

void testSingleThreadModeCheckpointExceptionJUCLock() {
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointExceptionJUCLock() before ReentrantLock.lock()");
jucLock.lock();
CRIUSupport criu = CRIUTestUtils.prepareCheckPointJVM(CRIUTestUtils.imagePath);
if (criu == null) {
// "CRIU is not enabled" is to appear and cause the test failure.
return;
}

try {
// ensure the lock already taken before performing a checkpoint
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointExceptionJUCLock() before doCheckpoint()");
Thread tpc = doCheckpointJUCLock(criu);
tpc.start();
// set timeout 10s
tpc.join(10000);
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointExceptionJUCLock() after doCheckpoint()");
} catch (InterruptedException e) {
}
jucLock.unlock();
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointExceptionJUCLock() after ReentrantLock.unlock()");
}

Thread doCheckpointSynLock(CRIUSupport criu) {
Thread t = new Thread(new Runnable() {
public void run() {
boolean result = false;
criu.registerPreCheckpointHook(new Runnable() {
public void run() {
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() before synchronized on " + synLock);
synchronized (synLock) {
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() within synchronized on " + synLock);
}
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() after synchronized on " + lock);
CRIUTestUtils.showThreadCurrentTime("PreCheckpointHook() after synchronized on " + synLock);
}
});

try {
System.out.println("Pre-checkpoint");
CRIUTestUtils.checkPointJVM(criu, imagePath, false);
System.out.println("Pre-checkpoint synchronization");
CRIUTestUtils.checkPointJVMNoSetup(criu, CRIUTestUtils.imagePath, false);
} catch (JVMCheckpointException jvmce) {
result = true;
}
if (result) {
System.out.println("TestSingleThreadModeCheckpointException: PASSED.");
System.out.println("testSingleThreadModeCheckpointExceptionSynLock: PASSED.");
} else {
System.out.println("TestSingleThreadModeCheckpointException: FAILED.");
System.out.println("testSingleThreadModeCheckpointExceptionSynLock: FAILED.");
}
}
});
return t;
}

void testSingleThreadModeCheckpointException() {
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointException() before synchronized on " + lock);
synchronized (lock) {
void testSingleThreadModeCheckpointExceptionSynLock() {
CRIUTestUtils.showThreadCurrentTime(
"testSingleThreadModeCheckpointExceptionSynLock() before synchronized on " + synLock);
synchronized (synLock) {
CRIUSupport criu = CRIUTestUtils.prepareCheckPointJVM(CRIUTestUtils.imagePath);
if (criu == null) {
// "CRIU is not enabled" is to appear and cause the test failure.
return;
}

try {
// ensure the lock already taken before performing a checkpoint
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointException() before doCheckpoint()");
Thread tpc = doCheckpoint();
CRIUTestUtils.showThreadCurrentTime(
"testSingleThreadModeCheckpointExceptionSynLock() before doCheckpoint()");
Thread tpc = doCheckpointSynLock(criu);
tpc.start();
// set timeout 10s
tpc.join(10000);
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointException() after doCheckpoint()");
CRIUTestUtils.showThreadCurrentTime(
"testSingleThreadModeCheckpointExceptionSynLock() after doCheckpoint()");
} catch (InterruptedException e) {
}
}
CRIUTestUtils.showThreadCurrentTime("testSingleThreadModeCheckpointException() after synchronized on " + lock);
CRIUTestUtils.showThreadCurrentTime(
"testSingleThreadModeCheckpointExceptionSynLock() after synchronized on " + synLock);
}
}
Loading

0 comments on commit efe6ee2

Please sign in to comment.