Win32Process.java (destroy): Declare as native.
authorRanjit Mathew <rmathew@hotmail.com>
Mon, 10 Feb 2003 23:52:56 +0000 (23:52 +0000)
committerTom Tromey <tromey@gcc.gnu.org>
Mon, 10 Feb 2003 23:52:56 +0000 (23:52 +0000)
2003-02-10  Ranjit Mathew  <rmathew@hotmail.com>

* 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
libjava/java/lang/Win32Process.java
libjava/java/lang/natWin32Process.cc

index 0f9454d..f5ec059 100644 (file)
@@ -1,3 +1,26 @@
+2003-02-10  Ranjit Mathew  <rmathew@hotmail.com>
+
+       * 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 <raif@fl.net.au>
 
        * java/math/BigInteger.java:
index 72911d2..b1c7e02 100644 (file)
@@ -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;
 }
index e69de29..38e6f91 100644 (file)
@@ -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 <config.h>
+
+#include <stdio.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+// Conflicts with the definition in "java/lang/reflect/Modifier.h"
+#undef STRICT
+
+#include <gcj/cni.h>
+#include <jvm.h>
+
+#include <java/lang/ConcreteProcess.h>
+#include <java/lang/IllegalThreadStateException.h>
+#include <java/lang/InterruptedException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/Thread.h>
+#include <java/io/File.h>
+#include <java/io/FileDescriptor.h>
+#include <java/io/FileInputStream.h>
+#include <java/io/FileOutputStream.h>
+#include <java/io/IOException.h>
+#include <java/lang/OutOfMemoryError.h>
+
+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;
+}