natWin32Process.cc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // natWin32Process.cc - Native side of Win32 process code.
  2. /* Copyright (C) 2003, 2006, 2007 Free Software Foundation
  3. This file is part of libgcj.
  4. This software is copyrighted work licensed under the terms of the
  5. Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
  6. details. */
  7. #include <config.h>
  8. #include <platform.h>
  9. // Conflicts with the definition in "java/lang/reflect/Modifier.h"
  10. #undef STRICT
  11. #include <java/lang/Win32Process.h>
  12. #include <java/lang/IllegalThreadStateException.h>
  13. #include <java/lang/InterruptedException.h>
  14. #include <java/lang/NullPointerException.h>
  15. #include <java/lang/Thread.h>
  16. #include <java/io/File.h>
  17. #include <java/io/FileDescriptor.h>
  18. #include <java/io/FileInputStream.h>
  19. #include <java/io/FileOutputStream.h>
  20. #include <java/io/IOException.h>
  21. #include <java/lang/OutOfMemoryError.h>
  22. #include <java/lang/Win32Process$EOFInputStream.h>
  23. #include <gnu/java/nio/channels/FileChannelImpl.h>
  24. using gnu::java::nio::channels::FileChannelImpl;
  25. void
  26. java::lang::Win32Process::cleanup (void)
  27. {
  28. // FIXME:
  29. // We used to close the input, output and
  30. // error streams here, but we can't do that
  31. // because the caller also has the right
  32. // to close these and FileInputStream and FileOutputStream
  33. // scream if you attempt to close() them twice. Presently,
  34. // we use _Jv_platform_close_on_exec, which is similar
  35. // to the POSIX approach.
  36. //
  37. // What I wanted to do is have private nested
  38. // classes in Win32Process which extend FileInputStream
  39. // and FileOutputStream, respectively, but override
  40. // close() to permit multiple calls to close(). This
  41. // led to class header and platform configury issues
  42. // that I didn't feel like dealing with. However,
  43. // this approach could conceivably be a good multiplatform
  44. // one since delaying the pipe close until process
  45. // termination could be wasteful if many child processes
  46. // are spawned within the parent process' lifetime.
  47. inputStream = NULL;
  48. outputStream = NULL;
  49. errorStream = NULL;
  50. if (procHandle)
  51. {
  52. CloseHandle((HANDLE) procHandle);
  53. procHandle = (jint) INVALID_HANDLE_VALUE;
  54. }
  55. }
  56. void
  57. java::lang::Win32Process::destroy (void)
  58. {
  59. if (! hasExited ())
  60. {
  61. // Kill it forcibly and assign an (arbitrary) exit code of 0.
  62. TerminateProcess ((HANDLE) procHandle, 0);
  63. exitCode = 0;
  64. cleanup ();
  65. }
  66. }
  67. jboolean
  68. java::lang::Win32Process::hasExited (void)
  69. {
  70. DWORD exitStatus;
  71. if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0)
  72. {
  73. // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the
  74. // child actually exits with this return code, we have a
  75. // problem here. See MSDN documentation on GetExitCodeProcess( ).
  76. if (exitStatus == STILL_ACTIVE)
  77. return false;
  78. else
  79. {
  80. cleanup ();
  81. exitCode = exitStatus;
  82. return true;
  83. }
  84. }
  85. else
  86. return true;
  87. }
  88. jint
  89. java::lang::Win32Process::waitFor (void)
  90. {
  91. if (! hasExited ())
  92. {
  93. DWORD exitStatus = 0UL;
  94. // Set up our waitable objects array
  95. // - 0: the handle to the process we just launched
  96. // - 1: our thread's interrupt event
  97. HANDLE arh[2];
  98. arh[0] = (HANDLE) procHandle;
  99. arh[1] = _Jv_Win32GetInterruptEvent ();
  100. DWORD rval = WaitForMultipleObjects (2, arh, 0, INFINITE);
  101. // Use the returned value from WaitForMultipleObjects
  102. // instead of our thread's interrupt_flag to test for
  103. // thread interruption. See the comment for
  104. // _Jv_Win32GetInterruptEvent().
  105. bool bInterrupted = rval == (WAIT_OBJECT_0 + 1);
  106. if (bInterrupted)
  107. {
  108. // Querying this forces a reset our thread's interrupt flag.
  109. Thread::interrupted();
  110. cleanup ();
  111. throw new InterruptedException ();
  112. }
  113. GetExitCodeProcess ((HANDLE) procHandle, &exitStatus);
  114. exitCode = exitStatus;
  115. cleanup ();
  116. }
  117. return exitCode;
  118. }
  119. // Helper class for creating and managing the pipes
  120. // used for I/O redirection for child processes.
  121. class ChildProcessPipe
  122. {
  123. public:
  124. // Indicates from the child process' point of view
  125. // whether the pipe is for reading or writing.
  126. enum EType {INPUT, OUTPUT, DUMMY};
  127. ChildProcessPipe(EType eType);
  128. ~ChildProcessPipe();
  129. // Returns a pipe handle suitable for use by the parent process
  130. HANDLE getParentHandle();
  131. // Returns a pipe handle suitable for use by the child process.
  132. HANDLE getChildHandle();
  133. private:
  134. EType m_eType;
  135. HANDLE m_hRead, m_hWrite;
  136. };
  137. ChildProcessPipe::ChildProcessPipe(EType eType):
  138. m_eType(eType), m_hRead(0), m_hWrite(0)
  139. {
  140. if (eType == DUMMY)
  141. return;
  142. SECURITY_ATTRIBUTES sAttrs;
  143. // Explicitly allow the handles to the pipes to be inherited.
  144. sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES);
  145. sAttrs.bInheritHandle = 1;
  146. sAttrs.lpSecurityDescriptor = NULL;
  147. if (CreatePipe (&m_hRead, &m_hWrite, &sAttrs, 0) == 0)
  148. {
  149. DWORD dwErrorCode = GetLastError ();
  150. throw new java::io::IOException (
  151. _Jv_WinStrError (_T("Error creating pipe"), dwErrorCode));
  152. }
  153. // If this is the read end of the child, we need
  154. // to make the parent write end non-inheritable. Similarly,
  155. // if this is the write end of the child, we need to make
  156. // the parent read end non-inheritable. If we didn't
  157. // do this, the child would inherit these ends and we wouldn't
  158. // be able to close them from our end. For full details,
  159. // do a Google search on "Q190351".
  160. HANDLE& rhStd = m_eType==INPUT ? m_hWrite : m_hRead;
  161. _Jv_platform_close_on_exec (rhStd);
  162. }
  163. ChildProcessPipe::~ChildProcessPipe()
  164. {
  165. // Close the parent end of the pipe. This
  166. // destructor is called after the child process
  167. // has been spawned.
  168. if (m_eType != DUMMY)
  169. CloseHandle(getChildHandle());
  170. }
  171. HANDLE ChildProcessPipe::getParentHandle()
  172. {
  173. return m_eType==INPUT ? m_hWrite : m_hRead;
  174. }
  175. HANDLE ChildProcessPipe::getChildHandle()
  176. {
  177. return m_eType==INPUT ? m_hRead : m_hWrite;
  178. }
  179. void
  180. java::lang::Win32Process::startProcess (jstringArray progarray,
  181. jstringArray envp,
  182. java::io::File *dir,
  183. jboolean redirect)
  184. {
  185. using namespace java::io;
  186. procHandle = (jint) INVALID_HANDLE_VALUE;
  187. // Reconstruct the command line.
  188. jstring *elts = elements (progarray);
  189. int cmdLineLen = 0;
  190. for (int i = 0; i < progarray->length; ++i)
  191. cmdLineLen += (elts[i]->length() + 1);
  192. LPTSTR cmdLine = (LPTSTR) _Jv_Malloc ((cmdLineLen + 1) * sizeof(TCHAR));
  193. LPTSTR cmdLineCurPos = cmdLine;
  194. for (int i = 0; i < progarray->length; ++i)
  195. {
  196. if (i > 0)
  197. *cmdLineCurPos++ = _T(' ');
  198. jint len = elts[i]->length();
  199. JV_TEMP_STRING_WIN32(thiselt, elts[i]);
  200. _tcscpy(cmdLineCurPos, thiselt);
  201. cmdLineCurPos += len;
  202. }
  203. *cmdLineCurPos = _T('\0');
  204. // Get the environment, if any.
  205. LPTSTR env = NULL;
  206. if (envp)
  207. {
  208. elts = elements (envp);
  209. int envLen = 0;
  210. for (int i = 0; i < envp->length; ++i)
  211. envLen += (elts[i]->length() + 1);
  212. env = (LPTSTR) _Jv_Malloc ((envLen + 1) * sizeof(TCHAR));
  213. int j = 0;
  214. for (int i = 0; i < envp->length; ++i)
  215. {
  216. jint len = elts[i]->length();
  217. JV_TEMP_STRING_WIN32(thiselt, elts[i]);
  218. _tcscpy(env + j, thiselt);
  219. j += len;
  220. // Skip past the null terminator that _tcscpy just inserted.
  221. j++;
  222. }
  223. *(env + j) = _T('\0');
  224. }
  225. // Get the working directory path, if specified.
  226. JV_TEMP_STRING_WIN32 (wdir, dir ? dir->getPath () : 0);
  227. errorStream = NULL;
  228. inputStream = NULL;
  229. outputStream = NULL;
  230. java::lang::Throwable *exc = NULL;
  231. try
  232. {
  233. // We create anonymous pipes to communicate with the child
  234. // on each of standard streams.
  235. ChildProcessPipe aChildStdIn(ChildProcessPipe::INPUT);
  236. ChildProcessPipe aChildStdOut(ChildProcessPipe::OUTPUT);
  237. ChildProcessPipe aChildStdErr(redirect ? ChildProcessPipe::DUMMY
  238. : ChildProcessPipe::OUTPUT);
  239. outputStream = new FileOutputStream (new FileChannelImpl (
  240. (jint) aChildStdIn.getParentHandle (),
  241. FileChannelImpl::WRITE));
  242. inputStream = new FileInputStream (new FileChannelImpl (
  243. (jint) aChildStdOut.getParentHandle (),
  244. FileChannelImpl::READ));
  245. if (redirect)
  246. errorStream = Win32Process$EOFInputStream::instance;
  247. else
  248. errorStream = new FileInputStream (new FileChannelImpl (
  249. (jint) aChildStdErr.getParentHandle (),
  250. FileChannelImpl::READ));
  251. // Now create the child process.
  252. PROCESS_INFORMATION pi;
  253. STARTUPINFO si;
  254. ZeroMemory (&pi, sizeof (PROCESS_INFORMATION));
  255. ZeroMemory (&si, sizeof (STARTUPINFO));
  256. si.cb = sizeof (STARTUPINFO);
  257. // Explicitly specify the handles to the standard streams.
  258. si.dwFlags |= STARTF_USESTDHANDLES;
  259. si.hStdInput = aChildStdIn.getChildHandle();
  260. si.hStdOutput = aChildStdOut.getChildHandle();
  261. si.hStdError = redirect ? aChildStdOut.getChildHandle()
  262. : aChildStdErr.getChildHandle();
  263. // Spawn the process. CREATE_NO_WINDOW only applies when
  264. // starting a console application; it suppresses the
  265. // creation of a console window. This flag is ignored on
  266. // Win9X.
  267. if (CreateProcess (NULL,
  268. cmdLine,
  269. NULL,
  270. NULL,
  271. 1,
  272. CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
  273. env,
  274. wdir,
  275. &si,
  276. &pi) == 0)
  277. {
  278. DWORD dwErrorCode = GetLastError ();
  279. throw new IOException (
  280. _Jv_WinStrError (_T("Error creating child process"), dwErrorCode));
  281. }
  282. procHandle = (jint ) pi.hProcess;
  283. _Jv_Free (cmdLine);
  284. if (env != NULL)
  285. _Jv_Free (env);
  286. }
  287. catch (java::lang::Throwable *thrown)
  288. {
  289. cleanup ();
  290. exc = thrown;
  291. }
  292. if (exc != NULL)
  293. throw exc;
  294. }