A quick overview of the code of my C++ Qt application (simplified for the purpose of readability).
- Make an out-of-process call with QProcess
- Invoke a java class via JNI
- Make another out-of-process call with QProcess
The problem is that any QProcess calls after (2) does not end (stuck at waitForFinished). I believe the application does not receive SIGCHLD and is trapped by JVM.
However, if I create JVM first before any QProcess call, then all QProcess calls after JVM works.
In summary,
QProcess() -> invokeJNI() -> QProcess == gets stuck at 2nd QProcess' waitForFinished()
invokeJNI() -> QProcess ->QProcess .. == WORKS!
void invokeQProcess(int id) {
QProcess process;
QString program = "/sbin/md5";
QStringList args;
args << "/tmp/tempFile.txt";
process.start(program, args);
if (!process.waitForFinished(-1)) {
QString output(process.readAllStandardOutput());
qDebug() << id << " QProcess failed with exit code -1 " << output;
return;
}
QString output(process.readAllStandardOutput());
qDebug() << id << " QProcess succeeded with output - " << output;
}
void invokeJNI() {
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=."
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
JavaVM *jvm;
JNIEnv *env;
JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
jclass sampleClass = env->FindClass("SampleClass");
jmethodID method = env->GetStaticMethodID(sampleClass, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(sampleClass, method, objArray);
jvm->DestroyJavaVM();
}
int main() {
invokeQProcess(1);
invokeJNI();
invokeQProcess(2);
return 0;
}
public class SampleClass {
public static void main(String[] args) {
List<String> command = new ArrayList<String>();
command.add("echo");
command.add("HelloJava");
ProcessBuilder pb = new ProcessBuilder(command);
process = pb.start();
try {
process.waitFor();
} catch (InterruptedException e) {
process.destroy();
}
}
}
Setup: Qt 5.12 | OpenJDK 11.0.5 | issue in both Win & macOS
EDIT: The problem arises in the first sequence only when the java method in JNI call has an out-of-process call inside (I'm using ProcessBuilder). Updated JNI call and added Java class.