OSDN Git Service

* win32.cc: fixed tab, indentation and whitespace
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natWin32Process.cc
1 // natWin32Process.cc - Native side of Win32 process code.
2
3 /* Copyright (C) 2003  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12 #include <platform.h>
13
14 // Conflicts with the definition in "java/lang/reflect/Modifier.h"
15 #undef STRICT
16
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
29 void
30 java::lang::ConcreteProcess::cleanup (void)
31 {
32   if (inputStream != NULL)
33     {
34       inputStream->close ();
35       inputStream = NULL;
36     }
37
38   if (outputStream != NULL)
39     {
40       outputStream->close ();
41       outputStream = NULL;
42     }
43
44   if (errorStream != NULL)
45     {
46       errorStream->close ();
47       errorStream = NULL;
48     }
49 }
50
51 void
52 java::lang::ConcreteProcess::destroy (void)
53 {
54   if (! hasExited ())
55     {
56       // Kill it forcibly and assign an (arbitrary) exit code of 0.
57       TerminateProcess ((HANDLE) procHandle, 0);
58       exitCode = 0;
59
60       cleanup ();
61     }
62 }
63
64 jboolean
65 java::lang::ConcreteProcess::hasExited (void)
66 {
67   DWORD exitStatus;
68
69   if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0)
70     {
71       // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the
72       // child actually exits with this return code, we have a
73       // problem here. See MSDN documentation on GetExitCodeProcess( ).
74
75       if (exitStatus == STILL_ACTIVE)
76         return false;
77       else
78         {
79           cleanup ();
80           exitCode = exitStatus;
81           return true;
82         }
83     }
84   else
85     return true;
86 }
87
88 jint
89 java::lang::ConcreteProcess::waitFor (void)
90 {
91   if (! hasExited ())
92     {
93       DWORD exitStatus = 0UL;
94
95       // FIXME: The wait should be interruptible.
96       WaitForSingleObject ((HANDLE) procHandle, INFINITE);
97
98       GetExitCodeProcess ((HANDLE) procHandle, &exitStatus);
99       exitCode = exitStatus;
100
101       cleanup ();
102     }
103
104   return exitCode;
105 }
106
107 void
108 java::lang::ConcreteProcess::startProcess (jstringArray progarray,
109                                            jstringArray envp,
110                                            java::io::File *dir)
111 {
112   using namespace java::io;
113
114   procHandle = (jint) INVALID_HANDLE_VALUE;
115
116   // Reconstruct the command line.
117   jstring *elts = elements (progarray);
118
119   int cmdLineLen = 0;
120
121   for (int i = 0; i < progarray->length; ++i)
122     cmdLineLen += (_Jv_GetStringUTFLength (elts[i]) + 1);
123
124   char *cmdLine = (char *) _Jv_Malloc (cmdLineLen + 1);
125   char *cmdLineCurPos = cmdLine;
126
127   for (int i = 0; i < progarray->length; ++i)
128     {
129       if (i > 0)
130         *cmdLineCurPos++ = ' ';
131       jsize s = _Jv_GetStringUTFLength (elts[i]);
132       _Jv_GetStringUTFRegion (elts[i], 0, s, cmdLineCurPos);
133       cmdLineCurPos += s;
134     }
135   *cmdLineCurPos = '\0';
136
137   // Get the environment, if any.
138   char *env = NULL;
139   if (envp)
140     {
141       elts = elements (envp);
142
143       int envLen = 0;
144       for (int i = 0; i < envp->length; ++i)
145         envLen += (_Jv_GetStringUTFLength (elts[i]) + 1);
146
147       env = (char *) _Jv_Malloc (envLen + 1);
148
149       int j = 0;
150       for (int i = 0; i < envp->length; ++i)
151         {
152           jsize s = _Jv_GetStringUTFLength (elts[i]);
153           _Jv_GetStringUTFRegion (elts[i], 0, s, (env + j));
154
155           j += s;
156           *(env + j) = '\0';
157           j++;
158         }
159       *(env + j) = '\0';
160     }
161
162   // Get the working directory path, if specified.
163   JV_TEMP_UTF_STRING (wdir, dir ? dir->getPath () : 0);
164
165   errorStream = NULL;
166   inputStream = NULL;
167   outputStream = NULL;
168
169   java::lang::Throwable *exc = NULL;
170
171   try
172     {
173       // We create anonymous pipes to communicate with the child
174       // on each of standard streams.
175
176       HANDLE cldStdInRd, cldStdInWr;
177       HANDLE cldStdOutRd, cldStdOutWr;
178       HANDLE cldStdErrRd, cldStdErrWr;
179
180       SECURITY_ATTRIBUTES sAttrs;
181
182       // Explicitly allow the handles to the pipes to be inherited.
183       sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES);
184       sAttrs.bInheritHandle = 1;
185       sAttrs.lpSecurityDescriptor = NULL;
186
187
188       if (CreatePipe (&cldStdInRd, &cldStdInWr, &sAttrs, 0) == 0)
189         {
190           DWORD dwErrorCode = GetLastError ();
191           throw new IOException (_Jv_WinStrError ("Error creating stdin pipe",
192             dwErrorCode));
193         }
194
195       if (CreatePipe (&cldStdOutRd, &cldStdOutWr, &sAttrs, 0) == 0)
196         {
197           DWORD dwErrorCode = GetLastError ();
198           throw new IOException (_Jv_WinStrError ("Error creating stdout pipe",
199             dwErrorCode));
200         }
201
202       if (CreatePipe (&cldStdErrRd, &cldStdErrWr, &sAttrs, 0) == 0)
203         {
204           DWORD dwErrorCode = GetLastError ();
205           throw new IOException (_Jv_WinStrError ("Error creating stderr pipe",
206             dwErrorCode));
207         }
208
209       outputStream = new FileOutputStream
210                          (new FileDescriptor ((jint) cldStdInWr));
211       inputStream = new FileInputStream
212                         (new FileDescriptor ((jint) cldStdOutRd));
213       errorStream = new FileInputStream
214                         (new FileDescriptor ((jint) cldStdErrRd));
215
216       // Now create the child process.
217       PROCESS_INFORMATION pi;
218       STARTUPINFO si;
219
220       ZeroMemory (&pi, sizeof (PROCESS_INFORMATION));
221
222       ZeroMemory (&si, sizeof (STARTUPINFO));
223       si.cb = sizeof (STARTUPINFO);
224
225       // Explicitly specify the handles to the standard streams.
226       si.dwFlags |= STARTF_USESTDHANDLES;
227
228       si.hStdInput = cldStdInRd;
229       si.hStdOutput = cldStdOutWr;
230       si.hStdError = cldStdErrWr;
231
232       if (CreateProcess (NULL,
233                          cmdLine,
234                          NULL,
235                          NULL,
236                          1,
237                          0,
238                          env,
239                          wdir,
240                          &si,
241                          &pi) == 0)
242         {
243           DWORD dwErrorCode = GetLastError ();
244           throw new IOException (
245             _Jv_WinStrError ("Error creating child process", dwErrorCode));
246         }
247
248       procHandle = (jint ) pi.hProcess;
249
250       // Close the wrong ends (for the parent) of the pipes.
251       CloseHandle (cldStdInRd);
252       CloseHandle (cldStdOutWr);
253       CloseHandle (cldStdErrWr);
254
255       _Jv_Free (cmdLine);
256       if (env != NULL)
257         _Jv_Free (env);
258     }
259   catch (java::lang::Throwable *thrown)
260     {
261       cleanup ();
262       exc = thrown;
263     }
264
265   if (exc != NULL)
266     throw exc;
267 }