From 3f8a370ba8631cbc6bdb7fed3b39a043be793477 Mon Sep 17 00:00:00 2001 From: James Sanders Date: Fri, 30 Nov 2007 16:39:51 -0700 Subject: [PATCH 1/2] Implemented Runtime.exec, Process.waitFor and Process.exitValue for non-windows --- classpath/java-lang.cpp | 156 +++++++++++++++++++++++++++++++ classpath/java/lang/Runtime.java | 2 - test/RuntimeExec.java | 45 ++++++--- 3 files changed, 187 insertions(+), 16 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 9a73e90715..870cdd1639 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -1,6 +1,7 @@ #include "math.h" #include "stdlib.h" #include "sys/time.h" +#include "sys/wait.h" #include "time.h" #include "time.h" #include "string.h" @@ -8,6 +9,9 @@ #include "stdint.h" #include "jni.h" #include "jni-util.h" +#include "errno.h" +#include "fcntl.h" +#include "unistd.h" #ifdef WIN32 # include "windows.h" @@ -69,6 +73,35 @@ namespace { } return fd; } +#else + void makePipe(JNIEnv* e, int p[2]) + { + if(pipe(p) != 0) { + throwNew(e, "java/io/IOException", strerror(errno)); + } + } + + void safeClose(int &fd) + { + if(fd != -1) close(fd); + fd = -1; + } + + void close(int p[2]) + { + ::close(p[0]); + ::close(p[1]); + } + + void clean(JNIEnv* e, jobjectArray command, char** p) + { + int i = 0; + for(char** x = p; *x; ++x, ++i){ + jstring element = (jstring) e->GetObjectArrayElement(command, i); + e->ReleaseStringUTFChars(element, *x); + } + free(p); + } #endif } @@ -165,6 +198,129 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) } return exitCode; } +#else +extern "C" JNIEXPORT void JNICALL +Java_java_lang_Runtime_exec(JNIEnv* e, jclass, + jobjectArray command, jlongArray process) +{ + char** argv = static_cast(malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); + int i; + for(i = 0; i < e->GetArrayLength(command); i++){ + jstring element = (jstring) e->GetObjectArrayElement(command, i); + char* s = const_cast(e->GetStringUTFChars(element, 0)); + argv[i] = s; + } + argv[i] = 0; + + int in[] = { -1, -1 }; + int out[] = { -1, -1 }; + int err[] = { -1, -1 }; + int msg[] = { -1, -1 }; + + makePipe(e, in); + if(e->ExceptionOccurred()) return; + jlong inDescriptor = static_cast(in[0]); + e->SetLongArrayRegion(process, 1, 1, &inDescriptor); + makePipe(e, out); + if(e->ExceptionOccurred()) return; + jlong outDescriptor = static_cast(out[1]); + e->SetLongArrayRegion(process, 1, 1, &outDescriptor); + makePipe(e, err); + if(e->ExceptionOccurred()) return; + jlong errDescriptor = static_cast(err[0]); + e->SetLongArrayRegion(process, 1, 1, &errDescriptor); + makePipe(e, msg); + if(e->ExceptionOccurred()) return; + if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { + throwNew(e, "java/io/IOException", strerror(errno)); + return; + } + + pid_t pid = fork(); + switch(pid){ + case -1: // error + throwNew(e, "java/io/IOException", strerror(errno)); + return; + case 0: { // child + // Setup stdin, stdout and stderr + dup2(in[1], 1); + close(in); + dup2(out[0], 0); + close(out); + dup2(err[1], 2); + close(err); + close(msg[0]); + + execvp(argv[0], argv); + + // Error if here + char c = errno; + write(msg[1], &c, 1); + exit(127); + } break; + + default: { //parent + jlong JNIPid = static_cast(pid); + e->SetLongArrayRegion(process, 0, 1, &JNIPid); + + safeClose(in[1]); + safeClose(out[0]); + safeClose(err[1]); + safeClose(msg[1]); + + char c; + int r = read(msg[0], &c, 1); + if(r == -1) { + throwNew(e, "java/io/IOException", strerror(errno)); + return; + } else if(r) { + throwNew(e, "java/io/IOException", strerror(c)); + return; + } + } break; + } + + safeClose(msg[0]); + clean(e, command, argv); + + fcntl(in[0], F_SETFD, FD_CLOEXEC); + fcntl(out[1], F_SETFD, FD_CLOEXEC); + fcntl(err[0], F_SETFD, FD_CLOEXEC); +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_lang_Runtime_exitValue(JNIEnv* e, jclass, jlong pid) +{ + int status; + pid_t returned = waitpid(pid, &status, WNOHANG); + if(returned == 0){ + throwNew(e, "java/lang/IllegalThreadStateException", strerror(errno)); + } else if(returned == -1){ + throwNew(e, "java/lang/Exception", strerror(errno)); + } + + return WEXITSTATUS(status); +} + +extern "C" JNIEXPORT jint JNICALL +Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) +{ + bool finished = false; + int status; + int exitCode; + while(!finished){ + waitpid(pid, &status, 0); + if(WIFEXITED(status)){ + finished = true; + exitCode = WEXITSTATUS(status); + } else if(WIFSIGNALED(status)){ + finished = true; + exitCode = -1; + } + } + + return exitCode; +} #endif extern "C" JNIEXPORT jstring JNICALL diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 9307ede463..b9941dd36a 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -49,8 +49,6 @@ public class Runtime { return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); } - //private static native void exec(String command, int[] process); - private static native void exec(String[] command, long[] process); private static native int exitValue(long pid); diff --git a/test/RuntimeExec.java b/test/RuntimeExec.java index 7aa53f3944..2895c61bf9 100644 --- a/test/RuntimeExec.java +++ b/test/RuntimeExec.java @@ -4,15 +4,28 @@ import java.lang.Process; public class RuntimeExec { public static void main(String[] args) throws java.io.IOException, java.lang.InterruptedException { Runtime runtime = Runtime.getRuntime(); - - System.out.println("Executing internet explorer"); - String ieStr = "\"c:\\program files\\internet explorer\\iexplore.exe\" http://www.google.com"; - Process ie = runtime.exec(ieStr); - - System.out.println("Executing firefox"); + String ieStr = null; + String charmapStr = null; String[] firefox = new String[2]; - firefox[0] = "c:\\program files\\mozilla firefox\\firefox.exe"; - firefox[1] = "http://www.google.com"; + + if(System.getProperty("os.name").equals("windows")){ + System.out.println("Executing internet explorer"); + ieStr = "\"c:\\program files\\internet explorer\\iexplore.exe\" http://www.google.com"; + } else { + System.out.println("Executing Firefox using string"); + ieStr = "firefox http://www.google.com"; + } + Process ie = runtime.exec(ieStr); + + if(System.getProperty("os.name").equals("windows")){ + System.out.println("Executing firefox"); + firefox[0] = "c:\\program files\\mozilla firefox\\firefox.exe"; + firefox[1] = "http://www.google.com"; + } else { + System.out.println("Executing Firefox using array"); + firefox[0] = "firefox"; + firefox[1] = "http://www.google.com"; + } Process ff = runtime.exec(firefox); boolean ffSuccess = false; @@ -20,21 +33,25 @@ public class RuntimeExec { while(!(ieSuccess && ffSuccess)){ if(!ffSuccess){ try{ - System.out.println("Firefox exit value: " + ff.exitValue()); + System.out.println("Exit value from string exec: " + ff.exitValue()); ffSuccess = true; } catch(IllegalThreadStateException e) {} } if(!ieSuccess){ try{ - System.out.println("Internet Explorer exit value: " + ie.exitValue()); + System.out.println("Exit value from array exec: " + ie.exitValue()); ieSuccess = true; } catch(IllegalThreadStateException e) {} } } - - System.out.println("Executing and waiting for charmap"); - String charmapStr = "c:\\windows\\system32\\charmap.exe"; + if(System.getProperty("os.name").equals("windows")){ + System.out.println("Executing and waiting for charmap"); + charmapStr = "c:\\windows\\system32\\charmap.exe"; + } else { + System.out.println("Executing and waiting for firefox"); + charmapStr = "firefox http://www.google.com"; + } Process cm = runtime.exec(charmapStr); - System.out.println("Charmap exit value: " + cm.waitFor()); + System.out.println("Exit value: " + cm.waitFor()); } } From 3cc1232fc2b5e35287f5af2144d5c6d990286f63 Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Mon, 3 Dec 2007 13:25:46 -0700 Subject: [PATCH 2/2] sys/wait.h should only be included when NOT compiling for win32 --- classpath/java-lang.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 870cdd1639..508d0fbbf9 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -1,7 +1,6 @@ #include "math.h" #include "stdlib.h" #include "sys/time.h" -#include "sys/wait.h" #include "time.h" #include "time.h" #include "string.h" @@ -21,6 +20,7 @@ # define SO_PREFIX "" #else # define SO_PREFIX "lib" +#include "sys/wait.h" #endif #ifdef __APPLE__