1 // natWin32Process.cc - Native side of Win32 process code.
3 /* Copyright (C) 2003, 2006, 2007 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
14 // Conflicts with the definition in "java/lang/reflect/Modifier.h"
17 #include <java/lang/Win32Process.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 <java/lang/Win32Process$EOFInputStream.h>
29 #include <gnu/java/nio/channels/FileChannelImpl.h>
31 using gnu::java::nio::channels::FileChannelImpl
;
34 java::lang::Win32Process::cleanup (void)
37 // We used to close the input, output and
38 // error streams here, but we can't do that
39 // because the caller also has the right
40 // to close these and FileInputStream and FileOutputStream
41 // scream if you attempt to close() them twice. Presently,
42 // we use _Jv_platform_close_on_exec, which is similar
43 // to the POSIX approach.
45 // What I wanted to do is have private nested
46 // classes in Win32Process which extend FileInputStream
47 // and FileOutputStream, respectively, but override
48 // close() to permit multiple calls to close(). This
49 // led to class header and platform configury issues
50 // that I didn't feel like dealing with. However,
51 // this approach could conceivably be a good multiplatform
52 // one since delaying the pipe close until process
53 // termination could be wasteful if many child processes
54 // are spawned within the parent process' lifetime.
61 CloseHandle((HANDLE
) procHandle
);
62 procHandle
= (jint
) INVALID_HANDLE_VALUE
;
67 java::lang::Win32Process::destroy (void)
71 // Kill it forcibly and assign an (arbitrary) exit code of 0.
72 TerminateProcess ((HANDLE
) procHandle
, 0);
80 java::lang::Win32Process::hasExited (void)
84 if (GetExitCodeProcess ((HANDLE
) procHandle
, &exitStatus
) != 0)
86 // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the
87 // child actually exits with this return code, we have a
88 // problem here. See MSDN documentation on GetExitCodeProcess( ).
90 if (exitStatus
== STILL_ACTIVE
)
95 exitCode
= exitStatus
;
104 java::lang::Win32Process::waitFor (void)
108 DWORD exitStatus
= 0UL;
110 // Set up our waitable objects array
111 // - 0: the handle to the process we just launched
112 // - 1: our thread's interrupt event
114 arh
[0] = (HANDLE
) procHandle
;
115 arh
[1] = _Jv_Win32GetInterruptEvent ();
116 DWORD rval
= WaitForMultipleObjects (2, arh
, 0, INFINITE
);
118 // Use the returned value from WaitForMultipleObjects
119 // instead of our thread's interrupt_flag to test for
120 // thread interruption. See the comment for
121 // _Jv_Win32GetInterruptEvent().
122 bool bInterrupted
= rval
== (WAIT_OBJECT_0
+ 1);
126 // Querying this forces a reset our thread's interrupt flag.
127 Thread::interrupted();
130 throw new InterruptedException ();
133 GetExitCodeProcess ((HANDLE
) procHandle
, &exitStatus
);
134 exitCode
= exitStatus
;
143 // Helper class for creating and managing the pipes
144 // used for I/O redirection for child processes.
145 class ChildProcessPipe
148 // Indicates from the child process' point of view
149 // whether the pipe is for reading or writing.
150 enum EType
{INPUT
, OUTPUT
, DUMMY
};
152 ChildProcessPipe(EType eType
);
155 // Returns a pipe handle suitable for use by the parent process
156 HANDLE
getParentHandle();
158 // Returns a pipe handle suitable for use by the child process.
159 HANDLE
getChildHandle();
163 HANDLE m_hRead
, m_hWrite
;
166 ChildProcessPipe::ChildProcessPipe(EType eType
):
167 m_eType(eType
), m_hRead(0), m_hWrite(0)
172 SECURITY_ATTRIBUTES sAttrs
;
174 // Explicitly allow the handles to the pipes to be inherited.
175 sAttrs
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
176 sAttrs
.bInheritHandle
= 1;
177 sAttrs
.lpSecurityDescriptor
= NULL
;
179 if (CreatePipe (&m_hRead
, &m_hWrite
, &sAttrs
, 0) == 0)
181 DWORD dwErrorCode
= GetLastError ();
182 throw new java::io::IOException (
183 _Jv_WinStrError (_T("Error creating pipe"), dwErrorCode
));
186 // If this is the read end of the child, we need
187 // to make the parent write end non-inheritable. Similarly,
188 // if this is the write end of the child, we need to make
189 // the parent read end non-inheritable. If we didn't
190 // do this, the child would inherit these ends and we wouldn't
191 // be able to close them from our end. For full details,
192 // do a Google search on "Q190351".
193 HANDLE
& rhStd
= m_eType
==INPUT
? m_hWrite
: m_hRead
;
194 _Jv_platform_close_on_exec (rhStd
);
197 ChildProcessPipe::~ChildProcessPipe()
199 // Close the parent end of the pipe. This
200 // destructor is called after the child process
202 if (m_eType
!= DUMMY
)
203 CloseHandle(getChildHandle());
206 HANDLE
ChildProcessPipe::getParentHandle()
208 return m_eType
==INPUT
? m_hWrite
: m_hRead
;
211 HANDLE
ChildProcessPipe::getChildHandle()
213 return m_eType
==INPUT
? m_hRead
: m_hWrite
;
217 java::lang::Win32Process::startProcess (jstringArray progarray
,
222 using namespace java::io
;
224 procHandle
= (jint
) INVALID_HANDLE_VALUE
;
226 // Reconstruct the command line.
227 jstring
*elts
= elements (progarray
);
231 for (int i
= 0; i
< progarray
->length
; ++i
)
232 cmdLineLen
+= (elts
[i
]->length() + 1);
234 LPTSTR cmdLine
= (LPTSTR
) _Jv_Malloc ((cmdLineLen
+ 1) * sizeof(TCHAR
));
235 LPTSTR cmdLineCurPos
= cmdLine
;
237 for (int i
= 0; i
< progarray
->length
; ++i
)
240 *cmdLineCurPos
++ = _T(' ');
242 jint len
= elts
[i
]->length();
243 JV_TEMP_STRING_WIN32(thiselt
, elts
[i
]);
244 _tcscpy(cmdLineCurPos
, thiselt
);
245 cmdLineCurPos
+= len
;
247 *cmdLineCurPos
= _T('\0');
249 // Get the environment, if any.
253 elts
= elements (envp
);
256 for (int i
= 0; i
< envp
->length
; ++i
)
257 envLen
+= (elts
[i
]->length() + 1);
259 env
= (LPTSTR
) _Jv_Malloc ((envLen
+ 1) * sizeof(TCHAR
));
262 for (int i
= 0; i
< envp
->length
; ++i
)
264 jint len
= elts
[i
]->length();
266 JV_TEMP_STRING_WIN32(thiselt
, elts
[i
]);
267 _tcscpy(env
+ j
, thiselt
);
271 // Skip past the null terminator that _tcscpy just inserted.
274 *(env
+ j
) = _T('\0');
277 // Get the working directory path, if specified.
278 JV_TEMP_STRING_WIN32 (wdir
, dir
? dir
->getPath () : 0);
284 java::lang::Throwable
*exc
= NULL
;
288 // We create anonymous pipes to communicate with the child
289 // on each of standard streams.
290 ChildProcessPipe
aChildStdIn(ChildProcessPipe::INPUT
);
291 ChildProcessPipe
aChildStdOut(ChildProcessPipe::OUTPUT
);
292 ChildProcessPipe
aChildStdErr(redirect
? ChildProcessPipe::DUMMY
293 : ChildProcessPipe::OUTPUT
);
295 outputStream
= new FileOutputStream (new FileChannelImpl (
296 (jint
) aChildStdIn
.getParentHandle (),
297 FileChannelImpl::WRITE
));
298 inputStream
= new FileInputStream (new FileChannelImpl (
299 (jint
) aChildStdOut
.getParentHandle (),
300 FileChannelImpl::READ
));
302 errorStream
= Win32Process$
EOFInputStream::instance
;
304 errorStream
= new FileInputStream (new FileChannelImpl (
305 (jint
) aChildStdErr
.getParentHandle (),
306 FileChannelImpl::READ
));
308 // Now create the child process.
309 PROCESS_INFORMATION pi
;
312 ZeroMemory (&pi
, sizeof (PROCESS_INFORMATION
));
314 ZeroMemory (&si
, sizeof (STARTUPINFO
));
315 si
.cb
= sizeof (STARTUPINFO
);
317 // Explicitly specify the handles to the standard streams.
318 si
.dwFlags
|= STARTF_USESTDHANDLES
;
320 si
.hStdInput
= aChildStdIn
.getChildHandle();
321 si
.hStdOutput
= aChildStdOut
.getChildHandle();
322 si
.hStdError
= redirect
? aChildStdOut
.getChildHandle()
323 : aChildStdErr
.getChildHandle();
325 // Spawn the process. CREATE_NO_WINDOW only applies when
326 // starting a console application; it suppresses the
327 // creation of a console window. This flag is ignored on
330 if (CreateProcess (NULL
,
335 CREATE_NO_WINDOW
| CREATE_UNICODE_ENVIRONMENT
,
341 DWORD dwErrorCode
= GetLastError ();
342 throw new IOException (
343 _Jv_WinStrError (_T("Error creating child process"), dwErrorCode
));
346 procHandle
= (jint
) pi
.hProcess
;
352 catch (java::lang::Throwable
*thrown
)