svn merge -r108665:108708 svn+ssh://gcc.gnu.org/svn/gcc/trunk
[official-gcc.git] / libjava / java / lang / natWin32Process.cc
blob3c1a4f02c8bbdec03bff02caa85d51083410e372
1 // natWin32Process.cc - Native side of Win32 process code.
3 /* Copyright (C) 2003 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 #include <config.h>
12 #include <platform.h>
14 // Conflicts with the definition in "java/lang/reflect/Modifier.h"
15 #undef STRICT
17 #include <java/lang/ConcreteProcess.h>
18 #include <java/lang/IllegalThreadStateException.h>
19 #include <java/lang/InterruptedException.h>
20 #include <java/lang/NullPointerException.h>
21 #include <java/lang/Thread.h>
22 #include <java/io/File.h>
23 #include <java/io/FileDescriptor.h>
24 #include <java/io/FileInputStream.h>
25 #include <java/io/FileOutputStream.h>
26 #include <java/io/IOException.h>
27 #include <java/lang/OutOfMemoryError.h>
28 #include <gnu/java/nio/channels/FileChannelImpl.h>
30 using gnu::java::nio::channels::FileChannelImpl;
32 void
33 java::lang::ConcreteProcess::cleanup (void)
35 // FIXME:
36 // We used to close the input, output and
37 // error streams here, but we can't do that
38 // because the caller also has the right
39 // to close these and FileInputStream and FileOutputStream
40 // scream if you attempt to close() them twice. Presently,
41 // we use _Jv_platform_close_on_exec, which is similar
42 // to the POSIX approach.
44 // What I wanted to do is have private nested
45 // classes in ConcreteProcess which extend FileInputStream
46 // and FileOutputStream, respectively, but override
47 // close() to permit multiple calls to close(). This
48 // led to class header and platform configury issues
49 // that I didn't feel like dealing with. However,
50 // this approach could conceivably be a good multiplatform
51 // one since delaying the pipe close until process
52 // termination could be wasteful if many child processes
53 // are spawned within the parent process' lifetime.
54 inputStream = NULL;
55 outputStream = NULL;
56 errorStream = NULL;
58 if (procHandle)
60 CloseHandle((HANDLE) procHandle);
61 procHandle = (jint) INVALID_HANDLE_VALUE;
65 void
66 java::lang::ConcreteProcess::destroy (void)
68 if (! hasExited ())
70 // Kill it forcibly and assign an (arbitrary) exit code of 0.
71 TerminateProcess ((HANDLE) procHandle, 0);
72 exitCode = 0;
74 cleanup ();
78 jboolean
79 java::lang::ConcreteProcess::hasExited (void)
81 DWORD exitStatus;
83 if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0)
85 // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the
86 // child actually exits with this return code, we have a
87 // problem here. See MSDN documentation on GetExitCodeProcess( ).
89 if (exitStatus == STILL_ACTIVE)
90 return false;
91 else
93 cleanup ();
94 exitCode = exitStatus;
95 return true;
98 else
99 return true;
102 jint
103 java::lang::ConcreteProcess::waitFor (void)
105 if (! hasExited ())
107 DWORD exitStatus = 0UL;
109 // Set up our waitable objects array
110 // - 0: the handle to the process we just launched
111 // - 1: our thread's interrupt event
112 HANDLE arh[2];
113 arh[0] = (HANDLE) procHandle;
114 arh[1] = _Jv_Win32GetInterruptEvent ();
115 DWORD rval = WaitForMultipleObjects (2, arh, 0, INFINITE);
117 // Use the returned value from WaitForMultipleObjects
118 // instead of our thread's interrupt_flag to test for
119 // thread interruption. See the comment for
120 // _Jv_Win32GetInterruptEvent().
121 bool bInterrupted = rval == (WAIT_OBJECT_0 + 1);
123 if (bInterrupted)
125 // Querying this forces a reset our thread's interrupt flag.
126 Thread::interrupted();
128 cleanup ();
129 throw new InterruptedException ();
132 GetExitCodeProcess ((HANDLE) procHandle, &exitStatus);
133 exitCode = exitStatus;
135 cleanup ();
138 return exitCode;
142 // Helper class for creating and managing the pipes
143 // used for I/O redirection for child processes.
144 class ChildProcessPipe
146 public:
147 // Indicates from the child process' point of view
148 // whether the pipe is for reading or writing.
149 enum EType {INPUT, OUTPUT};
151 ChildProcessPipe(EType eType);
152 ~ChildProcessPipe();
154 // Returns a pipe handle suitable for use by the parent process
155 HANDLE getParentHandle();
157 // Returns a pipe handle suitable for use by the child process.
158 HANDLE getChildHandle();
160 private:
161 EType m_eType;
162 HANDLE m_hRead, m_hWrite;
165 ChildProcessPipe::ChildProcessPipe(EType eType):
166 m_eType(eType)
168 SECURITY_ATTRIBUTES sAttrs;
170 // Explicitly allow the handles to the pipes to be inherited.
171 sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES);
172 sAttrs.bInheritHandle = 1;
173 sAttrs.lpSecurityDescriptor = NULL;
175 if (CreatePipe (&m_hRead, &m_hWrite, &sAttrs, 0) == 0)
177 DWORD dwErrorCode = GetLastError ();
178 throw new java::io::IOException (
179 _Jv_WinStrError (_T("Error creating pipe"), dwErrorCode));
182 // If this is the read end of the child, we need
183 // to make the parent write end non-inheritable. Similarly,
184 // if this is the write end of the child, we need to make
185 // the parent read end non-inheritable. If we didn't
186 // do this, the child would inherit these ends and we wouldn't
187 // be able to close them from our end. For full details,
188 // do a Google search on "Q190351".
189 HANDLE& rhStd = m_eType==INPUT ? m_hWrite : m_hRead;
190 _Jv_platform_close_on_exec (rhStd);
193 ChildProcessPipe::~ChildProcessPipe()
195 // Close the parent end of the pipe. This
196 // destructor is called after the child process
197 // has been spawned.
198 CloseHandle(getChildHandle());
201 HANDLE ChildProcessPipe::getParentHandle()
203 return m_eType==INPUT ? m_hWrite : m_hRead;
206 HANDLE ChildProcessPipe::getChildHandle()
208 return m_eType==INPUT ? m_hRead : m_hWrite;
211 void
212 java::lang::ConcreteProcess::startProcess (jstringArray progarray,
213 jstringArray envp,
214 java::io::File *dir)
216 using namespace java::io;
218 procHandle = (jint) INVALID_HANDLE_VALUE;
220 // Reconstruct the command line.
221 jstring *elts = elements (progarray);
223 int cmdLineLen = 0;
225 for (int i = 0; i < progarray->length; ++i)
226 cmdLineLen += (elts[i]->length() + 1);
228 LPTSTR cmdLine = (LPTSTR) _Jv_Malloc ((cmdLineLen + 1) * sizeof(TCHAR));
229 LPTSTR cmdLineCurPos = cmdLine;
231 for (int i = 0; i < progarray->length; ++i)
233 if (i > 0)
234 *cmdLineCurPos++ = _T(' ');
236 jint len = elts[i]->length();
237 JV_TEMP_STRING_WIN32(thiselt, elts[i]);
238 _tcscpy(cmdLineCurPos, thiselt);
239 cmdLineCurPos += len;
241 *cmdLineCurPos = _T('\0');
243 // Get the environment, if any.
244 LPTSTR env = NULL;
245 if (envp)
247 elts = elements (envp);
249 int envLen = 0;
250 for (int i = 0; i < envp->length; ++i)
251 envLen += (elts[i]->length() + 1);
253 env = (LPTSTR) _Jv_Malloc ((envLen + 1) * sizeof(TCHAR));
255 int j = 0;
256 for (int i = 0; i < envp->length; ++i)
258 jint len = elts[i]->length();
260 JV_TEMP_STRING_WIN32(thiselt, elts[i]);
261 _tcscpy(env + j, thiselt);
263 j += len;
265 // Skip past the null terminator that _tcscpy just inserted.
266 j++;
268 *(env + j) = _T('\0');
271 // Get the working directory path, if specified.
272 JV_TEMP_STRING_WIN32 (wdir, dir ? dir->getPath () : 0);
274 errorStream = NULL;
275 inputStream = NULL;
276 outputStream = NULL;
278 java::lang::Throwable *exc = NULL;
282 // We create anonymous pipes to communicate with the child
283 // on each of standard streams.
284 ChildProcessPipe aChildStdIn(ChildProcessPipe::INPUT);
285 ChildProcessPipe aChildStdOut(ChildProcessPipe::OUTPUT);
286 ChildProcessPipe aChildStdErr(ChildProcessPipe::OUTPUT);
288 outputStream = new FileOutputStream (new FileChannelImpl (
289 (jint) aChildStdIn.getParentHandle (),
290 FileChannelImpl::WRITE));
291 inputStream = new FileInputStream (new FileChannelImpl (
292 (jint) aChildStdOut.getParentHandle (),
293 FileChannelImpl::READ));
294 errorStream = new FileInputStream (new FileChannelImpl (
295 (jint) aChildStdErr.getParentHandle (),
296 FileChannelImpl::READ));
298 // Now create the child process.
299 PROCESS_INFORMATION pi;
300 STARTUPINFO si;
302 ZeroMemory (&pi, sizeof (PROCESS_INFORMATION));
304 ZeroMemory (&si, sizeof (STARTUPINFO));
305 si.cb = sizeof (STARTUPINFO);
307 // Explicitly specify the handles to the standard streams.
308 si.dwFlags |= STARTF_USESTDHANDLES;
310 si.hStdInput = aChildStdIn.getChildHandle();
311 si.hStdOutput = aChildStdOut.getChildHandle();
312 si.hStdError = aChildStdErr.getChildHandle();
314 // Spawn the process. CREATE_NO_WINDOW only applies when
315 // starting a console application; it suppresses the
316 // creation of a console window. This flag is ignored on
317 // Win9X.
319 if (CreateProcess (NULL,
320 cmdLine,
321 NULL,
322 NULL,
324 CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
325 env,
326 wdir,
327 &si,
328 &pi) == 0)
330 DWORD dwErrorCode = GetLastError ();
331 throw new IOException (
332 _Jv_WinStrError (_T("Error creating child process"), dwErrorCode));
335 procHandle = (jint ) pi.hProcess;
337 _Jv_Free (cmdLine);
338 if (env != NULL)
339 _Jv_Free (env);
341 catch (java::lang::Throwable *thrown)
343 cleanup ();
344 exc = thrown;
347 if (exc != NULL)
348 throw exc;