src/windows/native/java/lang/ProcessImpl_md.c

Print this page




  23  * questions.
  24  */
  25 
  26 #include <assert.h>
  27 #include "java_lang_ProcessImpl.h"
  28 
  29 #include "jni.h"
  30 #include "jvm.h"
  31 #include "jni_util.h"
  32 #include "io_util.h"
  33 #include <windows.h>
  34 #include <io.h>
  35 
  36 /* We try to make sure that we can read and write 4095 bytes (the
  37  * fixed limit on Linux) to the pipe on all operating systems without
  38  * deadlock.  Windows 2000 inexplicably appears to need an extra 24
  39  * bytes of slop to avoid deadlock.
  40  */
  41 #define PIPE_SIZE (4096+24)
  42 































  43 static void
  44 win32Error(JNIEnv *env, const char *functionName)
  45 {
  46     static const char * const format = "%s error=%d, %s";
  47     static const char * const fallbackFormat = "%s failed, error=%d";
  48     char buf[256];
  49     char errmsg[sizeof(buf) + 100];
  50     const int errnum = GetLastError();
  51     const int n = JVM_GetLastErrorString(buf, sizeof(buf));
  52     if (n > 0)
  53         sprintf(errmsg, format, functionName, errnum, buf);
  54     else
  55         sprintf(errmsg, fallbackFormat, functionName, errnum);
  56     JNU_ThrowIOException(env, errmsg);













  57 }
  58 
  59 static void
  60 closeSafely(HANDLE handle)
  61 {
  62     if (handle != INVALID_HANDLE_VALUE)
  63         CloseHandle(handle);
  64 }
  65 
  66 JNIEXPORT jlong JNICALL
  67 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
  68                                   jstring cmd,
  69                                   jstring envBlock,
  70                                   jstring dir,
  71                                   jlongArray stdHandles,
  72                                   jboolean redirectErrorStream)
  73 {
  74     HANDLE inRead   = INVALID_HANDLE_VALUE;
  75     HANDLE inWrite  = INVALID_HANDLE_VALUE;
  76     HANDLE outRead  = INVALID_HANDLE_VALUE;


  99         penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
 100         if (penvBlock == NULL) goto Catch;
 101     }
 102     assert(stdHandles != NULL);
 103     handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 104     if (handles == NULL) goto Catch;
 105 
 106     memset(&si, 0, sizeof(si));
 107     si.cb = sizeof(si);
 108     si.dwFlags = STARTF_USESTDHANDLES;
 109 
 110     sa.nLength = sizeof(sa);
 111     sa.lpSecurityDescriptor = 0;
 112     sa.bInheritHandle = TRUE;
 113 
 114     if (handles[0] != (jlong) -1) {
 115         si.hStdInput = (HANDLE) handles[0];
 116         handles[0] = (jlong) -1;
 117     } else {
 118         if (! CreatePipe(&inRead,  &inWrite,  &sa, PIPE_SIZE)) {
 119             win32Error(env, "CreatePipe");
 120             goto Catch;
 121         }
 122         si.hStdInput = inRead;
 123         SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0);
 124         handles[0] = (jlong) inWrite;
 125     }
 126     SetHandleInformation(si.hStdInput,
 127         HANDLE_FLAG_INHERIT,
 128         HANDLE_FLAG_INHERIT);
 129 
 130     if (handles[1] != (jlong) -1) {
 131         si.hStdOutput = (HANDLE) handles[1];
 132         handles[1] = (jlong) -1;
 133     } else {
 134         if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
 135             win32Error(env, "CreatePipe");
 136             goto Catch;
 137         }
 138         si.hStdOutput = outWrite;
 139         SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0);
 140         handles[1] = (jlong) outRead;
 141     }
 142     SetHandleInformation(si.hStdOutput,
 143         HANDLE_FLAG_INHERIT,
 144         HANDLE_FLAG_INHERIT);
 145 
 146     if (redirectErrorStream) {
 147         si.hStdError = si.hStdOutput;
 148         handles[2] = (jlong) -1;
 149     } else if (handles[2] != (jlong) -1) {
 150         si.hStdError = (HANDLE) handles[2];
 151         handles[2] = (jlong) -1;
 152     } else {
 153         if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
 154             win32Error(env, "CreatePipe");
 155             goto Catch;
 156         }
 157         si.hStdError = errWrite;
 158         SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0);
 159         handles[2] = (jlong) errRead;
 160     }
 161     SetHandleInformation(si.hStdError,
 162         HANDLE_FLAG_INHERIT,
 163         HANDLE_FLAG_INHERIT);
 164 
 165     processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 166     ret = CreateProcessW(0,                /* executable name */
 167                          (LPWSTR)pcmd,     /* command line */
 168                          0,                /* process security attribute */
 169                          0,                /* thread security attribute */
 170                          TRUE,             /* inherits system handles */
 171                          processFlag,      /* selected based on exe type */
 172                          (LPVOID)penvBlock,/* environment block */
 173                          (LPCWSTR)pdir,    /* change to the new current directory */
 174                          &si,              /* (in)  startup information */
 175                          &pi);             /* (out) process information */
 176     if (!ret) {
 177         win32Error(env, "CreateProcess");
 178         goto Catch;
 179     }
 180 
 181     CloseHandle(pi.hThread);
 182     ret = (jlong)pi.hProcess;
 183 
 184  Finally:
 185     /* Always clean up the child's side of the pipes */
 186     closeSafely(inRead);
 187     closeSafely(outWrite);
 188     closeSafely(errWrite);
 189 
 190     if (pcmd != NULL)
 191         (*env)->ReleaseStringChars(env, cmd, pcmd);
 192     if (pdir != NULL)
 193         (*env)->ReleaseStringChars(env, dir, pdir);
 194     if (penvBlock != NULL)
 195         (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 196     if (handles != NULL)
 197         (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 198     return ret;
 199 
 200  Catch:
 201     /* Clean up the parent's side of the pipes in case of failure only */
 202     closeSafely(inWrite);
 203     closeSafely(outRead);
 204     closeSafely(errRead);
 205     goto Finally;
 206 }
 207 
 208 JNIEXPORT jint JNICALL
 209 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 210 {
 211     DWORD exit_code;
 212     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 213         win32Error(env, "GetExitCodeProcess");
 214     return exit_code;
 215 }
 216 
 217 JNIEXPORT jint JNICALL
 218 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 219 {
 220     return STILL_ACTIVE;
 221 }
 222 
 223 JNIEXPORT void JNICALL
 224 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 225 {
 226     HANDLE events[2];
 227     events[0] = (HANDLE) handle;
 228     events[1] = JVM_GetThreadInterruptEvent();
 229 
 230     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 231                                FALSE,    /* Wait for ANY event */
 232                                INFINITE)  /* Wait forever */
 233         == WAIT_FAILED)
 234         win32Error(env, "WaitForMultipleObjects");
 235 }
 236 
 237 JNIEXPORT void JNICALL
 238 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
 239                                                        jclass ignored,
 240                                                        jlong handle,
 241                                                        jlong timeout)
 242 {
 243     HANDLE events[2];
 244     DWORD dwTimeout = (DWORD)timeout;
 245     DWORD result;
 246     events[0] = (HANDLE) handle;
 247     events[1] = JVM_GetThreadInterruptEvent();
 248     result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 249                                     FALSE,    /* Wait for ANY event */
 250                                     dwTimeout);  /* Wait for dwTimeout */
 251 
 252     if (result == WAIT_FAILED)
 253         win32Error(env, "WaitForMultipleObjects");
 254 }
 255 
 256 JNIEXPORT void JNICALL
 257 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 258 {
 259     TerminateProcess((HANDLE) handle, 1);
 260 }
 261 
 262 JNIEXPORT jboolean JNICALL
 263 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
 264 {
 265     DWORD dwExitStatus;
 266     GetExitCodeProcess(handle, &dwExitStatus);
 267     return dwExitStatus == STILL_ACTIVE;
 268 }
 269 
 270 JNIEXPORT jboolean JNICALL
 271 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 272 {
 273     return CloseHandle((HANDLE) handle);
 274 }
 275 
 276 /**
 277  * Returns a copy of the Unicode characters of a string. Fow now this
 278  * function doesn't handle long path names and other issues.
 279  */
 280 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 281     WCHAR *pathbuf = NULL;
 282     const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
 283     if (chars != NULL) {
 284         size_t pathlen = wcslen(chars);
 285         pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 286         if (pathbuf == NULL) {




  23  * questions.
  24  */
  25 
  26 #include <assert.h>
  27 #include "java_lang_ProcessImpl.h"
  28 
  29 #include "jni.h"
  30 #include "jvm.h"
  31 #include "jni_util.h"
  32 #include "io_util.h"
  33 #include <windows.h>
  34 #include <io.h>
  35 
  36 /* We try to make sure that we can read and write 4095 bytes (the
  37  * fixed limit on Linux) to the pipe on all operating systems without
  38  * deadlock.  Windows 2000 inexplicably appears to need an extra 24
  39  * bytes of slop to avoid deadlock.
  40  */
  41 #define PIPE_SIZE (4096+24)
  42 
  43 /* We have THREE locales in action: 
  44  * 1. Thread default locale - dictates UNICODE-to-8bit conversion
  45  * 2. System locale that defines the message localization
  46  * 3. The file name locale
  47  * Each locale could be an extended locale, that means that text cannot be
  48  * mapped to 8bit sequence without multibyte encoding.
  49  * VM is ready for that, if text is UTF-8.
  50  * Here we make the work right from the beginning.
  51  */
  52 size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
  53     size_t n = (size_t)FormatMessageW(
  54             FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
  55             NULL,
  56             (DWORD)errnum,
  57             0,
  58             utf16_OSErrorMsg,
  59             (DWORD)maxMsgLength,
  60             NULL);
  61     if (n > 3) {
  62         // Drop final '.', CR, LF
  63         if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
  64         if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
  65         if (utf16_OSErrorMsg[n - 1] == L'.') --n;
  66         utf16_OSErrorMsg[n] = L'\0';
  67     }
  68     return n;
  69 }
  70 
  71 #define MESSAGE_LENGTH (256 + 100)
  72 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
  73 
  74 static void
  75 win32Error(JNIEnv *env, const WCHAR *functionName)
  76 {
  77     WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
  78     WCHAR utf16_javaMessage[MESSAGE_LENGTH];
  79     /*Good suggestion about 2-bytes-per-symbol in localized error reports*/
  80     char  utf8_javaMessage[MESSAGE_LENGTH*2];
  81     const int errnum = (int)GetLastError();
  82     const int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
  83     if (n > 0)
  84         swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg);
  85     else
  86         swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
  87 
  88     WideCharToMultiByte(
  89         CP_UTF8,
  90         0,
  91         utf16_javaMessage,
  92         MESSAGE_LENGTH,
  93         utf8_javaMessage,
  94         MESSAGE_LENGTH*2,
  95         NULL,
  96         NULL);
  97 
  98     /*no way to die*/
  99     utf8_javaMessage[MESSAGE_LENGTH*2 - 1] = '\0';
 100     JNU_ThrowIOException(env, utf8_javaMessage);
 101 }
 102 
 103 static void
 104 closeSafely(HANDLE handle)
 105 {
 106     if (handle != INVALID_HANDLE_VALUE)
 107         CloseHandle(handle);
 108 }
 109 
 110 JNIEXPORT jlong JNICALL
 111 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 112                                   jstring cmd,
 113                                   jstring envBlock,
 114                                   jstring dir,
 115                                   jlongArray stdHandles,
 116                                   jboolean redirectErrorStream)
 117 {
 118     HANDLE inRead   = INVALID_HANDLE_VALUE;
 119     HANDLE inWrite  = INVALID_HANDLE_VALUE;
 120     HANDLE outRead  = INVALID_HANDLE_VALUE;


 143         penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
 144         if (penvBlock == NULL) goto Catch;
 145     }
 146     assert(stdHandles != NULL);
 147     handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 148     if (handles == NULL) goto Catch;
 149 
 150     memset(&si, 0, sizeof(si));
 151     si.cb = sizeof(si);
 152     si.dwFlags = STARTF_USESTDHANDLES;
 153 
 154     sa.nLength = sizeof(sa);
 155     sa.lpSecurityDescriptor = 0;
 156     sa.bInheritHandle = TRUE;
 157 
 158     if (handles[0] != (jlong) -1) {
 159         si.hStdInput = (HANDLE) handles[0];
 160         handles[0] = (jlong) -1;
 161     } else {
 162         if (! CreatePipe(&inRead,  &inWrite,  &sa, PIPE_SIZE)) {
 163             win32Error(env, L"CreatePipe");
 164             goto Catch;
 165         }
 166         si.hStdInput = inRead;
 167         SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0);
 168         handles[0] = (jlong) inWrite;
 169     }
 170     SetHandleInformation(si.hStdInput,
 171         HANDLE_FLAG_INHERIT,
 172         HANDLE_FLAG_INHERIT);
 173 
 174     if (handles[1] != (jlong) -1) {
 175         si.hStdOutput = (HANDLE) handles[1];
 176         handles[1] = (jlong) -1;
 177     } else {
 178         if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
 179             win32Error(env, L"CreatePipe");
 180             goto Catch;
 181         }
 182         si.hStdOutput = outWrite;
 183         SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0);
 184         handles[1] = (jlong) outRead;
 185     }
 186     SetHandleInformation(si.hStdOutput,
 187         HANDLE_FLAG_INHERIT,
 188         HANDLE_FLAG_INHERIT);
 189 
 190     if (redirectErrorStream) {
 191         si.hStdError = si.hStdOutput;
 192         handles[2] = (jlong) -1;
 193     } else if (handles[2] != (jlong) -1) {
 194         si.hStdError = (HANDLE) handles[2];
 195         handles[2] = (jlong) -1;
 196     } else {
 197         if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
 198             win32Error(env, L"CreatePipe");
 199             goto Catch;
 200         }
 201         si.hStdError = errWrite;
 202         SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0);
 203         handles[2] = (jlong) errRead;
 204     }
 205     SetHandleInformation(si.hStdError,
 206         HANDLE_FLAG_INHERIT,
 207         HANDLE_FLAG_INHERIT);
 208 
 209     processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 210     ret = CreateProcessW(0,                /* executable name */
 211                          (LPWSTR)pcmd,     /* command line */
 212                          0,                /* process security attribute */
 213                          0,                /* thread security attribute */
 214                          TRUE,             /* inherits system handles */
 215                          processFlag,      /* selected based on exe type */
 216                          (LPVOID)penvBlock,/* environment block */
 217                          (LPCWSTR)pdir,    /* change to the new current directory */
 218                          &si,              /* (in)  startup information */
 219                          &pi);             /* (out) process information */
 220     if (!ret) {
 221         win32Error(env, L"CreateProcess");
 222         goto Catch;
 223     }
 224 
 225     CloseHandle(pi.hThread);
 226     ret = (jlong)pi.hProcess;
 227 
 228  Finally:
 229     /* Always clean up the child's side of the pipes */
 230     closeSafely(inRead);
 231     closeSafely(outWrite);
 232     closeSafely(errWrite);
 233 
 234     if (pcmd != NULL)
 235         (*env)->ReleaseStringChars(env, cmd, pcmd);
 236     if (pdir != NULL)
 237         (*env)->ReleaseStringChars(env, dir, pdir);
 238     if (penvBlock != NULL)
 239         (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 240     if (handles != NULL)
 241         (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 242     return ret;
 243 
 244  Catch:
 245     /* Clean up the parent's side of the pipes in case of failure only */
 246     closeSafely(inWrite);
 247     closeSafely(outRead);
 248     closeSafely(errRead);
 249     goto Finally;
 250 }
 251 
 252 JNIEXPORT jint JNICALL
 253 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 254 {
 255     DWORD exit_code;
 256     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 257         win32Error(env, L"GetExitCodeProcess");
 258     return exit_code;
 259 }
 260 
 261 JNIEXPORT jint JNICALL
 262 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 263 {
 264     return STILL_ACTIVE;
 265 }
 266 
 267 JNIEXPORT void JNICALL
 268 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 269 {
 270     HANDLE events[2];
 271     events[0] = (HANDLE) handle;
 272     events[1] = JVM_GetThreadInterruptEvent();
 273 
 274     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 275                                FALSE,    /* Wait for ANY event */
 276                                INFINITE)  /* Wait forever */
 277         == WAIT_FAILED)
 278         win32Error(env, L"WaitForMultipleObjects");
 279 }
 280 
 281 JNIEXPORT void JNICALL
 282 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
 283                                                        jclass ignored,
 284                                                        jlong handle,
 285                                                        jlong timeout)
 286 {
 287     HANDLE events[2];
 288     DWORD dwTimeout = (DWORD)timeout;
 289     DWORD result;
 290     events[0] = (HANDLE) handle;
 291     events[1] = JVM_GetThreadInterruptEvent();
 292     result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 293                                     FALSE,    /* Wait for ANY event */
 294                                     dwTimeout);  /* Wait for dwTimeout */
 295 
 296     if (result == WAIT_FAILED)
 297         win32Error(env, L"WaitForMultipleObjects");
 298 }
 299 
 300 JNIEXPORT void JNICALL
 301 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 302 {
 303     TerminateProcess((HANDLE) handle, 1);
 304 }
 305 
 306 JNIEXPORT jboolean JNICALL
 307 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
 308 {
 309     DWORD dwExitStatus;
 310     GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
 311     return dwExitStatus == STILL_ACTIVE;
 312 }
 313 
 314 JNIEXPORT jboolean JNICALL
 315 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 316 {
 317     return CloseHandle((HANDLE) handle);
 318 }
 319 
 320 /**
 321  * Returns a copy of the Unicode characters of a string. Fow now this
 322  * function doesn't handle long path names and other issues.
 323  */
 324 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 325     WCHAR *pathbuf = NULL;
 326     const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
 327     if (chars != NULL) {
 328         size_t pathlen = wcslen(chars);
 329         pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 330         if (pathbuf == NULL) {