gcc/libjava/java/lang/natWin32Process.cc
Mohan Embar 83c02e38a3 configure.in: Added new MinGW-specific configure flag --with-win32-nlsapi.
* configure.in: Added new MinGW-specific configure flag
	--with-win32-nlsapi.
	Added new AC_DEFINE MINGW_LIBGCJ_UNICODE.
	Add -lunicows to MinGW SYSTEMSPEC if --with-win32-nlsapi
	is set to unicows.
	* configure: Rebuilt.
	* include/config.h.in: Rebuilt.
	* win32.cc (_Jv_Win32NewString): Implemented.
	(nativeToUnicode): New helper function defined only for
	non-UNICODE builds.
	(unicodeToNative): Likewise.
	(_Jv_Win32TempString): Implemented.
	(lots): Refactored using tchar.h macros.
	(WSAEventWrapper): Use _Jv_Win32NewString.
	(_Jv_platform_initialize): Use GetModuleFileNameA instead
	of GetModuleFileName.
	(_Jv_platform_initProperties): Use _Jv_Win32NewString.
	Use temporary stack buffer instead of a heap buffer.
	* include/win32.h
	Added defines for UNICODE and _UNICODE if MINGW_LIBGCJ_UNICODE is
	defined; added tchar.h include.
	(_Jv_Win32TempString): Declared new helper class.
	(JV_TEMP_STRING_WIN32): New helper macro.
	(_Jv_Win32NewString): Declared new helper method.
	* java/io/natFileDescriptorWin32.cc (open): Use
	JV_TEMP_STRING_WIN32 instead of JV_TEMP_UTF_STRING.
	(write): Reformatted slightly.
	* java/io/natFileWin32.cc (lots): Use tchar.h macros;
	use JV_TEMP_STRING_WIN32 instead of JV_TEMP_UTF_STRING.
	(getCanonicalPath): Use _Jv_Win32NewString instead of
	JvNewStringUTF.
	(performList): Likewise.
	* java/lang/natWin32Process.cc (ChildProcessPipe):
	Use tchar.h macros.
	(startProcess): Use tchar.h macros, JV_TEMP_STRING_WIN32,
	and UNICODE environment flag for CreateProcess.
	* java/net/natNetworkInterfaceWin32.cc
	(winsock2GetRealNetworkInterfaces): Use tchar.h macros and
	_Jv_Win32NewString.

From-SVN: r74201
2003-12-02 22:26:50 +00:00

344 lines
9.5 KiB
C++

// 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 <platform.h>
// Conflicts with the definition in "java/lang/reflect/Modifier.h"
#undef STRICT
#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)
{
// FIXME:
// We used to close the input, output and
// error streams here, but we can't do that
// because the caller also has the right
// to close these and FileInputStream and FileOutputStream
// scream if you attempt to close() them twice. Presently,
// we use _Jv_platform_close_on_exec, which is similar
// to the POSIX approach.
//
// What I wanted to do is have private nested
// classes in ConcreteProcess which extend FileInputStream
// and FileOutputStream, respectively, but override
// close() to permit multiple calls to close(). This
// led to class header and platform configury issues
// that I didn't feel like dealing with. However,
// 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)
{
CloseHandle((HANDLE) procHandle);
procHandle = (jint) INVALID_HANDLE_VALUE;
}
}
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;
// Set up our waitable objects array
// - 0: the handle to the process we just launched
// - 1: our thread's interrupt event
HANDLE arh[2];
arh[0] = (HANDLE) procHandle;
arh[1] = _Jv_Win32GetInterruptEvent ();
DWORD rval = WaitForMultipleObjects (2, arh, 0, INFINITE);
// Use the returned value from WaitForMultipleObjects
// instead of our thread's interrupt_flag to test for
// thread interruption. See the comment for
// _Jv_Win32GetInterruptEvent().
bool bInterrupted = rval == (WAIT_OBJECT_0 + 1);
if (bInterrupted)
{
// Querying this forces a reset our thread's interrupt flag.
Thread::interrupted();
cleanup ();
throw new InterruptedException ();
}
GetExitCodeProcess ((HANDLE) procHandle, &exitStatus);
exitCode = exitStatus;
cleanup ();
}
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 (_T("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
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 += (elts[i]->length() + 1);
LPTSTR cmdLine = (LPTSTR) _Jv_Malloc ((cmdLineLen + 1) * sizeof(TCHAR));
LPTSTR cmdLineCurPos = cmdLine;
for (int i = 0; i < progarray->length; ++i)
{
if (i > 0)
*cmdLineCurPos++ = _T(' ');
jint len = elts[i]->length();
JV_TEMP_STRING_WIN32(thiselt, elts[i]);
_tcscpy(cmdLineCurPos, thiselt);
cmdLineCurPos += len;
}
*cmdLineCurPos = _T('\0');
// Get the environment, if any.
LPTSTR env = NULL;
if (envp)
{
elts = elements (envp);
int envLen = 0;
for (int i = 0; i < envp->length; ++i)
envLen += (elts[i]->length() + 1);
env = (LPTSTR) _Jv_Malloc ((envLen + 1) * sizeof(TCHAR));
int j = 0;
for (int i = 0; i < envp->length; ++i)
{
jint len = elts[i]->length();
JV_TEMP_STRING_WIN32(thiselt, elts[i]);
_tcscpy(env + j, thiselt);
j += len;
// Skip past the null terminator that _tcscpy just inserted.
j++;
}
*(env + j) = _T('\0');
}
// Get the working directory path, if specified.
JV_TEMP_STRING_WIN32 (wdir, dir ? dir->getPath () : 0);
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.
ChildProcessPipe aChildStdIn(ChildProcessPipe::INPUT);
ChildProcessPipe aChildStdOut(ChildProcessPipe::OUTPUT);
ChildProcessPipe aChildStdErr(ChildProcessPipe::OUTPUT);
outputStream = new FileOutputStream (new FileDescriptor (
(jint) aChildStdIn.getParentHandle ()));
inputStream = new FileInputStream (new FileDescriptor (
(jint) aChildStdOut.getParentHandle ()));
errorStream = new FileInputStream (new FileDescriptor (
(jint) aChildStdErr.getParentHandle ()));
// 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 = aChildStdIn.getChildHandle();
si.hStdOutput = aChildStdOut.getChildHandle();
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,
cmdLine,
NULL,
NULL,
1,
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
env,
wdir,
&si,
&pi) == 0)
{
DWORD dwErrorCode = GetLastError ();
throw new IOException (
_Jv_WinStrError (_T("Error creating child process"), dwErrorCode));
}
procHandle = (jint ) pi.hProcess;
_Jv_Free (cmdLine);
if (env != NULL)
_Jv_Free (env);
}
catch (java::lang::Throwable *thrown)
{
cleanup ();
exc = thrown;
}
if (exc != NULL)
throw exc;
}