Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/lang/ProcessImpl_md.c
32287 views
1
/*
2
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
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
int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
83
n = (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);
86
87
if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
88
n = WideCharToMultiByte(
89
CP_UTF8,
90
0,
91
utf16_javaMessage,
92
n, /*by creation n <= MESSAGE_LENGTH*/
93
utf8_javaMessage,
94
MESSAGE_LENGTH*2,
95
NULL,
96
NULL);
97
98
/*no way to die*/
99
{
100
const char *errorMessage = "Secondary error while OS message extraction";
101
if (n > 0) {
102
utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
103
errorMessage = utf8_javaMessage;
104
}
105
JNU_ThrowIOException(env, errorMessage);
106
}
107
}
108
109
static void
110
closeSafely(HANDLE handle)
111
{
112
if (handle != INVALID_HANDLE_VALUE)
113
CloseHandle(handle);
114
}
115
116
static BOOL hasInheritFlag(HANDLE handle)
117
{
118
DWORD mask;
119
if (GetHandleInformation(handle, &mask)) {
120
return mask & HANDLE_FLAG_INHERIT;
121
}
122
return FALSE;
123
}
124
125
#define HANDLE_STORAGE_SIZE 6
126
#define OFFSET_READ 0
127
#define OFFSET_WRITE 1
128
//long signed version of INVALID_HANDLE_VALUE
129
#define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
130
#define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
131
132
/* Pipe holder structure */
133
typedef struct _STDHOLDER {
134
HANDLE pipe[2];
135
int offset;
136
} STDHOLDER;
137
138
/* Responsible for correct initialization of the [pHolder] structure
139
(that is used for handles recycling) if needs,
140
and appropriate setup of IOE handle [phStd] for child process based
141
on created pipe or Java handle. */
142
static BOOL initHolder(
143
JNIEnv *env,
144
jlong *pjhandles, /* IN OUT - the handle form Java,
145
that can be a file, console or undefined */
146
STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe
147
handles */
148
HANDLE *phStd /* OUT - initialized handle for child process */
149
) {
150
/* Here we test the value from Java against invalid
151
handle value. We are not using INVALID_HANDLE_VALUE macro
152
due to double signed/unsigned and 32/64bit ambiguity.
153
Otherwise it will be easy to get the wrong
154
value 0x00000000FFFFFFFF
155
instead 0xFFFFFFFFFFFFFFFF. */
156
if (*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())
160
to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
161
The initial Java handle [*pjhandles] will be closed in
162
ANY case. It is not a handle leak. */
163
*pjhandles = JAVA_INVALID_HANDLE_VALUE;
164
} else {
165
/* Creation of parent-child pipe */
166
if (!CreatePipe(
167
&pHolder->pipe[OFFSET_READ],
168
&pHolder->pipe[OFFSET_WRITE],
169
NULL, /* we would like to inherit
170
default process access,
171
instead of 'Everybody' access */
172
PIPE_SIZE))
173
{
174
win32Error(env, L"CreatePipe");
175
return FALSE;
176
} else {
177
/* [thisProcessEnd] has no the inherit flag because
178
the [lpPipeAttributes] param of [CreatePipe]
179
had the NULL value. */
180
HANDLE 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,
186
file handle will be closed in Java.
187
The long-live handle need to restore the inherit flag,
188
we do it later in the [prepareIOEHandleState] call. */
189
SetHandleInformation(
190
*phStd,
191
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
192
return TRUE;
193
}
194
195
/* Smart recycling of pipe handles in [pHolder]. For the failed
196
create process attempts, both ends of pipe need to be released.
197
The [complete] has the [TRUE] value in the failed attempt. */
198
static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
199
closeSafely(pHolder->pipe[pHolder->offset]);
200
if (complete) {
201
/* Error occur, close this process pipe end */
202
closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
203
}
204
}
205
206
/* Stores and drops the inherit flag of handles that should not
207
be shared with the child process by default, but can hold the
208
inherit flag due to MS process birth specific. */
209
static void prepareIOEHandleState(
210
HANDLE *stdIOE,
211
BOOL *inherit)
212
{
213
int i;
214
for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
215
HANDLE hstd = stdIOE[i];
216
if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
217
/* FALSE by default */
218
inherit[i] = TRUE;
219
/* Java does not need implicit inheritance for IOE handles,
220
so we drop inherit flag that probably was installed by
221
previous CreateProcess call that launched current process.
222
We will return the handle state back after CreateProcess call.
223
By clearing inherit flag we prevent "greedy grandchild" birth.
224
The explicit inheritance for child process IOE handles is
225
implemented in the [initHolder] call. */
226
SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
227
}
228
}
229
}
230
231
/* Restores the inheritance flag of handles from stored values. */
232
static void restoreIOEHandleState(
233
const HANDLE *stdIOE,
234
const BOOL *inherit)
235
{
236
/* The set of current process standard IOE handles and
237
the set of child process IOE handles can intersect.
238
To restore the inherit flag right, we use backward
239
array iteration. */
240
int i;
241
for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
242
if (INVALID_HANDLE_VALUE != stdIOE[i]) {
243
/* Restore inherit flag for any case.
244
The handle can be changed by explicit inheritance.*/
245
SetHandleInformation(stdIOE[i],
246
HANDLE_FLAG_INHERIT,
247
inherit[i] ? HANDLE_FLAG_INHERIT : 0);
248
}
249
}
250
251
/* Please, read about the MS inheritance problem
252
http://support.microsoft.com/kb/315939
253
and critical section/synchronized block solution. */
254
static jlong processCreate(
255
JNIEnv *env,
256
const jchar *pcmd,
257
const jchar *penvBlock,
258
const jchar *pdir,
259
jlong *handles,
260
jboolean redirectErrorStream)
261
{
262
jlong ret = 0L;
263
STARTUPINFOW si = {sizeof(si)};
264
265
/* Handles for which the inheritance flag must be restored. */
266
HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
267
/* Current process standard IOE handles: JDK-7147084 */
268
INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
269
/* Child process IOE handles: JDK-6921885 */
270
(HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
271
BOOL inherit[HANDLE_STORAGE_SIZE] = {
272
FALSE, FALSE, FALSE,
273
FALSE, FALSE, FALSE};
274
275
/* These three should not be closed by CloseHandle! */
276
stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);
277
stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);
278
stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);
279
280
prepareIOEHandleState(stdIOE, inherit);
281
{
282
/* Input */
283
STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
284
if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
285
286
/* Output */
287
STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
288
if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
289
290
/* Error */
291
STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
292
BOOL success;
293
if (redirectErrorStream) {
294
si.hStdError = si.hStdOutput;
295
/* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
296
value. That is in accordance with Java Doc for the redirection case.
297
The Java file for the [ handles[2] ] will be closed in ANY case. It is not
298
a handle leak. */
299
handles[2] = JAVA_INVALID_HANDLE_VALUE;
300
success = TRUE;
301
} else {
302
success = initHolder(env, &handles[2], &holderErr, &si.hStdError);
303
}
304
305
if (success) {
306
PROCESS_INFORMATION pi;
307
DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
308
309
/* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */
310
if (GetConsoleWindow() != NULL &&
311
(si.hStdInput == stdIOE[0] ||
312
si.hStdOutput == stdIOE[1] ||
313
si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))
314
{
315
processFlag &= ~CREATE_NO_WINDOW;
316
}
317
318
si.dwFlags = STARTF_USESTDHANDLES;
319
if (!CreateProcessW(
320
NULL, /* executable name */
321
(LPWSTR)pcmd, /* command line */
322
NULL, /* process security attribute */
323
NULL, /* thread security attribute */
324
TRUE, /* inherits system handles */
325
processFlag, /* selected based on exe type */
326
(LPVOID)penvBlock,/* environment block */
327
(LPCWSTR)pdir, /* change to the new current directory */
328
&si, /* (in) startup information */
329
&pi)) /* (out) process information */
330
{
331
win32Error(env, L"CreateProcess");
332
} else {
333
closeSafely(pi.hThread);
334
ret = (jlong)pi.hProcess;
335
}
336
}
337
releaseHolder(ret == 0, &holderErr);
338
releaseHolder(ret == 0, &holderOut);
339
}
340
releaseHolder(ret == 0, &holderIn);
341
}
342
}
343
restoreIOEHandleState(stdIOE, inherit);
344
345
return ret;
346
}
347
348
JNIEXPORT jlong JNICALL
349
Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
350
jstring cmd,
351
jstring envBlock,
352
jstring dir,
353
jlongArray stdHandles,
354
jboolean redirectErrorStream)
355
{
356
jlong ret = 0;
357
if (cmd != NULL && stdHandles != NULL) {
358
const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
359
if (pcmd != NULL) {
360
const jchar *penvBlock = (envBlock != NULL)
361
? (*env)->GetStringChars(env, envBlock, NULL)
362
: NULL;
363
if (!(*env)->ExceptionCheck(env)) {
364
const jchar *pdir = (dir != NULL)
365
? (*env)->GetStringChars(env, dir, NULL)
366
: NULL;
367
if (!(*env)->ExceptionCheck(env)) {
368
jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
369
if (handles != NULL) {
370
ret = processCreate(
371
env,
372
pcmd,
373
penvBlock,
374
pdir,
375
handles,
376
redirectErrorStream);
377
(*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
378
}
379
if (pdir != NULL)
380
(*env)->ReleaseStringChars(env, dir, pdir);
381
}
382
if (penvBlock != NULL)
383
(*env)->ReleaseStringChars(env, envBlock, penvBlock);
384
}
385
(*env)->ReleaseStringChars(env, cmd, pcmd);
386
}
387
}
388
return ret;
389
}
390
391
JNIEXPORT jint JNICALL
392
Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
393
{
394
DWORD exit_code;
395
if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
396
win32Error(env, L"GetExitCodeProcess");
397
return exit_code;
398
}
399
400
JNIEXPORT jint JNICALL
401
Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
402
{
403
return STILL_ACTIVE;
404
}
405
406
JNIEXPORT void JNICALL
407
Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
408
{
409
HANDLE events[2];
410
events[0] = (HANDLE) handle;
411
events[1] = JVM_GetThreadInterruptEvent();
412
413
if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
414
FALSE, /* Wait for ANY event */
415
INFINITE) /* Wait forever */
416
== WAIT_FAILED)
417
win32Error(env, L"WaitForMultipleObjects");
418
}
419
420
JNIEXPORT void JNICALL
421
Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
422
jclass ignored,
423
jlong handle,
424
jlong timeoutMillis)
425
{
426
HANDLE events[2];
427
DWORD dwTimeout = (DWORD)timeoutMillis;
428
DWORD result;
429
events[0] = (HANDLE) handle;
430
events[1] = JVM_GetThreadInterruptEvent();
431
result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
432
FALSE, /* Wait for ANY event */
433
dwTimeout); /* Wait for dwTimeout */
434
435
if (result == WAIT_FAILED)
436
win32Error(env, L"WaitForMultipleObjects");
437
}
438
439
JNIEXPORT void JNICALL
440
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
441
{
442
TerminateProcess((HANDLE) handle, 1);
443
}
444
445
JNIEXPORT jboolean JNICALL
446
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
447
{
448
DWORD dwExitStatus;
449
GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
450
return dwExitStatus == STILL_ACTIVE;
451
}
452
453
JNIEXPORT jboolean JNICALL
454
Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
455
{
456
return (jboolean) CloseHandle((HANDLE) handle);
457
}
458
459
/**
460
* Returns a copy of the Unicode characters of a string. Fow now this
461
* function doesn't handle long path names and other issues.
462
*/
463
static WCHAR* getPath(JNIEnv *env, jstring ps) {
464
WCHAR *pathbuf = NULL;
465
const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
466
if (chars != NULL) {
467
size_t pathlen = wcslen(chars);
468
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
469
if (pathbuf == NULL) {
470
JNU_ThrowOutOfMemoryError(env, NULL);
471
} else {
472
wcscpy(pathbuf, chars);
473
}
474
(*env)->ReleaseStringChars(env, ps, chars);
475
}
476
return pathbuf;
477
}
478
479
JNIEXPORT jlong JNICALL
480
Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
481
{
482
const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
483
const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
484
const DWORD disposition = OPEN_ALWAYS;
485
const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
486
HANDLE h;
487
WCHAR *pathbuf = getPath(env, path);
488
if (pathbuf == NULL) {
489
/* Exception already pending */
490
return -1;
491
}
492
h = CreateFileW(
493
pathbuf, /* Wide char path name */
494
access, /* Read and/or write permission */
495
sharing, /* File sharing flags */
496
NULL, /* Security attributes */
497
disposition, /* creation disposition */
498
flagsAndAttributes, /* flags and attributes */
499
NULL);
500
free(pathbuf);
501
if (h == INVALID_HANDLE_VALUE) {
502
JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
503
}
504
return ptr_to_jlong(h);
505
}
506
507