Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4388188

Fork/exec fails after creating JVM using JNI from C (Linux)

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P2 P2
    • None
    • 1.3.0
    • hotspot
    • x86
    • linux



      Name: yyT116575 Date: 11/10/2000


      9 Nov 2000, eval1127@eng -- see first two bugs (# 4373248 and 4366835) returned via:
      http://search.java.sun.com/query.html?qt=%2Bfork+%2Blinux+&col=obug&qp=&qs=&qc=&pw=100%25&ws=0&qm=0&st=1&nh=10&lk=1&rf=0&rq=0
      ------------------------------------------
      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
      Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)


      After using JNI to create the JVM from a C/C++ program under Linux, it is
      no longer possible to fork/exec a new process from that main process.
      It is not possible to spawn a process from C++ (using fork() + exec()),
      nor is it possible to spawn a process from the Java code (using Runtime.exec()).
      The attached program demonstrates the problem.

      1. Test fork from C++
      > forktest
      This program first launches the JVM, and then calls fork() and exec().
      The child process attempts to run a simple script (tick.sh) that loops
      forever printing counter output to a file.
      The child process is forked, but then freezes when calling exec.
      The JVM dies, leaving a single defunct java process.
      The stack trace of the child process is :

      #0 0x404d8deb in __sigsuspend (set=0xbfffd8d8) at
      ../sysdeps/unix/sysv/linux/sigsuspend.c:48
      #1 0x405cdc82 in __pthread_wait_for_restart_signal (self=0x405d5940) at
      pthread.c:785
      #2 0x405cd6f6 in __pthread_kill_other_threads_np () at restart.h:26
      #3 0x4054bd6b in __execve (file=0x8048d9a "./tick.sh", argv=0xbfffdab4,
      envp=0x808f770)
          at ../sysdeps/unix/sysv/linux/execve.c:39
      #4 0x4054bf67 in execl (path=0x8048d9a "./tick.sh", arg=0x8048d92 "tick.sh") at
      execl.c:74
      #5 0x8048a59 in testCFork ()
      #6 0x8048b3d in main ()
      #7 0x404d29cb in __libc_start_main (main=0x8048b14 <main>, argc=1,
      argv=0xbfffeb44, init=0x8048610 <_init>,
          fini=0x8048ccc <_fini>, rtld_fini=0x4000ae60 <_dl_fini>,
      stack_end=0xbfffeb3c)
          at ../sysdeps/generic/libc-start.c:92

      The forktest program runs OK if the JVM is not launched before the fork.



      2. Test fork from Java

      The java Spawn class executes the shell script by using Runtime.exec().
      When run from C++ the Spawn class is created but appears to fail in the
      exec, even though no exception is raised. ie.
      > forktest java

      This program runs ok when launched directly using the JVM. ie.
      > java Spawn


      The problem appeared on with Redhat Linux (kernel 2.2.14-12 & 2.2.16-3) using
      either jdk1.2.2 or jdk1.3.
      The problem did not occur on SPARC Solaris 7 with jdk1.3.


      ------------------------------------------------------

      The forktest program was built using:
      > javac Spawn.java
      > gcc ForkTest.C -I$JAVAHOME/include -I$JAVAHOME/include/linux -L$JAVAHOME/jre/lib/i386 -L$JAVAHOME/jre/lib/i386/client -L$JAVAHOME/jre/lib/i386/native_threads -ljava -ljvm -lhpi -lstdc++ -lnsl -o forktest



      //--------------------------- file ForkTest.C ---------------------------

      #include <jni.h>
      #include <iostream.h>
      #include <unistd.h>
      #include <stdlib.h>

      // Create the Java virtual machine, and start a test object.
      static JNIEnv* createJVM(void) {
          JavaVM* jvm;
          JNIEnv* env;

          JavaVMOption options[20];
          int numOptions = 0;
          options[numOptions++].optionString = "-Djava.class.path=.";

          JavaVMInitArgs args;
          args.version = JNI_VERSION_1_2;
          args.options = options;
          args.nOptions = (jint)numOptions;
          args.ignoreUnrecognized = 0;

          if (JNI_CreateJavaVM(&jvm, (void **)&env, &args)) {
              cerr << "Can't create JVM." << endl;
              exit(1);
          }
          cout << "JVM created." << endl;
          return env;
      }

      void testJavaFork(JNIEnv *env) {
          jclass clazz = env->FindClass("Spawn");
          if (env->ExceptionOccurred() || (clazz == 0)) {
              cerr << "Can't find Java class." << endl;
              exit(1);
          }
          jmethodID init = env->GetMethodID(clazz, "<init>", "()V");
          if (env->ExceptionOccurred() || (init == 0)) {
              cerr << "Can't find Java method." << endl;
              exit(1);
          }
          jobject obj = env->NewObject(clazz, init);
          if (env->ExceptionOccurred() || (obj == 0)) {
              cerr << "Can't create Java object." << endl;
              exit(1);
          }
          cout << "Java object created." << endl;
      }

      void testCFork(void) {
          pid_t pid;
          if ((pid = fork()) == 0) {
              // Child process
              execl("./tick.sh", "tick.sh", (char *)0);
              cerr << "Error in C exec." << endl;
              _exit(1);
          }
          // Parent process
          cout << "Child PID = " << pid << endl;
      }

      int main(int argc, char **argv) {

          JNIEnv* env = createJVM();

          if (argc > 1) {
              testJavaFork(env);
          } else {
              testCFork();
          }

          int count = 0;
          while (1) {
              cout << "Parent " << ++count << endl;
              sleep(5);
          }
      }

      //--------------------------- file Spawn.java ---------------------------

      import java.io.*;

      public class Spawn implements Runnable {
          public static void main(String[] args){
              new Spawn();
          }

          /**
           * Use a new thread to wait for process termination
           */
          public Spawn() {
              new Thread(this).start();
          }

          /**
           * Spawn a process to run a ticker shell script.
           */
          public void run() {
              try {
                  System.out.println("Spawning tick....");
                  Process proc = Runtime.getRuntime().exec("tick.sh");
                  System.out.println("Done spawn.");
                  proc.waitFor();
                  System.out.println("tick exit status = " + proc.exitValue());
              } catch (Exception e) {
                  System.err.println("Java exec failed " + e.getMessage());
                  return;
              }
          }
      }

      //--------------------------- file tick.sh ---------------------------
      #!/bin/sh

      echo "pid = $$" | tee log
      count=0
      while [ 1 ]
      do
          count=`expr $count + 1`
          echo "Tick = $count" | tee -a log
          sleep 4
      done
      (Review ID: 112065)
      ======================================================================

            duke J. Duke
            yyoungsunw Yung-ching Young (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: