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

Print this page




  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;
  77     HANDLE outWrite = INVALID_HANDLE_VALUE;
  78     HANDLE errRead  = INVALID_HANDLE_VALUE;
  79     HANDLE errWrite = INVALID_HANDLE_VALUE;
  80     SECURITY_ATTRIBUTES sa;
  81     PROCESS_INFORMATION pi;
  82     STARTUPINFOW si;
  83     const jchar*  pcmd = NULL;
  84     const jchar*  pdir = NULL;
  85     const jchar*  penvBlock = NULL;
  86     jlong  *handles = NULL;
  87     jlong ret = 0;
  88     DWORD processFlag;
  89 
  90     assert(cmd != NULL);
  91     pcmd = (*env)->GetStringChars(env, cmd, NULL);
  92     if (pcmd == NULL) goto Catch;
  93 
  94     if (dir != 0) {
  95         pdir = (*env)->GetStringChars(env, dir, NULL);
  96         if (pdir == NULL) goto Catch;
  97     }
  98     if (envBlock != NULL) {
  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 {


 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) {




  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 static BOOL hasInheritFlag(HANDLE handle)






  67 {
  68     DWORD mask;
  69     if (GetHandleInformation(handle, &mask)) {
  70         return mask & HANDLE_FLAG_INHERIT;
  71     }
  72     return FALSE;
  73 }





























  74 
  75 #define HANDLE_STORAGE_SIZE 6
  76 #define OFFSET_READ  0
  77 #define OFFSET_WRITE 1
  78 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
  79 
  80 typedef struct _STDHOLDER {
  81     HANDLE  pipe[2];
  82     int     offset;
  83 } STDHOLDER;
  84 
  85 static BOOL initHolder(
  86     JNIEnv *env,
  87     STDHOLDER *pHolder,
  88     jlong *pjhandles,
  89     HANDLE *phStd)
  90 {
  91     if (*pjhandles != (jlong) -1) {
  92         *phStd = (HANDLE) *pjhandles;
  93         *pjhandles = (jlong) -1;
  94     } else {
  95         if (!CreatePipe(
  96             &pHolder->pipe[OFFSET_READ],
  97             &pHolder->pipe[OFFSET_WRITE],
  98             NULL, /* we would like to inherit
  99                      default process access,
 100                      instead of 'Everybody' access */
 101             PIPE_SIZE))
 102         {
 103             win32Error(env, "CreatePipe");
 104             return FALSE;
 105         } else {
 106             /* [thisProcessEnd] has no the inherit flag.
 107                the [lpPipeAttributes] param had the NULL value. */
 108             HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
 109             *phStd = pHolder->pipe[pHolder->offset];
 110             *pjhandles = (jlong) thisProcessEnd;
 111         }



 112     }
 113     /* Pipe handle will be closed in the [releaseHolder] call,
 114        file handle will be closed in Java.
 115        The long-live handle need to restore the inherit flag,
 116        we do it later in the [prepareIOEHandleState] call. */
 117     SetHandleInformation(
 118         *phStd,
 119         HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
 120     return TRUE;
 121 }
 122 
 123 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
 124     closeSafely(pHolder->pipe[pHolder->offset]);
 125     if (complete) {
 126         /* Error occur, close this process pipe end */
 127         closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
 128     }
 129 }
 130 
 131 static void prepareIOEHandleState(
 132     HANDLE *stdIOE,
 133     BOOL *inherit)
 134 {
 135     int i;
 136     for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
 137         HANDLE hstd = stdIOE[i];
 138         if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
 139             /* FALSE by default */
 140             inherit[i] = TRUE;
 141             /* Java does not need implicit inheritance for IOE handles,
 142                so we drop inherit flag that probably was installed by
 143                previous CreateProcess call that launched current process.
 144                We will return the handle state back after CreateProcess call.
 145                By clearing inherit flag we prevent "greedy grandchild" birth.
 146                The explicit inheritance for child process IOE handles is
 147                supported in the [initHolder] call. */
 148             SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
 149         }



 150     }
 151 }
 152 
 153 static void restoreIOEHandleState(
 154     const HANDLE *stdIOE,
 155     const BOOL *inherit)
 156 {
 157     /* The set of current process standard IOE handles and
 158        the set of child process IOE handles can intersect.
 159        To restore the inherit flag right, we use backward
 160        array iteration. */
 161     int i;
 162     for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
 163         if (INVALID_HANDLE_VALUE != stdIOE[i]) {
 164            /* Restore inherit flag for any case.
 165               The handle can be changed by explicit inheritance.*/
 166             SetHandleInformation(stdIOE[i],
 167                 HANDLE_FLAG_INHERIT,
 168                 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
 169         }
 170 }
 171 
 172 /* Please, read about the MS inheritance problem
 173    http://support.microsoft.com/kb/315939
 174    and critical section/synchronized block solution. */
 175 static jlong processCreate(
 176     JNIEnv *env,
 177     const jchar *pcmd,
 178     const jchar *penvBlock,
 179     const jchar *pdir,
 180     jlong *handles,
 181     jboolean redirectErrorStream)
 182 {
 183     jlong ret = 0L;
 184     STARTUPINFOW si = {sizeof(si)};
 185 
 186     /* Handles for which the inheritance flag must be restored. */
 187     HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
 188         /* Current process standard IOE handles: JDK-7147084 */
 189         INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
 190         /* Child process IOE handles: JDK-6921885 */
 191         (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
 192     BOOL inherit[HANDLE_STORAGE_SIZE] = {
 193         FALSE, FALSE, FALSE,
 194         FALSE, FALSE, FALSE};
 195 
 196     {
 197         /* Extraction of current process standard IOE handles */
 198         DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
 199         int i;
 200         for (i = 0; i < 3; ++i)
 201             /* Should not be closed by CloseHandle! */
 202             stdIOE[i] = GetStdHandle(idsIOE[i]);
 203     }
 204 
 205     prepareIOEHandleState(stdIOE, inherit);
 206     {
 207         /* Input */
 208         STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
 209         if (initHolder(env, &holderIn, &handles[0], &si.hStdInput)) {
 210 
 211             /* Output */
 212             STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
 213             if (initHolder(env, &holderOut, &handles[1], &si.hStdOutput)) {
 214 
 215                 /* Error */
 216                 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
 217                 BOOL success;
 218                 if (redirectErrorStream) {
 219                     si.hStdError = si.hStdOutput;
 220                     handles[2] = (jlong) -1;
 221                     success = TRUE;


 222                 } else {
 223                     success = initHolder(env, &holderErr, &handles[2], &si.hStdError);






 224                 }



 225 
 226                 if (success) {
 227                     PROCESS_INFORMATION pi;
 228                     DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 229 
 230                     si.dwFlags = STARTF_USESTDHANDLES;
 231                     if (!CreateProcessW(
 232                         NULL,             /* executable name */
 233                         (LPWSTR)pcmd,     /* command line */
 234                         NULL,             /* process security attribute */
 235                         NULL,             /* thread security attribute */
 236                         TRUE,             /* inherits system handles */
 237                         processFlag,      /* selected based on exe type */
 238                         (LPVOID)penvBlock,/* environment block */
 239                         (LPCWSTR)pdir,    /* change to the new current directory */
 240                         &si,              /* (in)  startup information */
 241                         &pi))             /* (out) process information */
 242                     {
 243                         win32Error(env, "CreateProcess");
 244                     } else {
 245                         closeSafely(pi.hThread);


 246                         ret = (jlong)pi.hProcess;
 247                     }
 248                 }
 249                 releaseHolder(ret == 0, &holderErr);
 250                 releaseHolder(ret == 0, &holderOut);
 251             }
 252             releaseHolder(ret == 0, &holderIn);
 253         }
 254     }
 255     restoreIOEHandleState(stdIOE, inherit);
 256 
 257     return ret;
 258 }



 259 
 260 JNIEXPORT jlong JNICALL
 261 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 262                                   jstring cmd,
 263                                   jstring envBlock,
 264                                   jstring dir,
 265                                   jlongArray stdHandles,
 266                                   jboolean redirectErrorStream)
 267 {
 268     jlong ret = 0;
 269     if (cmd != NULL
 270      && stdHandles != NULL)
 271     {
 272         const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
 273         if (pcmd != NULL) {
 274             const jchar *penvBlock = (envBlock != NULL)
 275                 ? (*env)->GetStringChars(env, envBlock, NULL)
 276                 : NULL;
 277             const jchar *pdir = (dir != NULL)
 278                 ? (*env)->GetStringChars(env, dir, NULL)
 279                 : NULL;
 280             jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 281             if (handles != NULL) {
 282                 ret = processCreate(
 283                     env,
 284                     pcmd,
 285                     penvBlock,
 286                     pdir,
 287                     handles,
 288                     redirectErrorStream);
 289                 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 290             }
 291             if (pdir != NULL)
 292                 (*env)->ReleaseStringChars(env, dir, pdir);
 293             if (penvBlock != NULL)
 294                 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 295             (*env)->ReleaseStringChars(env, cmd, pcmd);
 296         }
 297     }
 298     return ret;







 299 }
 300 
 301 JNIEXPORT jint JNICALL
 302 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 303 {
 304     DWORD exit_code;
 305     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 306         win32Error(env, "GetExitCodeProcess");
 307     return exit_code;
 308 }
 309 
 310 JNIEXPORT jint JNICALL
 311 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 312 {
 313     return STILL_ACTIVE;
 314 }
 315 
 316 JNIEXPORT void JNICALL
 317 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 318 {


 339     events[0] = (HANDLE) handle;
 340     events[1] = JVM_GetThreadInterruptEvent();
 341     result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 342                                     FALSE,    /* Wait for ANY event */
 343                                     dwTimeout);  /* Wait for dwTimeout */
 344 
 345     if (result == WAIT_FAILED)
 346         win32Error(env, "WaitForMultipleObjects");
 347 }
 348 
 349 JNIEXPORT void JNICALL
 350 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 351 {
 352     TerminateProcess((HANDLE) handle, 1);
 353 }
 354 
 355 JNIEXPORT jboolean JNICALL
 356 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
 357 {
 358     DWORD dwExitStatus;
 359     GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
 360     return dwExitStatus == STILL_ACTIVE;
 361 }
 362 
 363 JNIEXPORT jboolean JNICALL
 364 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 365 {
 366     return CloseHandle((HANDLE) handle);
 367 }
 368 
 369 /**
 370  * Returns a copy of the Unicode characters of a string. Fow now this
 371  * function doesn't handle long path names and other issues.
 372  */
 373 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 374     WCHAR *pathbuf = NULL;
 375     const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
 376     if (chars != NULL) {
 377         size_t pathlen = wcslen(chars);
 378         pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 379         if (pathbuf == NULL) {