mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 20:44:41 +02:00
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
Reviewed-by: alanb
This commit is contained in:
parent
d558c37a5b
commit
54ddaf5ab7
9 changed files with 598 additions and 26 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,6 +26,7 @@
|
|||
package java.lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The {@link ProcessBuilder#start()} and
|
||||
|
@ -91,7 +92,7 @@ public abstract class Process {
|
|||
* @return the output stream connected to the normal input of the
|
||||
* subprocess
|
||||
*/
|
||||
abstract public OutputStream getOutputStream();
|
||||
public abstract OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Returns the input stream connected to the normal output of the
|
||||
|
@ -117,7 +118,7 @@ public abstract class Process {
|
|||
* @return the input stream connected to the normal output of the
|
||||
* subprocess
|
||||
*/
|
||||
abstract public InputStream getInputStream();
|
||||
public abstract InputStream getInputStream();
|
||||
|
||||
/**
|
||||
* Returns the input stream connected to the error output of the
|
||||
|
@ -138,7 +139,7 @@ public abstract class Process {
|
|||
* @return the input stream connected to the error output of
|
||||
* the subprocess
|
||||
*/
|
||||
abstract public InputStream getErrorStream();
|
||||
public abstract InputStream getErrorStream();
|
||||
|
||||
/**
|
||||
* Causes the current thread to wait, if necessary, until the
|
||||
|
@ -156,7 +157,51 @@ public abstract class Process {
|
|||
* thread while it is waiting, then the wait is ended and
|
||||
* an {@link InterruptedException} is thrown.
|
||||
*/
|
||||
abstract public int waitFor() throws InterruptedException;
|
||||
public abstract int waitFor() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Causes the current thread to wait, if necessary, until the
|
||||
* subprocess represented by this {@code Process} object has
|
||||
* terminated, or the specified waiting time elapses.
|
||||
*
|
||||
* <p>If the subprocess has already terminated then this method returns
|
||||
* immediately with the value {@code true}. If the process has not
|
||||
* terminated and the timeout value is less than, or equal to, zero, then
|
||||
* this method returns immediately with the value {@code false}.
|
||||
*
|
||||
* <p>The default implementation of this methods polls the {@code exitValue}
|
||||
* to check if the process has terminated. Concrete implementations of this
|
||||
* class are strongly encouraged to override this method with a more
|
||||
* efficient implementation.
|
||||
*
|
||||
* @param timeout the maximum time to wait
|
||||
* @param unit the time unit of the {@code timeout} argument
|
||||
* @return {@code true} if the subprocess has exited and {@code false} if
|
||||
* the waiting time elapsed before the subprocess has exited.
|
||||
* @throws InterruptedException if the current thread is interrupted
|
||||
* while waiting.
|
||||
* @throws NullPointerException if unit is null
|
||||
* @since 1.8
|
||||
*/
|
||||
public boolean waitFor(long timeout, TimeUnit unit)
|
||||
throws InterruptedException
|
||||
{
|
||||
long startTime = System.nanoTime();
|
||||
long rem = unit.toNanos(timeout);
|
||||
|
||||
do {
|
||||
try {
|
||||
exitValue();
|
||||
return true;
|
||||
} catch(IllegalThreadStateException ex) {
|
||||
if (rem > 0)
|
||||
Thread.sleep(
|
||||
Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
|
||||
}
|
||||
rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
|
||||
} while (rem > 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exit value for the subprocess.
|
||||
|
@ -167,11 +212,54 @@ public abstract class Process {
|
|||
* @throws IllegalThreadStateException if the subprocess represented
|
||||
* by this {@code Process} object has not yet terminated
|
||||
*/
|
||||
abstract public int exitValue();
|
||||
public abstract int exitValue();
|
||||
|
||||
/**
|
||||
* Kills the subprocess. Whether the subprocess represented by this
|
||||
* {@code Process} object is forcibly terminated or not is
|
||||
* implementation dependent.
|
||||
*/
|
||||
public abstract void destroy();
|
||||
|
||||
/**
|
||||
* Kills the subprocess. The subprocess represented by this
|
||||
* {@code Process} object is forcibly terminated.
|
||||
*
|
||||
* <p>The default implementation of this method invokes {@link #destroy}
|
||||
* and so may not forcibly terminate the process. Concrete implementations
|
||||
* of this class are strongly encouraged to override this method with a
|
||||
* compliant implementation. Invoking this method on {@code Process}
|
||||
* objects returned by {@link ProcessBuilder#start} and
|
||||
* {@link Runtime#exec} will forcibly terminate the process.
|
||||
*
|
||||
* <p>Note: The subprocess may not terminate immediately.
|
||||
* i.e. {@code isAlive()} may return true for a brief period
|
||||
* after {@code destroyForcibly()} is called. This method
|
||||
* may be chained to {@code waitFor()} if needed.
|
||||
*
|
||||
* @return the {@code Process} object representing the
|
||||
* subprocess to be forcibly destroyed.
|
||||
* @since 1.8
|
||||
*/
|
||||
abstract public void destroy();
|
||||
public Process destroyForcibly() {
|
||||
destroy();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the subprocess represented by this {@code Process} is
|
||||
* alive.
|
||||
*
|
||||
* @return {@code true} if the subprocess represented by this
|
||||
* {@code Process} object has not yet terminated.
|
||||
* @since 1.8
|
||||
*/
|
||||
public boolean isAlive() {
|
||||
try {
|
||||
exitValue();
|
||||
return false;
|
||||
} catch(IllegalThreadStateException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -38,6 +38,7 @@ import java.util.Arrays;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.security.AccessController;
|
||||
import static java.security.AccessController.doPrivileged;
|
||||
import java.security.PrivilegedAction;
|
||||
|
@ -212,6 +213,24 @@ final class UNIXProcess extends Process {
|
|||
return exitcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean waitFor(long timeout, TimeUnit unit)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (hasExited) return true;
|
||||
if (timeout <= 0) return false;
|
||||
|
||||
long timeoutAsNanos = unit.toNanos(timeout);
|
||||
long startTime = System.nanoTime();
|
||||
long rem = timeoutAsNanos;
|
||||
|
||||
while (!hasExited && (rem > 0)) {
|
||||
wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
|
||||
rem = timeoutAsNanos - (System.nanoTime() - startTime);
|
||||
}
|
||||
return hasExited;
|
||||
}
|
||||
|
||||
public synchronized int exitValue() {
|
||||
if (!hasExited) {
|
||||
throw new IllegalThreadStateException("process hasn't exited");
|
||||
|
@ -219,8 +238,8 @@ final class UNIXProcess extends Process {
|
|||
return exitcode;
|
||||
}
|
||||
|
||||
private static native void destroyProcess(int pid);
|
||||
public void destroy() {
|
||||
private static native void destroyProcess(int pid, boolean force);
|
||||
private void destroy(boolean force) {
|
||||
// There is a risk that pid will be recycled, causing us to
|
||||
// kill the wrong process! So we only terminate processes
|
||||
// that appear to still be running. Even with this check,
|
||||
|
@ -229,13 +248,28 @@ final class UNIXProcess extends Process {
|
|||
// soon, so this is quite safe.
|
||||
synchronized (this) {
|
||||
if (!hasExited)
|
||||
destroyProcess(pid);
|
||||
destroyProcess(pid, force);
|
||||
}
|
||||
try { stdin.close(); } catch (IOException ignored) {}
|
||||
try { stdout.close(); } catch (IOException ignored) {}
|
||||
try { stderr.close(); } catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
destroy(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process destroyForcibly() {
|
||||
destroy(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isAlive() {
|
||||
return !hasExited;
|
||||
}
|
||||
|
||||
/* This routine initializes JNI field offsets for the class */
|
||||
private static native void initIDs();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -38,6 +38,7 @@ import java.util.Arrays;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.security.AccessController;
|
||||
import static java.security.AccessController.doPrivileged;
|
||||
import java.security.PrivilegedAction;
|
||||
|
@ -212,6 +213,24 @@ final class UNIXProcess extends Process {
|
|||
return exitcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean waitFor(long timeout, TimeUnit unit)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (hasExited) return true;
|
||||
if (timeout <= 0) return false;
|
||||
|
||||
long timeoutAsNanos = unit.toNanos(timeout);
|
||||
long startTime = System.nanoTime();
|
||||
long rem = timeoutAsNanos;
|
||||
|
||||
while (!hasExited && (rem > 0)) {
|
||||
wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
|
||||
rem = timeoutAsNanos - (System.nanoTime() - startTime);
|
||||
}
|
||||
return hasExited;
|
||||
}
|
||||
|
||||
public synchronized int exitValue() {
|
||||
if (!hasExited) {
|
||||
throw new IllegalThreadStateException("process hasn't exited");
|
||||
|
@ -219,8 +238,8 @@ final class UNIXProcess extends Process {
|
|||
return exitcode;
|
||||
}
|
||||
|
||||
private static native void destroyProcess(int pid);
|
||||
public void destroy() {
|
||||
private static native void destroyProcess(int pid, boolean force);
|
||||
private void destroy(boolean force) {
|
||||
// There is a risk that pid will be recycled, causing us to
|
||||
// kill the wrong process! So we only terminate processes
|
||||
// that appear to still be running. Even with this check,
|
||||
|
@ -229,13 +248,28 @@ final class UNIXProcess extends Process {
|
|||
// soon, so this is quite safe.
|
||||
synchronized (this) {
|
||||
if (!hasExited)
|
||||
destroyProcess(pid);
|
||||
destroyProcess(pid, force);
|
||||
}
|
||||
try { stdin.close(); } catch (IOException ignored) {}
|
||||
try { stdout.close(); } catch (IOException ignored) {}
|
||||
try { stderr.close(); } catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
destroy(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process destroyForcibly() {
|
||||
destroy(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isAlive() {
|
||||
return !hasExited;
|
||||
}
|
||||
|
||||
/* This routine initializes JNI field offsets for the class */
|
||||
private static native void initIDs();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,6 +26,7 @@
|
|||
package java.lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/* java.lang.Process subclass in the UNIX environment.
|
||||
*
|
||||
|
@ -158,6 +159,24 @@ final class UNIXProcess extends Process {
|
|||
return exitcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean waitFor(long timeout, TimeUnit unit)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (hasExited) return true;
|
||||
if (timeout <= 0) return false;
|
||||
|
||||
long timeoutAsNanos = unit.toNanos(timeout);
|
||||
long startTime = System.nanoTime();
|
||||
long rem = timeoutAsNanos;
|
||||
|
||||
while (!hasExited && (rem > 0)) {
|
||||
wait(Math.max(TimeUnit.NANOSECONDS.toMillis(rem), 1));
|
||||
rem = timeoutAsNanos - (System.nanoTime() - startTime);
|
||||
}
|
||||
return hasExited;
|
||||
}
|
||||
|
||||
public synchronized int exitValue() {
|
||||
if (!hasExited) {
|
||||
throw new IllegalThreadStateException("process hasn't exited");
|
||||
|
@ -165,8 +184,8 @@ final class UNIXProcess extends Process {
|
|||
return exitcode;
|
||||
}
|
||||
|
||||
private static native void destroyProcess(int pid);
|
||||
public synchronized void destroy() {
|
||||
private static native void destroyProcess(int pid, boolean force);
|
||||
private synchronized void destroy(boolean force) {
|
||||
// There is a risk that pid will be recycled, causing us to
|
||||
// kill the wrong process! So we only terminate processes
|
||||
// that appear to still be running. Even with this check,
|
||||
|
@ -174,7 +193,7 @@ final class UNIXProcess extends Process {
|
|||
// is very small, and OSes try hard to not recycle pids too
|
||||
// soon, so this is quite safe.
|
||||
if (!hasExited)
|
||||
destroyProcess(pid);
|
||||
destroyProcess(pid, force);
|
||||
try {
|
||||
stdin_stream.close();
|
||||
if (stdout_inner_stream != null)
|
||||
|
@ -187,6 +206,21 @@ final class UNIXProcess extends Process {
|
|||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
destroy(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Process destroyForcibly() {
|
||||
destroy(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isAlive() {
|
||||
return !hasExited;
|
||||
}
|
||||
|
||||
// A FileInputStream that supports the deferment of the actual close
|
||||
// operation until the last pending I/O operation on the stream has
|
||||
// finished. This is required on Solaris because we must close the stdin
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -955,7 +955,11 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
|
|||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, jobject junk, jint pid)
|
||||
Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env,
|
||||
jobject junk,
|
||||
jint pid,
|
||||
jboolean force)
|
||||
{
|
||||
kill(pid, SIGTERM);
|
||||
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
|
||||
kill(pid, sig);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -37,6 +37,7 @@ import java.io.BufferedOutputStream;
|
|||
import java.lang.ProcessBuilder.Redirect;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/* This class is for the exclusive use of ProcessBuilder.start() to
|
||||
* create new processes.
|
||||
|
@ -254,11 +255,44 @@ final class ProcessImpl extends Process {
|
|||
throw new InterruptedException();
|
||||
return exitValue();
|
||||
}
|
||||
|
||||
private static native void waitForInterruptibly(long handle);
|
||||
|
||||
@Override
|
||||
public boolean waitFor(long timeout, TimeUnit unit)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (getExitCodeProcess(handle) != STILL_ACTIVE) return true;
|
||||
if (timeout <= 0) return false;
|
||||
|
||||
long msTimeout = unit.toMillis(timeout);
|
||||
|
||||
waitForTimeoutInterruptibly(handle, msTimeout);
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
return (getExitCodeProcess(handle) != STILL_ACTIVE);
|
||||
}
|
||||
|
||||
private static native void waitForTimeoutInterruptibly(
|
||||
long handle, long timeout);
|
||||
|
||||
public void destroy() { terminateProcess(handle); }
|
||||
|
||||
@Override
|
||||
public Process destroyForcibly() {
|
||||
destroy();
|
||||
return this;
|
||||
}
|
||||
|
||||
private static native void terminateProcess(long handle);
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return isProcessAlive(handle);
|
||||
}
|
||||
|
||||
private static native boolean isProcessAlive(long handle);
|
||||
|
||||
/**
|
||||
* Create a process using the win32 function CreateProcess.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -304,12 +304,39 @@ Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlo
|
|||
win32Error(env, "WaitForMultipleObjects");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
|
||||
jclass ignored,
|
||||
jlong handle,
|
||||
jlong timeout)
|
||||
{
|
||||
HANDLE events[2];
|
||||
DWORD dwTimeout = (DWORD)timeout;
|
||||
DWORD result;
|
||||
events[0] = (HANDLE) handle;
|
||||
events[1] = JVM_GetThreadInterruptEvent();
|
||||
result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
|
||||
FALSE, /* Wait for ANY event */
|
||||
dwTimeout); /* Wait for dwTimeout */
|
||||
|
||||
if (result == WAIT_FAILED)
|
||||
win32Error(env, "WaitForMultipleObjects");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
|
||||
{
|
||||
TerminateProcess((HANDLE) handle, 1);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
|
||||
{
|
||||
DWORD dwExitStatus;
|
||||
GetExitCodeProcess(handle, &dwExitStatus);
|
||||
return dwExitStatus == STILL_ACTIVE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
|
||||
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
|
||||
* 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
|
||||
* 4947220 7018606 7034570
|
||||
* 4947220 7018606 7034570 4244896
|
||||
* @summary Basic tests for Process and Environment Variable code
|
||||
* @run main/othervm/timeout=300 Basic
|
||||
* @author Martin Buchholz
|
||||
|
@ -38,6 +38,7 @@ import static java.lang.ProcessBuilder.Redirect.*;
|
|||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.security.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -636,6 +637,44 @@ public class Basic {
|
|||
static boolean is() { return is; }
|
||||
}
|
||||
|
||||
static class DelegatingProcess extends Process {
|
||||
final Process p;
|
||||
|
||||
DelegatingProcess(Process p) {
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int exitValue() {
|
||||
return p.exitValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int waitFor() throws InterruptedException {
|
||||
return p.waitFor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return p.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return p.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getErrorStream() {
|
||||
return p.getErrorStream();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean matches(String str, String regex) {
|
||||
return Pattern.compile(regex).matcher(str).find();
|
||||
}
|
||||
|
@ -2090,6 +2129,112 @@ public class Basic {
|
|||
policy.setPermissions(new RuntimePermission("setSecurityManager"));
|
||||
System.setSecurityManager(null);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check that Process.isAlive() &
|
||||
// Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
List<String> childArgs = new ArrayList<String>(javaChildArgs);
|
||||
childArgs.add("sleep");
|
||||
final Process p = new ProcessBuilder(childArgs).start();
|
||||
long start = System.nanoTime();
|
||||
if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) {
|
||||
fail("Test failed: Process exited prematurely");
|
||||
}
|
||||
long end = System.nanoTime();
|
||||
// give waitFor(timeout) a wide berth (100ms)
|
||||
if ((end - start) > 100000000)
|
||||
fail("Test failed: waitFor took too long");
|
||||
|
||||
p.destroy();
|
||||
p.waitFor();
|
||||
|
||||
if (p.isAlive() ||
|
||||
!p.waitFor(0, TimeUnit.MILLISECONDS))
|
||||
{
|
||||
fail("Test failed: Process still alive - please terminate " +
|
||||
p.toString() + " manually");
|
||||
}
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
|
||||
// works as expected.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
List<String> childArgs = new ArrayList<String>(javaChildArgs);
|
||||
childArgs.add("sleep");
|
||||
final Process p = new ProcessBuilder(childArgs).start();
|
||||
long start = System.nanoTime();
|
||||
|
||||
p.waitFor(1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
long end = System.nanoTime();
|
||||
if ((end - start) < 500000000)
|
||||
fail("Test failed: waitFor didn't take long enough");
|
||||
|
||||
p.destroy();
|
||||
|
||||
start = System.nanoTime();
|
||||
p.waitFor(1000, TimeUnit.MILLISECONDS);
|
||||
end = System.nanoTime();
|
||||
if ((end - start) > 100000000)
|
||||
fail("Test failed: waitFor took too long on a dead process.");
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
|
||||
// interrupt works as expected.
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
List<String> childArgs = new ArrayList<String>(javaChildArgs);
|
||||
childArgs.add("sleep");
|
||||
final Process p = new ProcessBuilder(childArgs).start();
|
||||
final long start = System.nanoTime();
|
||||
|
||||
final Thread thread = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
try {
|
||||
p.waitFor(10000, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
fail("waitFor() wasn't interrupted");
|
||||
} catch (Throwable t) { unexpected(t); }}};
|
||||
|
||||
thread.start();
|
||||
Thread.sleep(1000);
|
||||
thread.interrupt();
|
||||
p.destroy();
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Check the default implementation for
|
||||
// Process.waitFor(long, TimeUnit)
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
List<String> childArgs = new ArrayList<String>(javaChildArgs);
|
||||
childArgs.add("sleep");
|
||||
final Process proc = new ProcessBuilder(childArgs).start();
|
||||
DelegatingProcess p = new DelegatingProcess(proc);
|
||||
long start = System.nanoTime();
|
||||
|
||||
p.waitFor(1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
long end = System.nanoTime();
|
||||
if ((end - start) < 500000000)
|
||||
fail("Test failed: waitFor didn't take long enough");
|
||||
|
||||
p.destroy();
|
||||
|
||||
start = System.nanoTime();
|
||||
p.waitFor(1000, TimeUnit.MILLISECONDS);
|
||||
end = System.nanoTime();
|
||||
// allow for the less accurate default implementation
|
||||
if ((end - start) > 200000000)
|
||||
fail("Test failed: waitFor took too long on a dead process.");
|
||||
} catch (Throwable t) { unexpected(t); }
|
||||
}
|
||||
|
||||
static void closeStreams(Process p) {
|
||||
|
|
172
jdk/test/java/lang/ProcessBuilder/DestroyTest.java
Normal file
172
jdk/test/java/lang/ProcessBuilder/DestroyTest.java
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4244896
|
||||
* @summary Test for the various platform specific implementations of
|
||||
* destroyForcibly.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
abstract class ProcessTest implements Runnable {
|
||||
ProcessBuilder bldr;
|
||||
Process p;
|
||||
|
||||
public Process killProc(boolean force) throws Exception {
|
||||
if (force) {
|
||||
p.destroyForcibly();
|
||||
} else {
|
||||
p.destroy();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return p.isAlive();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
String line;
|
||||
BufferedReader is =
|
||||
new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
while ((line = is.readLine()) != null)
|
||||
System.err.println("ProcessTrap: " + line);
|
||||
} catch(IOException e) {
|
||||
if (!e.getMessage().matches("[Ss]tream [Cc]losed")) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void runTest() throws Exception;
|
||||
}
|
||||
|
||||
class UnixTest extends ProcessTest {
|
||||
public UnixTest(File script) throws IOException {
|
||||
script.deleteOnExit();
|
||||
createScript(script);
|
||||
bldr = new ProcessBuilder(script.getCanonicalPath());
|
||||
bldr.redirectErrorStream(true);
|
||||
bldr.directory(new File("."));
|
||||
p = bldr.start();
|
||||
}
|
||||
|
||||
void createScript(File processTrapScript) throws IOException {
|
||||
processTrapScript.deleteOnExit();
|
||||
FileWriter fstream = new FileWriter(processTrapScript);
|
||||
try (BufferedWriter out = new BufferedWriter(fstream)) {
|
||||
out.write("#!/bin/bash\n" +
|
||||
"echo \\\"ProcessTrap.sh started: trapping SIGTERM/SIGINT\\\"\n" +
|
||||
"trap bashtrap SIGTERM SIGINT\n" +
|
||||
"bashtrap()\n" +
|
||||
"{\n" +
|
||||
" echo \\\"SIGTERM/SIGINT detected!\\\"\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"while :\n" +
|
||||
"do\n" +
|
||||
" sleep 1;\n" +
|
||||
"done\n");
|
||||
}
|
||||
processTrapScript.setExecutable(true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest() throws Exception {
|
||||
killProc(false);
|
||||
Thread.sleep(1000);
|
||||
if (!p.isAlive())
|
||||
throw new RuntimeException("Process terminated prematurely.");
|
||||
killProc(true).waitFor();
|
||||
if (p.isAlive())
|
||||
throw new RuntimeException("Problem terminating the process.");
|
||||
}
|
||||
}
|
||||
|
||||
class MacTest extends UnixTest {
|
||||
public MacTest(File script) throws IOException {
|
||||
super(script);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest() throws Exception {
|
||||
// On Mac, it appears that when we close the processes streams
|
||||
// after a destroy() call, the process terminates with a
|
||||
// SIGPIPE even if it was trapping the SIGTERM, so as with
|
||||
// windows, we skip the trap test and go straight to destroyForcibly().
|
||||
killProc(true).waitFor();
|
||||
if (p.isAlive())
|
||||
throw new RuntimeException("Problem terminating the process.");
|
||||
}
|
||||
}
|
||||
|
||||
class WindowsTest extends ProcessTest {
|
||||
public WindowsTest() throws IOException {
|
||||
bldr = new ProcessBuilder("ftp");
|
||||
bldr.redirectErrorStream(true);
|
||||
bldr.directory(new File("."));
|
||||
p = bldr.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest() throws Exception {
|
||||
killProc(true).waitFor();
|
||||
}
|
||||
}
|
||||
|
||||
public class DestroyTest {
|
||||
|
||||
public static ProcessTest getTest() throws Exception {
|
||||
String osName = System.getProperty("os.name");
|
||||
if (osName.startsWith("Windows")) {
|
||||
return new WindowsTest();
|
||||
} else if (osName.startsWith("Linux") == true) {
|
||||
return new UnixTest(
|
||||
File.createTempFile("ProcessTrap-", ".sh",null));
|
||||
} else if (osName.startsWith("Mac OS")) {
|
||||
return new MacTest(
|
||||
File.createTempFile("ProcessTrap-", ".sh",null));
|
||||
} else if (osName.equals("SunOS")) {
|
||||
return new UnixTest(
|
||||
File.createTempFile("ProcessTrap-", ".sh",null));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
ProcessTest test = getTest();
|
||||
if (test == null) {
|
||||
throw new RuntimeException("Unrecognised OS");
|
||||
} else {
|
||||
new Thread(test).start();
|
||||
Thread.sleep(1000);
|
||||
test.runTest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue