Commit cafa5032 by Mohan Embar Committed by Mohan Embar

re PR libgcj/12231 ([win32] Console applications spawned via Runtime.exec( ) in…

re PR libgcj/12231 ([win32] Console applications spawned via Runtime.exec( ) in a GUI application flash console window)

	PR libgcj/12231
	* java/lang/Win32Process.java (hasExited) Changed from
	public to private.
	(startProcess): Likewise.
	(cleanup): Likewise.
	* java/lang/natWin32Process.cc (cleanup) Don't close
	input, output and error streams.
	(ChildProcessPipe): New helper class.
	(startProcess): Refactored to use ChildProcessPipe.
	Use CREATE_NO_WINDOW when launching child process.

From-SVN: r73326
parent bbf76ec0
2003-11-06 Mohan Embar <gnustuff@thisiscool.com> 2003-11-06 Mohan Embar <gnustuff@thisiscool.com>
PR libgcj/12231
* java/lang/Win32Process.java (hasExited) Changed from
public to private.
(startProcess): Likewise.
(cleanup): Likewise.
* java/lang/natWin32Process.cc (cleanup) Don't close
input, output and error streams.
(ChildProcessPipe): New helper class.
(startProcess): Refactored to use ChildProcessPipe.
Use CREATE_NO_WINDOW when launching child process.
2003-11-06 Mohan Embar <gnustuff@thisiscool.com>
* include/win32.h (_Jv_platform_close_on_exec): Changed * include/win32.h (_Jv_platform_close_on_exec): Changed
signature and declared extern. signature and declared extern.
* win32.cc (_Jv_platform_close_on_exec): Implemented. * win32.cc (_Jv_platform_close_on_exec): Implemented.
......
...@@ -28,8 +28,6 @@ final class ConcreteProcess extends Process ...@@ -28,8 +28,6 @@ final class ConcreteProcess extends Process
{ {
public native void destroy (); public native void destroy ();
public native boolean hasExited ();
public int exitValue () public int exitValue ()
{ {
if (! hasExited ()) if (! hasExited ())
...@@ -55,13 +53,6 @@ final class ConcreteProcess extends Process ...@@ -55,13 +53,6 @@ final class ConcreteProcess extends Process
public native int waitFor () throws InterruptedException; 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, public ConcreteProcess (String[] progarray,
String[] envp, String[] envp,
File dir) File dir)
...@@ -89,4 +80,11 @@ final class ConcreteProcess extends Process ...@@ -89,4 +80,11 @@ final class ConcreteProcess extends Process
// Exit code of the child if it has exited. // Exit code of the child if it has exited.
private int exitCode; private int exitCode;
private native boolean hasExited ();
private native void startProcess (String[] progarray,
String[] envp,
File dir)
throws IOException;
private native void cleanup ();
} }
...@@ -29,23 +29,29 @@ details. */ ...@@ -29,23 +29,29 @@ details. */
void void
java::lang::ConcreteProcess::cleanup (void) java::lang::ConcreteProcess::cleanup (void)
{ {
if (inputStream != NULL) // FIXME:
{ // We used to close the input, output and
inputStream->close (); // error streams here, but we can't do that
inputStream = NULL; // because the caller also has the right
} // to close these and FileInputStream and FileOutputStream
// scream if you attempt to close() them twice. Presently,
if (outputStream != NULL) // we use _Jv_platform_close_on_exec, which is similar
{ // to the POSIX approach.
outputStream->close (); //
outputStream = NULL; // What I wanted to do is have private nested
} // classes in ConcreteProcess which extend FileInputStream
// and FileOutputStream, respectively, but override
if (errorStream != NULL) // close() to permit multiple calls to close(). This
{ // led to class header and platform configury issues
errorStream->close (); // that I didn't feel like dealing with. However,
errorStream = NULL; // this approach could conceivably be a good multiplatform
} // one since delaying the pipe close until process
// termination could be wasteful if many child processes
// are spawned within the parent process' lifetime.
inputStream = NULL;
outputStream = NULL;
errorStream = NULL;
if (procHandle) if (procHandle)
{ {
CloseHandle((HANDLE) procHandle); CloseHandle((HANDLE) procHandle);
...@@ -129,6 +135,76 @@ java::lang::ConcreteProcess::waitFor (void) ...@@ -129,6 +135,76 @@ java::lang::ConcreteProcess::waitFor (void)
return exitCode; return exitCode;
} }
// Helper class for creating and managing the pipes
// used for I/O redirection for child processes.
class ChildProcessPipe
{
public:
// Indicates from the child process' point of view
// whether the pipe is for reading or writing.
enum EType {INPUT, OUTPUT};
ChildProcessPipe(EType eType);
~ChildProcessPipe();
// Returns a pipe handle suitable for use by the parent process
HANDLE getParentHandle();
// Returns a pipe handle suitable for use by the child process.
HANDLE getChildHandle();
private:
EType m_eType;
HANDLE m_hRead, m_hWrite;
};
ChildProcessPipe::ChildProcessPipe(EType eType):
m_eType(eType)
{
SECURITY_ATTRIBUTES sAttrs;
// Explicitly allow the handles to the pipes to be inherited.
sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES);
sAttrs.bInheritHandle = 1;
sAttrs.lpSecurityDescriptor = NULL;
if (CreatePipe (&m_hRead, &m_hWrite, &sAttrs, 0) == 0)
{
DWORD dwErrorCode = GetLastError ();
throw new java::io::IOException (
_Jv_WinStrError ("Error creating pipe", dwErrorCode));
}
// If this is the read end of the child, we need
// to make the parent write end non-inheritable. Similarly,
// if this is the write end of the child, we need to make
// the parent read end non-inheritable. If we didn't
// do this, the child would inherit these ends and we wouldn't
// be able to close them from our end. For full details,
// do a Google search on "Q190351".
HANDLE& rhStd = m_eType==INPUT ? m_hWrite : m_hRead;
_Jv_platform_close_on_exec (rhStd);
}
ChildProcessPipe::~ChildProcessPipe()
{
// Close the parent end of the pipe. This
// destructor is called after the child process
// has been spawned.
CloseHandle(getChildHandle());
}
HANDLE ChildProcessPipe::getParentHandle()
{
return m_eType==INPUT ? m_hWrite : m_hRead;
}
HANDLE ChildProcessPipe::getChildHandle()
{
return m_eType==INPUT ? m_hRead : m_hWrite;
}
void void
java::lang::ConcreteProcess::startProcess (jstringArray progarray, java::lang::ConcreteProcess::startProcess (jstringArray progarray,
jstringArray envp, jstringArray envp,
...@@ -197,46 +273,16 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, ...@@ -197,46 +273,16 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray,
{ {
// We create anonymous pipes to communicate with the child // We create anonymous pipes to communicate with the child
// on each of standard streams. // on each of standard streams.
ChildProcessPipe aChildStdIn(ChildProcessPipe::INPUT);
ChildProcessPipe aChildStdOut(ChildProcessPipe::OUTPUT);
ChildProcessPipe aChildStdErr(ChildProcessPipe::OUTPUT);
HANDLE cldStdInRd, cldStdInWr; outputStream = new FileOutputStream (new FileDescriptor (
HANDLE cldStdOutRd, cldStdOutWr; (jint) aChildStdIn.getParentHandle ()));
HANDLE cldStdErrRd, cldStdErrWr; inputStream = new FileInputStream (new FileDescriptor (
(jint) aChildStdOut.getParentHandle ()));
SECURITY_ATTRIBUTES sAttrs; errorStream = new FileInputStream (new FileDescriptor (
(jint) aChildStdErr.getParentHandle ()));
// Explicitly allow the handles to the pipes to be inherited.
sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES);
sAttrs.bInheritHandle = 1;
sAttrs.lpSecurityDescriptor = NULL;
if (CreatePipe (&cldStdInRd, &cldStdInWr, &sAttrs, 0) == 0)
{
DWORD dwErrorCode = GetLastError ();
throw new IOException (_Jv_WinStrError ("Error creating stdin pipe",
dwErrorCode));
}
if (CreatePipe (&cldStdOutRd, &cldStdOutWr, &sAttrs, 0) == 0)
{
DWORD dwErrorCode = GetLastError ();
throw new IOException (_Jv_WinStrError ("Error creating stdout pipe",
dwErrorCode));
}
if (CreatePipe (&cldStdErrRd, &cldStdErrWr, &sAttrs, 0) == 0)
{
DWORD dwErrorCode = GetLastError ();
throw new IOException (_Jv_WinStrError ("Error creating stderr pipe",
dwErrorCode));
}
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. // Now create the child process.
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
...@@ -250,16 +296,20 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, ...@@ -250,16 +296,20 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray,
// Explicitly specify the handles to the standard streams. // Explicitly specify the handles to the standard streams.
si.dwFlags |= STARTF_USESTDHANDLES; si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = cldStdInRd; si.hStdInput = aChildStdIn.getChildHandle();
si.hStdOutput = cldStdOutWr; si.hStdOutput = aChildStdOut.getChildHandle();
si.hStdError = cldStdErrWr; si.hStdError = aChildStdErr.getChildHandle();
// Spawn the process. CREATE_NO_WINDOW only applies when
// starting a console application; it suppresses the
// creation of a console window. This flag is ignored on
// Win9X.
if (CreateProcess (NULL, if (CreateProcess (NULL,
cmdLine, cmdLine,
NULL, NULL,
NULL, NULL,
1, 1,
0, CREATE_NO_WINDOW,
env, env,
wdir, wdir,
&si, &si,
...@@ -272,11 +322,6 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, ...@@ -272,11 +322,6 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray,
procHandle = (jint ) pi.hProcess; procHandle = (jint ) pi.hProcess;
// Close the wrong ends (for the parent) of the pipes.
CloseHandle (cldStdInRd);
CloseHandle (cldStdOutWr);
CloseHandle (cldStdErrWr);
_Jv_Free (cmdLine); _Jv_Free (cmdLine);
if (env != NULL) if (env != NULL)
_Jv_Free (env); _Jv_Free (env);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment