From d6a2d36ee72dd89c72dbd05720fd4bc81e4b20e2 Mon Sep 17 00:00:00 2001 From: Ranjit Mathew Date: Mon, 10 Feb 2003 23:52:56 +0000 Subject: [PATCH] Win32Process.java (destroy): Declare as native. 2003-02-10 Ranjit Mathew * java/lang/Win32Process.java (destroy): Declare as native. (hasExited): New native method. (exitValue): Define. (getErrorStream): Likewise. (getInputStream): Likewise. (getOutputStream): Likewise. (waitFor): Declare as native. (startProcess): New native method. (cleanup): Likewise. (ConcreteProcess): Define. (outputStream, inputStream, errorStream): New members. (procHandle, exitCode): Likewise. * java/lang/natWin32Process.cc (java::lang::ConcreteProcess::cleanup): Define. (java::lang::ConcreteProcess::destroy): Likewise. (java::lang::ConcreteProcess::hasExited): Likewise. (java::lang::ConcreteProcess::waitFor): Likewise. (new_string): Likewise. (java::lang::ConcreteProcess::startProcess): Likewise. From-SVN: r62657 --- libjava/ChangeLog | 23 +++ libjava/java/lang/Win32Process.java | 52 +++-- libjava/java/lang/natWin32Process.cc | 294 +++++++++++++++++++++++++++ 3 files changed, 349 insertions(+), 20 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 0f9454d7781..f5ec059558f 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,26 @@ +2003-02-10 Ranjit Mathew + + * java/lang/Win32Process.java (destroy): Declare as native. + (hasExited): New native method. + (exitValue): Define. + (getErrorStream): Likewise. + (getInputStream): Likewise. + (getOutputStream): Likewise. + (waitFor): Declare as native. + (startProcess): New native method. + (cleanup): Likewise. + (ConcreteProcess): Define. + (outputStream, inputStream, errorStream): New members. + (procHandle, exitCode): Likewise. + + * java/lang/natWin32Process.cc + (java::lang::ConcreteProcess::cleanup): Define. + (java::lang::ConcreteProcess::destroy): Likewise. + (java::lang::ConcreteProcess::hasExited): Likewise. + (java::lang::ConcreteProcess::waitFor): Likewise. + (new_string): Likewise. + (java::lang::ConcreteProcess::startProcess): Likewise. + 2003-02-10 Raif S. Naffah * java/math/BigInteger.java: diff --git a/libjava/java/lang/Win32Process.java b/libjava/java/lang/Win32Process.java index 72911d2961b..b1c7e027379 100644 --- a/libjava/java/lang/Win32Process.java +++ b/libjava/java/lang/Win32Process.java @@ -1,6 +1,6 @@ // Win32Process.java - Subclass of Process for Win32 systems. -/* Copyright (C) 2002 Free Software Foundation +/* Copyright (C) 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -22,51 +22,63 @@ import java.io.IOException; // This is entirely internal to our implementation. -// NOTE: when this is implemented, we'll need to add -// HANDLE_FLAG_INHERIT in FileDescriptor and other places, to make -// sure that file descriptors aren't inherited by the child process. -// See _Jv_platform_close_on_exec. - // This file is copied to `ConcreteProcess.java' before compilation. // Hence the class name apparently does not match the file name. final class ConcreteProcess extends Process { - public void destroy () - { - throw new Error("not implemented"); - } - + public native void destroy (); + + public native boolean hasExited (); + public int exitValue () { - throw new Error("not implemented"); + if (! hasExited ()) + throw new IllegalThreadStateException ("Process has not exited"); + + return exitCode; } public InputStream getErrorStream () { - throw new Error("not implemented"); + return errorStream; } public InputStream getInputStream () { - throw new Error("not implemented"); + return inputStream; } public OutputStream getOutputStream () { - throw new Error("not implemented"); + return outputStream; } - public int waitFor () throws InterruptedException - { - throw new Error("not implemented"); - } + public native int waitFor () throws InterruptedException; + + public native void startProcess (String[] progarray, + String[] envp, + File dir) + throws IOException; + + public native void cleanup (); public ConcreteProcess (String[] progarray, String[] envp, File dir) throws IOException { - throw new IOException("not implemented"); + startProcess (progarray, envp, dir); } + // The standard streams (stdin, stdout and stderr, respectively) + // of the child as seen by the parent process. + private OutputStream outputStream; + private InputStream inputStream; + private InputStream errorStream; + + // Handle to the child process - cast to HANDLE before use. + private int procHandle; + + // Exit code of the child if it has exited. + private int exitCode; } diff --git a/libjava/java/lang/natWin32Process.cc b/libjava/java/lang/natWin32Process.cc index e69de29bb2d..38e6f919174 100644 --- a/libjava/java/lang/natWin32Process.cc +++ b/libjava/java/lang/natWin32Process.cc @@ -0,0 +1,294 @@ +// natWin32Process.cc - Native side of Win32 process code. + +/* Copyright (C) 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +// Conflicts with the definition in "java/lang/reflect/Modifier.h" +#undef STRICT + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void +java::lang::ConcreteProcess::cleanup (void) +{ + if (inputStream != NULL) + { + inputStream->close (); + inputStream = NULL; + } + + if (outputStream != NULL) + { + outputStream->close (); + outputStream = NULL; + } + + if (errorStream != NULL) + { + errorStream->close (); + errorStream = NULL; + } +} + +void +java::lang::ConcreteProcess::destroy (void) +{ + if (! hasExited ()) + { + // Kill it forcibly and assign an (arbitrary) exit code of 0. + TerminateProcess ((HANDLE) procHandle, 0); + exitCode = 0; + + cleanup (); + } +} + +jboolean +java::lang::ConcreteProcess::hasExited (void) +{ + DWORD exitStatus; + + if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0) + { + // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the + // child actually exits with this return code, we have a + // problem here. See MSDN documentation on GetExitCodeProcess( ). + + if (exitStatus == STILL_ACTIVE) + return false; + else + { + cleanup (); + exitCode = exitStatus; + return true; + } + } + else + return true; +} + +jint +java::lang::ConcreteProcess::waitFor (void) +{ + if (! hasExited ()) + { + DWORD exitStatus = 0UL; + + // FIXME: The wait should be interruptible. + WaitForSingleObject ((HANDLE) procHandle, INFINITE); + + GetExitCodeProcess ((HANDLE) procHandle, &exitStatus); + exitCode = exitStatus; + + cleanup (); + } + + return exitCode; +} + +static char * +new_string (jstring string) +{ + jsize s = _Jv_GetStringUTFLength (string); + char *buf = (char *) _Jv_Malloc (s + 1); + _Jv_GetStringUTFRegion (string, 0, s, buf); + buf[s] = '\0'; + return buf; +} + +void +java::lang::ConcreteProcess::startProcess (jstringArray progarray, + jstringArray envp, + java::io::File *dir) +{ + using namespace java::io; + + procHandle = (jint) INVALID_HANDLE_VALUE; + + // Reconstruct the command line. + jstring *elts = elements (progarray); + + int cmdLineLen = 0; + + for (int i = 0; i < progarray->length; ++i) + cmdLineLen += (_Jv_GetStringUTFLength (elts[i]) + 1); + + char *cmdLine = (char *) _Jv_Malloc (cmdLineLen + 1); + + int j = 0; + for (int i = 0; i < progarray->length; ++i) + { + jsize s = _Jv_GetStringUTFLength (elts[i]); + _Jv_GetStringUTFRegion (elts[i], 0, s, (cmdLine + j)); + + j += s; + *(cmdLine + j) = ' '; + j++; + } + *(cmdLine + j) = '\0'; + + // Get the environment, if any. + char *env = NULL; + if (envp) + { + elts = elements (envp); + + int envLen = 0; + for (int i = 0; i < envp->length; ++i) + envLen += (_Jv_GetStringUTFLength (elts[i]) + 1); + + env = (char *) _Jv_Malloc (envLen + 1); + + int j = 0; + for (int i = 0; i < envp->length; ++i) + { + jsize s = _Jv_GetStringUTFLength (elts[i]); + _Jv_GetStringUTFRegion (elts[i], 0, s, (env + j)); + + j += s; + *(env + j) = '\0'; + j++; + } + *(env + j) = '\0'; + } + + // Get the working directory path, if specified. + char *wdir = NULL; + if (dir != NULL) + wdir = new_string (dir->getPath ()); + + errorStream = NULL; + inputStream = NULL; + outputStream = NULL; + + java::lang::Throwable *exc = NULL; + + try + { + // We create anonymous pipes to communicate with the child + // on each of standard streams. + + HANDLE cldStdInRd, cldStdInWr; + HANDLE cldStdOutRd, cldStdOutWr; + HANDLE cldStdErrRd, cldStdErrWr; + + SECURITY_ATTRIBUTES sAttrs; + + // Explicitly allow the handles to the pipes to be inherited. + sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES); + sAttrs.bInheritHandle = 1; + sAttrs.lpSecurityDescriptor = NULL; + + + char tmpBuff[64]; + if (CreatePipe (&cldStdInRd, &cldStdInWr, &sAttrs, 0) == 0) + { + sprintf (tmpBuff, + "Error creating stdin pipe (Win32 Error Code: %lu)", + GetLastError ()); + throw new IOException (JvNewStringLatin1 (tmpBuff)); + } + + if (CreatePipe (&cldStdOutRd, &cldStdOutWr, &sAttrs, 0) == 0) + { + sprintf (tmpBuff, + "Error creating stdout pipe (Win32 Error Code: %lu)", + GetLastError ()); + throw new IOException (JvNewStringLatin1 (tmpBuff)); + } + + if (CreatePipe (&cldStdErrRd, &cldStdErrWr, &sAttrs, 0) == 0) + { + sprintf (tmpBuff, + "Error creating stderr pipe (Win32 Error Code: %lu)", + GetLastError ()); + throw new IOException (JvNewStringLatin1 (tmpBuff)); + } + + outputStream = new FileOutputStream + (new FileDescriptor ((jint) cldStdInWr)); + inputStream = new FileInputStream + (new FileDescriptor ((jint) cldStdOutRd)); + errorStream = new FileInputStream + (new FileDescriptor ((jint) cldStdErrRd)); + + // Now create the child process. + PROCESS_INFORMATION pi; + STARTUPINFO si; + + ZeroMemory (&pi, sizeof (PROCESS_INFORMATION)); + + ZeroMemory (&si, sizeof (STARTUPINFO)); + si.cb = sizeof (STARTUPINFO); + + // Explicitly specify the handles to the standard streams. + si.dwFlags |= STARTF_USESTDHANDLES; + + si.hStdInput = cldStdInRd; + si.hStdOutput = cldStdOutWr; + si.hStdError = cldStdErrWr; + + if (CreateProcess (NULL, + cmdLine, + NULL, + NULL, + 1, + 0, + env, + wdir, + &si, + &pi) == 0) + { + sprintf (tmpBuff, + "Error creating child process (Win32 Error Code: %lu)", + GetLastError ()); + throw new IOException (JvNewStringLatin1 (tmpBuff)); + } + + procHandle = (jint ) pi.hProcess; + + // Close the wrong ends (for the parent) of the pipes. + CloseHandle (cldStdInRd); + CloseHandle (cldStdOutWr); + CloseHandle (cldStdErrWr); + + _Jv_Free (cmdLine); + if (env != NULL) + _Jv_Free (env); + if (wdir != NULL) + _Jv_Free (wdir); + } + catch (java::lang::Throwable *thrown) + { + cleanup (); + exc = thrown; + } + + if (exc != NULL) + throw exc; +}