Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/lang/ProcessImpl_md.c
32287 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <assert.h>26#include "java_lang_ProcessImpl.h"2728#include "jni.h"29#include "jvm.h"30#include "jni_util.h"31#include "io_util.h"32#include <windows.h>33#include <io.h>3435/* We try to make sure that we can read and write 4095 bytes (the36* fixed limit on Linux) to the pipe on all operating systems without37* deadlock. Windows 2000 inexplicably appears to need an extra 2438* bytes of slop to avoid deadlock.39*/40#define PIPE_SIZE (4096+24)4142/* We have THREE locales in action:43* 1. Thread default locale - dictates UNICODE-to-8bit conversion44* 2. System locale that defines the message localization45* 3. The file name locale46* Each locale could be an extended locale, that means that text cannot be47* mapped to 8bit sequence without multibyte encoding.48* VM is ready for that, if text is UTF-8.49* Here we make the work right from the beginning.50*/51size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {52size_t n = (size_t)FormatMessageW(53FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,54NULL,55(DWORD)errnum,560,57utf16_OSErrorMsg,58(DWORD)maxMsgLength,59NULL);60if (n > 3) {61// Drop final '.', CR, LF62if (utf16_OSErrorMsg[n - 1] == L'\n') --n;63if (utf16_OSErrorMsg[n - 1] == L'\r') --n;64if (utf16_OSErrorMsg[n - 1] == L'.') --n;65utf16_OSErrorMsg[n] = L'\0';66}67return n;68}6970#define MESSAGE_LENGTH (256 + 100)71#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))7273static void74win32Error(JNIEnv *env, const WCHAR *functionName)75{76WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];77WCHAR utf16_javaMessage[MESSAGE_LENGTH];78/*Good suggestion about 2-bytes-per-symbol in localized error reports*/79char utf8_javaMessage[MESSAGE_LENGTH*2];80const int errnum = (int)GetLastError();81int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));82n = (n > 0)83? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)84: swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);8586if (n > 0) /*terminate '\0' is not a part of conversion procedure*/87n = WideCharToMultiByte(88CP_UTF8,890,90utf16_javaMessage,91n, /*by creation n <= MESSAGE_LENGTH*/92utf8_javaMessage,93MESSAGE_LENGTH*2,94NULL,95NULL);9697/*no way to die*/98{99const char *errorMessage = "Secondary error while OS message extraction";100if (n > 0) {101utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';102errorMessage = utf8_javaMessage;103}104JNU_ThrowIOException(env, errorMessage);105}106}107108static void109closeSafely(HANDLE handle)110{111if (handle != INVALID_HANDLE_VALUE)112CloseHandle(handle);113}114115static BOOL hasInheritFlag(HANDLE handle)116{117DWORD mask;118if (GetHandleInformation(handle, &mask)) {119return mask & HANDLE_FLAG_INHERIT;120}121return FALSE;122}123124#define HANDLE_STORAGE_SIZE 6125#define OFFSET_READ 0126#define OFFSET_WRITE 1127//long signed version of INVALID_HANDLE_VALUE128#define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)129#define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)130131/* Pipe holder structure */132typedef struct _STDHOLDER {133HANDLE pipe[2];134int offset;135} STDHOLDER;136137/* Responsible for correct initialization of the [pHolder] structure138(that is used for handles recycling) if needs,139and appropriate setup of IOE handle [phStd] for child process based140on created pipe or Java handle. */141static BOOL initHolder(142JNIEnv *env,143jlong *pjhandles, /* IN OUT - the handle form Java,144that can be a file, console or undefined */145STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe146handles */147HANDLE *phStd /* OUT - initialized handle for child process */148) {149/* Here we test the value from Java against invalid150handle value. We are not using INVALID_HANDLE_VALUE macro151due to double signed/unsigned and 32/64bit ambiguity.152Otherwise it will be easy to get the wrong153value 0x00000000FFFFFFFF154instead 0xFFFFFFFFFFFFFFFF. */155if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {156/* Java file or console redirection */157*phStd = (HANDLE) *pjhandles;158/* Here we set the related Java stream (Process.getXXXXStream())159to [ProcessBuilder.NullXXXXStream.INSTANCE] value.160The initial Java handle [*pjhandles] will be closed in161ANY case. It is not a handle leak. */162*pjhandles = JAVA_INVALID_HANDLE_VALUE;163} else {164/* Creation of parent-child pipe */165if (!CreatePipe(166&pHolder->pipe[OFFSET_READ],167&pHolder->pipe[OFFSET_WRITE],168NULL, /* we would like to inherit169default process access,170instead of 'Everybody' access */171PIPE_SIZE))172{173win32Error(env, L"CreatePipe");174return FALSE;175} else {176/* [thisProcessEnd] has no the inherit flag because177the [lpPipeAttributes] param of [CreatePipe]178had the NULL value. */179HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];180*phStd = pHolder->pipe[pHolder->offset];181*pjhandles = (jlong) thisProcessEnd;182}183}184/* Pipe handle will be closed in the [releaseHolder] call,185file handle will be closed in Java.186The long-live handle need to restore the inherit flag,187we do it later in the [prepareIOEHandleState] call. */188SetHandleInformation(189*phStd,190HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);191return TRUE;192}193194/* Smart recycling of pipe handles in [pHolder]. For the failed195create process attempts, both ends of pipe need to be released.196The [complete] has the [TRUE] value in the failed attempt. */197static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {198closeSafely(pHolder->pipe[pHolder->offset]);199if (complete) {200/* Error occur, close this process pipe end */201closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);202}203}204205/* Stores and drops the inherit flag of handles that should not206be shared with the child process by default, but can hold the207inherit flag due to MS process birth specific. */208static void prepareIOEHandleState(209HANDLE *stdIOE,210BOOL *inherit)211{212int i;213for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {214HANDLE hstd = stdIOE[i];215if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {216/* FALSE by default */217inherit[i] = TRUE;218/* Java does not need implicit inheritance for IOE handles,219so we drop inherit flag that probably was installed by220previous CreateProcess call that launched current process.221We will return the handle state back after CreateProcess call.222By clearing inherit flag we prevent "greedy grandchild" birth.223The explicit inheritance for child process IOE handles is224implemented in the [initHolder] call. */225SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);226}227}228}229230/* Restores the inheritance flag of handles from stored values. */231static void restoreIOEHandleState(232const HANDLE *stdIOE,233const BOOL *inherit)234{235/* The set of current process standard IOE handles and236the set of child process IOE handles can intersect.237To restore the inherit flag right, we use backward238array iteration. */239int i;240for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)241if (INVALID_HANDLE_VALUE != stdIOE[i]) {242/* Restore inherit flag for any case.243The handle can be changed by explicit inheritance.*/244SetHandleInformation(stdIOE[i],245HANDLE_FLAG_INHERIT,246inherit[i] ? HANDLE_FLAG_INHERIT : 0);247}248}249250/* Please, read about the MS inheritance problem251http://support.microsoft.com/kb/315939252and critical section/synchronized block solution. */253static jlong processCreate(254JNIEnv *env,255const jchar *pcmd,256const jchar *penvBlock,257const jchar *pdir,258jlong *handles,259jboolean redirectErrorStream)260{261jlong ret = 0L;262STARTUPINFOW si = {sizeof(si)};263264/* Handles for which the inheritance flag must be restored. */265HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {266/* Current process standard IOE handles: JDK-7147084 */267INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,268/* Child process IOE handles: JDK-6921885 */269(HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};270BOOL inherit[HANDLE_STORAGE_SIZE] = {271FALSE, FALSE, FALSE,272FALSE, FALSE, FALSE};273274/* These three should not be closed by CloseHandle! */275stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);276stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);277stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);278279prepareIOEHandleState(stdIOE, inherit);280{281/* Input */282STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};283if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {284285/* Output */286STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};287if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {288289/* Error */290STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};291BOOL success;292if (redirectErrorStream) {293si.hStdError = si.hStdOutput;294/* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]295value. That is in accordance with Java Doc for the redirection case.296The Java file for the [ handles[2] ] will be closed in ANY case. It is not297a handle leak. */298handles[2] = JAVA_INVALID_HANDLE_VALUE;299success = TRUE;300} else {301success = initHolder(env, &handles[2], &holderErr, &si.hStdError);302}303304if (success) {305PROCESS_INFORMATION pi;306DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;307308/* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */309if (GetConsoleWindow() != NULL &&310(si.hStdInput == stdIOE[0] ||311si.hStdOutput == stdIOE[1] ||312si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))313{314processFlag &= ~CREATE_NO_WINDOW;315}316317si.dwFlags = STARTF_USESTDHANDLES;318if (!CreateProcessW(319NULL, /* executable name */320(LPWSTR)pcmd, /* command line */321NULL, /* process security attribute */322NULL, /* thread security attribute */323TRUE, /* inherits system handles */324processFlag, /* selected based on exe type */325(LPVOID)penvBlock,/* environment block */326(LPCWSTR)pdir, /* change to the new current directory */327&si, /* (in) startup information */328&pi)) /* (out) process information */329{330win32Error(env, L"CreateProcess");331} else {332closeSafely(pi.hThread);333ret = (jlong)pi.hProcess;334}335}336releaseHolder(ret == 0, &holderErr);337releaseHolder(ret == 0, &holderOut);338}339releaseHolder(ret == 0, &holderIn);340}341}342restoreIOEHandleState(stdIOE, inherit);343344return ret;345}346347JNIEXPORT jlong JNICALL348Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,349jstring cmd,350jstring envBlock,351jstring dir,352jlongArray stdHandles,353jboolean redirectErrorStream)354{355jlong ret = 0;356if (cmd != NULL && stdHandles != NULL) {357const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);358if (pcmd != NULL) {359const jchar *penvBlock = (envBlock != NULL)360? (*env)->GetStringChars(env, envBlock, NULL)361: NULL;362if (!(*env)->ExceptionCheck(env)) {363const jchar *pdir = (dir != NULL)364? (*env)->GetStringChars(env, dir, NULL)365: NULL;366if (!(*env)->ExceptionCheck(env)) {367jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);368if (handles != NULL) {369ret = processCreate(370env,371pcmd,372penvBlock,373pdir,374handles,375redirectErrorStream);376(*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);377}378if (pdir != NULL)379(*env)->ReleaseStringChars(env, dir, pdir);380}381if (penvBlock != NULL)382(*env)->ReleaseStringChars(env, envBlock, penvBlock);383}384(*env)->ReleaseStringChars(env, cmd, pcmd);385}386}387return ret;388}389390JNIEXPORT jint JNICALL391Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)392{393DWORD exit_code;394if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)395win32Error(env, L"GetExitCodeProcess");396return exit_code;397}398399JNIEXPORT jint JNICALL400Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)401{402return STILL_ACTIVE;403}404405JNIEXPORT void JNICALL406Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)407{408HANDLE events[2];409events[0] = (HANDLE) handle;410events[1] = JVM_GetThreadInterruptEvent();411412if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,413FALSE, /* Wait for ANY event */414INFINITE) /* Wait forever */415== WAIT_FAILED)416win32Error(env, L"WaitForMultipleObjects");417}418419JNIEXPORT void JNICALL420Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,421jclass ignored,422jlong handle,423jlong timeoutMillis)424{425HANDLE events[2];426DWORD dwTimeout = (DWORD)timeoutMillis;427DWORD result;428events[0] = (HANDLE) handle;429events[1] = JVM_GetThreadInterruptEvent();430result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,431FALSE, /* Wait for ANY event */432dwTimeout); /* Wait for dwTimeout */433434if (result == WAIT_FAILED)435win32Error(env, L"WaitForMultipleObjects");436}437438JNIEXPORT void JNICALL439Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)440{441TerminateProcess((HANDLE) handle, 1);442}443444JNIEXPORT jboolean JNICALL445Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)446{447DWORD dwExitStatus;448GetExitCodeProcess((HANDLE) handle, &dwExitStatus);449return dwExitStatus == STILL_ACTIVE;450}451452JNIEXPORT jboolean JNICALL453Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)454{455return (jboolean) CloseHandle((HANDLE) handle);456}457458/**459* Returns a copy of the Unicode characters of a string. Fow now this460* function doesn't handle long path names and other issues.461*/462static WCHAR* getPath(JNIEnv *env, jstring ps) {463WCHAR *pathbuf = NULL;464const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);465if (chars != NULL) {466size_t pathlen = wcslen(chars);467pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));468if (pathbuf == NULL) {469JNU_ThrowOutOfMemoryError(env, NULL);470} else {471wcscpy(pathbuf, chars);472}473(*env)->ReleaseStringChars(env, ps, chars);474}475return pathbuf;476}477478JNIEXPORT jlong JNICALL479Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)480{481const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);482const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;483const DWORD disposition = OPEN_ALWAYS;484const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;485HANDLE h;486WCHAR *pathbuf = getPath(env, path);487if (pathbuf == NULL) {488/* Exception already pending */489return -1;490}491h = CreateFileW(492pathbuf, /* Wide char path name */493access, /* Read and/or write permission */494sharing, /* File sharing flags */495NULL, /* Security attributes */496disposition, /* creation disposition */497flagsAndAttributes, /* flags and attributes */498NULL);499free(pathbuf);500if (h == INVALID_HANDLE_VALUE) {501JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");502}503return ptr_to_jlong(h);504}505506507