Path: blob/master/src/java.base/windows/native/libjava/ProcessImpl_md.c
41119 views
/*1* Copyright (c) 1997, 2015, 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 "io_util_md.h"33#include <windows.h>34#include <io.h>3536/* We try to make sure that we can read and write 4095 bytes (the37* fixed limit on Linux) to the pipe on all operating systems without38* deadlock. Windows 2000 inexplicably appears to need an extra 2439* bytes of slop to avoid deadlock.40*/41#define PIPE_SIZE (4096+24)4243/* We have THREE locales in action:44* 1. Thread default locale - dictates UNICODE-to-8bit conversion45* 2. System locale that defines the message localization46* 3. The file name locale47* Each locale could be an extended locale, that means that text cannot be48* 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*/52size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {53size_t n = (size_t)FormatMessageW(54FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,55NULL,56(DWORD)errnum,570,58utf16_OSErrorMsg,59(DWORD)maxMsgLength,60NULL);61if (n > 3) {62// Drop final '.', CR, LF63if (utf16_OSErrorMsg[n - 1] == L'\n') --n;64if (utf16_OSErrorMsg[n - 1] == L'\r') --n;65if (utf16_OSErrorMsg[n - 1] == L'.') --n;66utf16_OSErrorMsg[n] = L'\0';67}68return n;69}7071#define MESSAGE_LENGTH (256 + 100)72#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))7374static void75win32Error(JNIEnv *env, const WCHAR *functionName)76{77WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];78WCHAR utf16_javaMessage[MESSAGE_LENGTH];79/*Good suggestion about 2-bytes-per-symbol in localized error reports*/80char utf8_javaMessage[MESSAGE_LENGTH*2];81const int errnum = (int)GetLastError();82size_t n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));83n = (n > 0)84? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)85: swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);8687if (n > 0) /*terminate '\0' is not a part of conversion procedure*/88n = WideCharToMultiByte(89CP_UTF8,900,91utf16_javaMessage,92(int)n, /*by creation n <= MESSAGE_LENGTH*/93utf8_javaMessage,94MESSAGE_LENGTH*2,95NULL,96NULL);9798/*no way to die*/99{100const char *errorMessage = "Secondary error while OS message extraction";101if (n > 0) {102utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';103errorMessage = utf8_javaMessage;104}105JNU_ThrowIOException(env, errorMessage);106}107}108109static void110closeSafely(HANDLE handle)111{112if (handle != INVALID_HANDLE_VALUE)113CloseHandle(handle);114}115116static BOOL hasInheritFlag(HANDLE handle)117{118DWORD mask;119if (GetHandleInformation(handle, &mask)) {120return mask & HANDLE_FLAG_INHERIT;121}122return FALSE;123}124125#define HANDLE_STORAGE_SIZE 6126#define OFFSET_READ 0127#define OFFSET_WRITE 1128//long signed version of INVALID_HANDLE_VALUE129#define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)130#define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)131132/* Pipe holder structure */133typedef struct _STDHOLDER {134HANDLE pipe[2];135int offset;136} STDHOLDER;137138/* Responsible for correct initialization of the [pHolder] structure139(that is used for handles recycling) if needs,140and appropriate setup of IOE handle [phStd] for child process based141on created pipe or Java handle. */142static BOOL initHolder(143JNIEnv *env,144jlong *pjhandles, /* IN OUT - the handle form Java,145that can be a file, console or undefined */146STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe147handles */148HANDLE *phStd /* OUT - initialized handle for child process */149) {150/* Here we test the value from Java against invalid151handle value. We are not using INVALID_HANDLE_VALUE macro152due to double signed/unsigned and 32/64bit ambiguity.153Otherwise it will be easy to get the wrong154value 0x00000000FFFFFFFF155instead 0xFFFFFFFFFFFFFFFF. */156if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {157/* Java file or console redirection */158*phStd = (HANDLE) *pjhandles;159/* Here we set the related Java stream (Process.getXXXXStream())160to [ProcessBuilder.NullXXXXStream.INSTANCE] value.161The initial Java handle [*pjhandles] will be closed in162ANY case. It is not a handle leak. */163*pjhandles = JAVA_INVALID_HANDLE_VALUE;164} else {165/* Creation of parent-child pipe */166if (!CreatePipe(167&pHolder->pipe[OFFSET_READ],168&pHolder->pipe[OFFSET_WRITE],169NULL, /* we would like to inherit170default process access,171instead of 'Everybody' access */172PIPE_SIZE))173{174win32Error(env, L"CreatePipe");175return FALSE;176} else {177/* [thisProcessEnd] has no the inherit flag because178the [lpPipeAttributes] param of [CreatePipe]179had the NULL value. */180HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];181*phStd = pHolder->pipe[pHolder->offset];182*pjhandles = (jlong) thisProcessEnd;183}184}185/* Pipe handle will be closed in the [releaseHolder] call,186file handle will be closed in Java.187The long-live handle need to restore the inherit flag,188we do it later in the [prepareIOEHandleState] call. */189SetHandleInformation(190*phStd,191HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);192return TRUE;193}194195/* Smart recycling of pipe handles in [pHolder]. For the failed196create process attempts, both ends of pipe need to be released.197The [complete] has the [TRUE] value in the failed attempt. */198static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {199closeSafely(pHolder->pipe[pHolder->offset]);200if (complete) {201/* Error occur, close this process pipe end */202closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);203}204}205206/* Stores and drops the inherit flag of handles that should not207be shared with the child process by default, but can hold the208inherit flag due to MS process birth specific. */209static void prepareIOEHandleState(210HANDLE *stdIOE,211BOOL *inherit)212{213int i;214for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {215HANDLE hstd = stdIOE[i];216if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {217/* FALSE by default */218inherit[i] = TRUE;219/* Java does not need implicit inheritance for IOE handles,220so we drop inherit flag that probably was installed by221previous CreateProcess call that launched current process.222We will return the handle state back after CreateProcess call.223By clearing inherit flag we prevent "greedy grandchild" birth.224The explicit inheritance for child process IOE handles is225implemented in the [initHolder] call. */226SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);227}228}229}230231/* Restores the inheritance flag of handles from stored values. */232static void restoreIOEHandleState(233const HANDLE *stdIOE,234const BOOL *inherit)235{236/* The set of current process standard IOE handles and237the set of child process IOE handles can intersect.238To restore the inherit flag right, we use backward239array iteration. */240int i;241for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)242if (INVALID_HANDLE_VALUE != stdIOE[i]) {243/* Restore inherit flag for any case.244The handle can be changed by explicit inheritance.*/245SetHandleInformation(stdIOE[i],246HANDLE_FLAG_INHERIT,247inherit[i] ? HANDLE_FLAG_INHERIT : 0);248}249}250251/*252* Class: java_lang_ProcessImpl253* Method: getProcessId0254* Signature: (J)I255*/256JNIEXPORT jint JNICALL Java_java_lang_ProcessImpl_getProcessId0257(JNIEnv *env, jclass clazz, jlong handle) {258DWORD pid = GetProcessId((HANDLE) jlong_to_ptr(handle));259return (jint)pid;260}261262/* Please, read about the MS inheritance problem263http://support.microsoft.com/kb/315939264and critical section/synchronized block solution. */265static jlong processCreate(266JNIEnv *env,267const jchar *pcmd,268const jchar *penvBlock,269const jchar *pdir,270jlong *handles,271jboolean redirectErrorStream)272{273jlong ret = 0L;274STARTUPINFOW si = {sizeof(si)};275276/* Handles for which the inheritance flag must be restored. */277HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {278/* Current process standard IOE handles: JDK-7147084 */279INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,280/* Child process IOE handles: JDK-6921885 */281(HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};282BOOL inherit[HANDLE_STORAGE_SIZE] = {283FALSE, FALSE, FALSE,284FALSE, FALSE, FALSE};285286/* These three should not be closed by CloseHandle! */287stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);288stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);289stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);290291prepareIOEHandleState(stdIOE, inherit);292{293/* Input */294STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};295if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {296297/* Output */298STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};299if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {300301/* Error */302STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};303BOOL success;304if (redirectErrorStream) {305si.hStdError = si.hStdOutput;306/* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]307value. That is in accordance with Java Doc for the redirection case.308The Java file for the [ handles[2] ] will be closed in ANY case. It is not309a handle leak. */310handles[2] = JAVA_INVALID_HANDLE_VALUE;311success = TRUE;312} else {313success = initHolder(env, &handles[2], &holderErr, &si.hStdError);314}315316if (success) {317PROCESS_INFORMATION pi;318DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;319320/* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */321if (GetConsoleWindow() != NULL &&322(si.hStdInput == stdIOE[0] ||323si.hStdOutput == stdIOE[1] ||324si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))325{326processFlag &= ~CREATE_NO_WINDOW;327}328329si.dwFlags = STARTF_USESTDHANDLES;330if (!CreateProcessW(331NULL, /* executable name */332(LPWSTR)pcmd, /* command line */333NULL, /* process security attribute */334NULL, /* thread security attribute */335TRUE, /* inherits system handles */336processFlag, /* selected based on exe type */337(LPVOID)penvBlock,/* environment block */338(LPCWSTR)pdir, /* change to the new current directory */339&si, /* (in) startup information */340&pi)) /* (out) process information */341{342win32Error(env, L"CreateProcess");343} else {344closeSafely(pi.hThread);345ret = (jlong)pi.hProcess;346}347}348releaseHolder(ret == 0, &holderErr);349releaseHolder(ret == 0, &holderOut);350}351releaseHolder(ret == 0, &holderIn);352}353}354restoreIOEHandleState(stdIOE, inherit);355356return ret;357}358359JNIEXPORT jlong JNICALL360Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,361jstring cmd,362jstring envBlock,363jstring dir,364jlongArray stdHandles,365jboolean redirectErrorStream)366{367jlong ret = 0;368if (cmd != NULL && stdHandles != NULL) {369const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);370if (pcmd != NULL) {371const jchar *penvBlock = (envBlock != NULL)372? (*env)->GetStringChars(env, envBlock, NULL)373: NULL;374if (!(*env)->ExceptionCheck(env)) {375const jchar *pdir = (dir != NULL)376? (*env)->GetStringChars(env, dir, NULL)377: NULL;378if (!(*env)->ExceptionCheck(env)) {379jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);380if (handles != NULL) {381ret = processCreate(382env,383pcmd,384penvBlock,385pdir,386handles,387redirectErrorStream);388(*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);389}390if (pdir != NULL)391(*env)->ReleaseStringChars(env, dir, pdir);392}393if (penvBlock != NULL)394(*env)->ReleaseStringChars(env, envBlock, penvBlock);395}396(*env)->ReleaseStringChars(env, cmd, pcmd);397}398}399return ret;400}401402JNIEXPORT jint JNICALL403Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)404{405DWORD exit_code;406if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)407win32Error(env, L"GetExitCodeProcess");408return exit_code;409}410411JNIEXPORT jint JNICALL412Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)413{414return STILL_ACTIVE;415}416417JNIEXPORT void JNICALL418Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)419{420HANDLE events[2];421events[0] = (HANDLE) handle;422events[1] = JVM_GetThreadInterruptEvent();423424if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,425FALSE, /* Wait for ANY event */426INFINITE) /* Wait forever */427== WAIT_FAILED)428win32Error(env, L"WaitForMultipleObjects");429}430431JNIEXPORT void JNICALL432Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,433jclass ignored,434jlong handle,435jlong timeoutMillis)436{437HANDLE events[2];438DWORD dwTimeout = (DWORD)timeoutMillis;439DWORD result;440events[0] = (HANDLE) handle;441events[1] = JVM_GetThreadInterruptEvent();442result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,443FALSE, /* Wait for ANY event */444dwTimeout); /* Wait for dwTimeout */445446if (result == WAIT_FAILED)447win32Error(env, L"WaitForMultipleObjects");448}449450JNIEXPORT void JNICALL451Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)452{453TerminateProcess((HANDLE) handle, 1);454}455456JNIEXPORT jboolean JNICALL457Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)458{459DWORD dwExitStatus;460GetExitCodeProcess((HANDLE) handle, &dwExitStatus);461return dwExitStatus == STILL_ACTIVE;462}463464JNIEXPORT jboolean JNICALL465Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)466{467return (jboolean) CloseHandle((HANDLE) handle);468}469470JNIEXPORT jlong JNICALL471Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)472{473const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);474const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;475const DWORD disposition = OPEN_ALWAYS;476const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;477HANDLE h;478WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);479if (pathbuf == NULL) {480/* Exception already pending */481return -1;482}483h = CreateFileW(484pathbuf, /* Wide char path name */485access, /* Read and/or write permission */486sharing, /* File sharing flags */487NULL, /* Security attributes */488disposition, /* creation disposition */489flagsAndAttributes, /* flags and attributes */490NULL);491free(pathbuf);492if (h == INVALID_HANDLE_VALUE) {493JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");494}495return ptr_to_jlong(h);496}497498499