Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
095ce48d
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
095ce48d
编写于
3月 10, 2008
作者:
M
martin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
4960438: (process) Need IO redirection API for subprocesses
Reviewed-by: alanb, iris
上级
6d73e05f
变更
12
展开全部
隐藏空白更改
内联
并排
Showing
12 changed file
with
1680 addition
and
476 deletion
+1680
-476
src/share/classes/java/lang/Process.java
src/share/classes/java/lang/Process.java
+50
-21
src/share/classes/java/lang/ProcessBuilder.java
src/share/classes/java/lang/ProcessBuilder.java
+635
-91
src/share/classes/sun/misc/JavaIOFileDescriptorAccess.java
src/share/classes/sun/misc/JavaIOFileDescriptorAccess.java
+4
-0
src/solaris/classes/java/io/FileDescriptor.java
src/solaris/classes/java/io/FileDescriptor.java
+9
-1
src/solaris/classes/java/lang/ProcessImpl.java
src/solaris/classes/java/lang/ProcessImpl.java
+58
-1
src/solaris/classes/java/lang/UNIXProcess.java.linux
src/solaris/classes/java/lang/UNIXProcess.java.linux
+105
-79
src/solaris/classes/java/lang/UNIXProcess.java.solaris
src/solaris/classes/java/lang/UNIXProcess.java.solaris
+209
-183
src/solaris/native/java/lang/UNIXProcess_md.c
src/solaris/native/java/lang/UNIXProcess_md.c
+30
-21
src/windows/classes/java/io/FileDescriptor.java
src/windows/classes/java/io/FileDescriptor.java
+19
-14
src/windows/classes/java/lang/ProcessImpl.java
src/windows/classes/java/lang/ProcessImpl.java
+121
-29
src/windows/native/java/lang/ProcessImpl_md.c
src/windows/native/java/lang/ProcessImpl_md.c
+64
-33
test/java/lang/ProcessBuilder/Basic.java
test/java/lang/ProcessBuilder/Basic.java
+376
-3
未找到文件。
src/share/classes/java/lang/Process.java
浏览文件 @
095ce48d
...
...
@@ -41,18 +41,24 @@ import java.io.*;
* <p>The methods that create processes may not work well for special
* processes on certain native platforms, such as native windowing
* processes, daemon processes, Win16/DOS processes on Microsoft
* Windows, or shell scripts. The created subprocess does not have
* its own terminal or console. All its standard I/O (i.e. stdin,
* stdout, stderr) operations will be redirected to the parent process
* through three streams
* ({@link #getOutputStream()},
* {@link #getInputStream()},
* {@link #getErrorStream()}).
* Windows, or shell scripts.
*
* <p>By default, the created subprocess does not have its own terminal
* or console. All its standard I/O (i.e. stdin, stdout, stderr)
* operations will be redirected to the parent process, where they can
* be accessed via the streams obtained using the methods
* {@link #getOutputStream()},
* {@link #getInputStream()}, and
* {@link #getErrorStream()}.
* The parent process uses these streams to feed input to and get output
* from the subprocess. Because some native platforms only provide
* limited buffer size for standard input and output streams, failure
* to promptly write the input stream or read the output stream of
* the subprocess may cause the subprocess to block, and even deadlock.
* the subprocess may cause the subprocess to block, or even deadlock.
*
* <p>Where desired, <a href="ProcessBuilder.html#redirect-input">
* subprocess I/O can also be redirected</a>
* using methods of the {@link ProcessBuilder} class.
*
* <p>The subprocess is not killed when there are no more references to
* the {@code Process} object, but rather the subprocess
...
...
@@ -62,16 +68,22 @@ import java.io.*;
* Process} object execute asynchronously or concurrently with respect
* to the Java process that owns the {@code Process} object.
*
* @author unascribed
* @see ProcessBuilder
* <p>As of 1.5, {@link ProcessBuilder#start()} is the preferred way
* to create a {@code Process}.
*
* @since JDK1.0
*/
public
abstract
class
Process
{
/**
* Returns the output stream connected to the normal input of the
* subprocess. Output to the stream is piped into the standard
* input stream of the process represented by this {@code Process}
* object.
* input of the process represented by this {@code Process} object.
*
* <p>If the standard input of the subprocess has been redirected using
* {@link ProcessBuilder#redirectInput(Redirect)
* ProcessBuilder.redirectInput}
* then this method will return a
* <a href="ProcessBuilder.html#redirect-input">null output stream</a>.
*
* <p>Implementation note: It is a good idea for the returned
* output stream to be buffered.
...
...
@@ -84,30 +96,47 @@ public abstract class Process {
/**
* Returns the input stream connected to the normal output of the
* subprocess. The stream obtains data piped from the standard
* output stream of the process represented by this {@code
* Process} object.
* output of the process represented by this {@code Process} object.
*
* <p>If the standard output of the subprocess has been redirected using
* {@link ProcessBuilder#redirectOutput(Redirect)
* ProcessBuilder.redirectOutput}
* then this method will return a
* <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
*
* <p>Otherwise, if the standard error of the subprocess has been
* redirected using
* {@link ProcessBuilder#redirectErrorStream(boolean)
* ProcessBuilder.redirectErrorStream}
* then the input stream returned by this method will receive the
* merged standard output and the standard error of the subprocess.
*
* <p>Implementation note: It is a good idea for the returned
* input stream to be buffered.
*
* @return the input stream connected to the normal output of the
* subprocess
* @see ProcessBuilder#redirectErrorStream()
*/
abstract
public
InputStream
getInputStream
();
/**
* Returns the input stream connected to the error output stream of
* the subprocess. The stream obtains data piped from the error
* output stream of the process represented by this {@code Process}
* object.
* Returns the input stream connected to the error output of the
* subprocess. The stream obtains data piped from the error output
* of the process represented by this {@code Process} object.
*
* <p>If the standard error of the subprocess has been redirected using
* {@link ProcessBuilder#redirectError(Redirect)
* ProcessBuilder.redirectError} or
* {@link ProcessBuilder#redirectErrorStream(boolean)
* ProcessBuilder.redirectErrorStream}
* then this method will return a
* <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
*
* <p>Implementation note: It is a good idea for the returned
* input stream to be buffered.
*
* @return the input stream connected to the error output
stream
of
* @return the input stream connected to the error output of
* the subprocess
* @see ProcessBuilder#redirectErrorStream()
*/
abstract
public
InputStream
getErrorStream
();
...
...
src/share/classes/java/lang/ProcessBuilder.java
浏览文件 @
095ce48d
此差异已折叠。
点击以展开。
src/share/classes/sun/misc/JavaIOFileDescriptorAccess.java
浏览文件 @
095ce48d
...
...
@@ -33,4 +33,8 @@ import java.io.FileDescriptor;
public
interface
JavaIOFileDescriptorAccess
{
public
void
set
(
FileDescriptor
obj
,
int
fd
);
public
int
get
(
FileDescriptor
fd
);
// Only valid on Windows
public
void
setHandle
(
FileDescriptor
obj
,
long
handle
);
public
long
getHandle
(
FileDescriptor
obj
);
}
src/solaris/classes/java/io/FileDescriptor.java
浏览文件 @
095ce48d
...
...
@@ -152,11 +152,19 @@ public final class FileDescriptor {
public
int
get
(
FileDescriptor
obj
)
{
return
obj
.
fd
;
}
public
void
setHandle
(
FileDescriptor
obj
,
long
handle
)
{
throw
new
UnsupportedOperationException
();
}
public
long
getHandle
(
FileDescriptor
obj
)
{
throw
new
UnsupportedOperationException
();
}
}
);
}
// pac
akge private methods used by FIS,
FOS and RAF
// pac
kage private methods used by FIS,
FOS and RAF
int
incrementAndGetUseCount
()
{
return
useCount
.
incrementAndGet
();
...
...
src/solaris/classes/java/lang/ProcessImpl.java
浏览文件 @
095ce48d
...
...
@@ -26,7 +26,10 @@
package
java.lang
;
import
java.io.IOException
;
import
java.lang.Process
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.lang.ProcessBuilder.Redirect
;
import
java.lang.ProcessBuilder.Redirect
;
/**
* This class is for the exclusive use of ProcessBuilder.start() to
...
...
@@ -36,6 +39,9 @@ import java.lang.Process;
* @since 1.5
*/
final
class
ProcessImpl
{
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
();
private
ProcessImpl
()
{}
// Not instantiable
private
static
byte
[]
toCString
(
String
s
)
{
...
...
@@ -54,6 +60,7 @@ final class ProcessImpl {
static
Process
start
(
String
[]
cmdarray
,
java
.
util
.
Map
<
String
,
String
>
environment
,
String
dir
,
ProcessBuilder
.
Redirect
[]
redirects
,
boolean
redirectErrorStream
)
throws
IOException
{
...
...
@@ -78,11 +85,61 @@ final class ProcessImpl {
int
[]
envc
=
new
int
[
1
];
byte
[]
envBlock
=
ProcessEnvironment
.
toEnvironmentBlock
(
environment
,
envc
);
int
[]
std_fds
;
FileInputStream
f0
=
null
;
FileOutputStream
f1
=
null
;
FileOutputStream
f2
=
null
;
try
{
if
(
redirects
==
null
)
{
std_fds
=
new
int
[]
{
-
1
,
-
1
,
-
1
};
}
else
{
std_fds
=
new
int
[
3
];
if
(
redirects
[
0
]
==
Redirect
.
PIPE
)
std_fds
[
0
]
=
-
1
;
else
if
(
redirects
[
0
]
==
Redirect
.
INHERIT
)
std_fds
[
0
]
=
0
;
else
{
f0
=
new
FileInputStream
(
redirects
[
0
].
file
());
std_fds
[
0
]
=
fdAccess
.
get
(
f0
.
getFD
());
}
if
(
redirects
[
1
]
==
Redirect
.
PIPE
)
std_fds
[
1
]
=
-
1
;
else
if
(
redirects
[
1
]
==
Redirect
.
INHERIT
)
std_fds
[
1
]
=
1
;
else
{
f1
=
redirects
[
1
].
toFileOutputStream
();
std_fds
[
1
]
=
fdAccess
.
get
(
f1
.
getFD
());
}
if
(
redirects
[
2
]
==
Redirect
.
PIPE
)
std_fds
[
2
]
=
-
1
;
else
if
(
redirects
[
2
]
==
Redirect
.
INHERIT
)
std_fds
[
2
]
=
2
;
else
{
f2
=
redirects
[
2
].
toFileOutputStream
();
std_fds
[
2
]
=
fdAccess
.
get
(
f2
.
getFD
());
}
}
return
new
UNIXProcess
(
toCString
(
cmdarray
[
0
]),
argBlock
,
args
.
length
,
envBlock
,
envc
[
0
],
toCString
(
dir
),
std_fds
,
redirectErrorStream
);
}
finally
{
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
try
{
if
(
f0
!=
null
)
f0
.
close
();
}
finally
{
try
{
if
(
f1
!=
null
)
f1
.
close
();
}
finally
{
if
(
f2
!=
null
)
f2
.
close
();
}
}
}
}
}
src/solaris/classes/java/lang/UNIXProcess.java.linux
浏览文件 @
095ce48d
/*
*
Copyright
1995
-
200
6
Sun
Microsystems
,
Inc
.
All
Rights
Reserved
.
/*
*
Copyright
1995
-
200
8
Sun
Microsystems
,
Inc
.
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
...
...
@@ -34,9 +34,9 @@ import java.io.*;
*/
final
class
UNIXProcess
extends
Process
{
private
FileDescriptor
stdin_fd
;
private
FileDescriptor
stdout_fd
;
private
FileDescriptor
stderr_fd
;
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
()
;
private
int
pid
;
private
int
exitcode
;
private
boolean
hasExited
;
...
...
@@ -48,15 +48,26 @@ final class UNIXProcess extends Process {
/*
this
is
for
the
reaping
thread
*/
private
native
int
waitForProcessExit
(
int
pid
);
/**
*
Create
a
process
using
fork
(
2
)
and
exec
(
2
).
*
*
@
param
std_fds
array
of
file
descriptors
.
Indexes
0
,
1
,
and
*
2
correspond
to
standard
input
,
standard
output
and
*
standard
error
,
respectively
.
On
input
,
a
value
of
-
1
*
means
to
create
a
pipe
to
connect
child
and
parent
*
processes
.
On
output
,
a
value
which
is
not
-
1
is
the
*
parent
pipe
fd
corresponding
to
the
pipe
which
has
*
been
created
.
An
element
of
this
array
is
-
1
on
input
*
if
and
only
if
it
is
<
em
>
not
</
em
>
-
1
on
output
.
*
@
return
the
pid
of
the
subprocess
*/
private
native
int
forkAndExec
(
byte
[]
prog
,
byte
[]
argBlock
,
int
argc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
dir
,
boolean
redirectErrorStream
,
FileDescriptor
stdin_fd
,
FileDescriptor
stdout_fd
,
FileDescriptor
stderr_fd
)
throws
IOException
;
byte
[]
argBlock
,
int
argc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
dir
,
int
[]
std_fds
,
boolean
redirectErrorStream
)
throws
IOException
;
/*
In
the
process
constructor
we
wait
on
this
gate
until
the
process
*/
/*
has
been
created
.
Then
we
return
from
the
constructor
.
*/
...
...
@@ -97,67 +108,82 @@ final class UNIXProcess extends Process {
}
UNIXProcess
(
final
byte
[]
prog
,
final
byte
[]
argBlock
,
final
int
argc
,
final
byte
[]
envBlock
,
final
int
envc
,
final
byte
[]
dir
,
final
boolean
redirectErrorStream
)
final
byte
[]
argBlock
,
final
int
argc
,
final
byte
[]
envBlock
,
final
int
envc
,
final
byte
[]
dir
,
final
int
[]
std_fds
,
final
boolean
redirectErrorStream
)
throws
IOException
{
stdin_fd
=
new
FileDescriptor
();
stdout_fd
=
new
FileDescriptor
();
stderr_fd
=
new
FileDescriptor
();
final
Gate
gate
=
new
Gate
();
/*
*
For
each
subprocess
forked
a
corresponding
reaper
thread
*
is
started
.
That
thread
is
the
only
thread
which
waits
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
* locks while doing so. This design allows waitFor() and
* exitStatus() to be safely executed in parallel (and they
* need no native code).
*/
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction
() {
public Object
run() {
Thread t = new Thread("process reaper") {
public void run() {
/*
*
For
each
subprocess
forked
a
corresponding
reaper
thread
*
is
started
.
That
thread
is
the
only
thread
which
waits
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
* locks while doing so. This design allows waitFor() and
* exitStatus() to be safely executed in parallel (and they
* need no native code).
*/
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>
() {
public Void
run() {
Thread t = new Thread("process reaper") {
public void run() {
try {
pid = forkAndExec(prog,
argBlock, argc,
envBlock, envc,
dir,
redirectErrorStream
,
stdin_fd, stdout_fd, stderr_fd
);
argBlock, argc,
envBlock, envc,
dir,
std_fds
,
redirectErrorStream
);
} catch (IOException e) {
gate.setException(e); /*remember to rethrow later*/
gate.exit();
return;
}
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
stdin_stream = new BufferedOutputStream(new
FileOutputStream(stdin_fd));
stdout_stream = new BufferedInputStream(new
FileInputStream(stdout_fd));
new java.security.PrivilegedAction<Void>() {
public Void run() {
if (std_fds[0] == -1)
stdin_stream = new ProcessBuilder.NullOutputStream();
else {
FileDescriptor stdin_fd = new FileDescriptor();
fdAccess.set(stdin_fd, std_fds[0]);
stdin_stream = new BufferedOutputStream(
new FileOutputStream(stdin_fd));
}
if (std_fds[1] == -1)
stdout_stream = new ProcessBuilder.NullInputStream();
else {
FileDescriptor stdout_fd = new FileDescriptor();
fdAccess.set(stdout_fd, std_fds[1]);
stdout_stream = new BufferedInputStream(
new FileInputStream(stdout_fd));
}
if (std_fds[2] == -1)
stderr_stream = new ProcessBuilder.NullInputStream();
else {
FileDescriptor stderr_fd = new FileDescriptor();
fdAccess.set(stderr_fd, std_fds[2]);
stderr_stream = new FileInputStream(stderr_fd);
return null;
}
});
return null; }});
gate.exit(); /* exit from constructor */
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
hasExited = true;
exitcode = res;
UNIXProcess.this.notifyAll();
}
}
};
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
hasExited = true;
exitcode = res;
UNIXProcess.this.notifyAll();
}
}
};
t.setDaemon(true);
t.start();
return null;
}
});
return null; }});
gate.waitForExit();
IOException e = gate.getException();
if (e != null)
...
...
@@ -165,43 +191,43 @@ final class UNIXProcess extends Process {
}
public OutputStream getOutputStream() {
return stdin_stream;
return stdin_stream;
}
public InputStream getInputStream() {
return stdout_stream;
return stdout_stream;
}
public InputStream getErrorStream() {
return stderr_stream;
return stderr_stream;
}
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
wait();
}
return exitcode;
wait();
}
return exitcode;
}
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn'
t
exited
");
}
return exitcode;
if (!hasExited) {
throw new IllegalThreadStateException("process hasn'
t
exited
");
}
return exitcode;
}
private static native void destroyProcess(int pid);
public void destroy() {
// 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,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
destroyProcess(pid);
}
// 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,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
destroyProcess(pid);
}
try {
stdin_stream.close();
stdout_stream.close();
...
...
@@ -215,6 +241,6 @@ final class UNIXProcess extends Process {
private static native void initIDs();
static {
initIDs();
initIDs();
}
}
src/solaris/classes/java/lang/UNIXProcess.java.solaris
浏览文件 @
095ce48d
/*
*
Copyright
1995
-
200
6
Sun
Microsystems
,
Inc
.
All
Rights
Reserved
.
/*
*
Copyright
1995
-
200
8
Sun
Microsystems
,
Inc
.
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
...
...
@@ -33,129 +33,155 @@ import java.io.*;
*/
final
class
UNIXProcess
extends
Process
{
private
FileDescriptor
stdin_fd
;
private
FileDescriptor
stdout_fd
;
private
FileDescriptor
stderr_fd
;
private
int
pid
;
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
()
;
private
final
int
pid
;
private
int
exitcode
;
private
boolean
hasExited
;
private
OutputStream
stdin_stream
;
private
Buffered
InputStream
stdout_stream
;
private
InputStream
stdout_stream
;
private
DeferredCloseInputStream
stdout_inner_stream
;
private
DeferredClose
InputStream
stderr_stream
;
private
InputStream
stderr_stream
;
/*
this
is
for
the
reaping
thread
*/
private
native
int
waitForProcessExit
(
int
pid
);
/**
*
Create
a
process
using
fork
(
2
)
and
exec
(
2
).
*
*
@
param
std_fds
array
of
file
descriptors
.
Indexes
0
,
1
,
and
*
2
correspond
to
standard
input
,
standard
output
and
*
standard
error
,
respectively
.
On
input
,
a
value
of
-
1
*
means
to
create
a
pipe
to
connect
child
and
parent
*
processes
.
On
output
,
a
value
which
is
not
-
1
is
the
*
parent
pipe
fd
corresponding
to
the
pipe
which
has
*
been
created
.
An
element
of
this
array
is
-
1
on
input
*
if
and
only
if
it
is
<
em
>
not
</
em
>
-
1
on
output
.
*
@
return
the
pid
of
the
subprocess
*/
private
native
int
forkAndExec
(
byte
[]
prog
,
byte
[]
argBlock
,
int
argc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
dir
,
boolean
redirectErrorStream
,
FileDescriptor
stdin_fd
,
FileDescriptor
stdout_fd
,
FileDescriptor
stderr_fd
)
throws
IOException
;
byte
[]
argBlock
,
int
argc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
dir
,
int
[]
std_fds
,
boolean
redirectErrorStream
)
throws
IOException
;
UNIXProcess
(
final
byte
[]
prog
,
final
byte
[]
argBlock
,
int
argc
,
final
byte
[]
envBlock
,
int
envc
,
final
byte
[]
dir
,
final
boolean
redirectErrorStream
)
final
byte
[]
argBlock
,
int
argc
,
final
byte
[]
envBlock
,
int
envc
,
final
byte
[]
dir
,
final
int
[]
std_fds
,
final
boolean
redirectErrorStream
)
throws
IOException
{
stdin_fd
=
new
FileDescriptor
();
stdout_fd
=
new
FileDescriptor
();
stderr_fd
=
new
FileDescriptor
();
pid
=
forkAndExec
(
prog
,
argBlock
,
argc
,
envBlock
,
envc
,
dir
,
redirectErrorStream
,
stdin_fd
,
stdout_fd
,
stderr_fd
);
java
.
security
.
AccessController
.
doPrivileged
(
new
java
.
security
.
PrivilegedAction
()
{
public
Object
run
()
{
stdin_stream
=
new
BufferedOutputStream
(
new
FileOutputStream
(
stdin_fd
));
stdout_inner_stream
=
new
DeferredCloseInputStream
(
stdout_fd
);
stdout_stream
=
new
BufferedInputStream
(
stdout_inner_stream
);
stderr_stream
=
new
DeferredCloseInputStream
(
stderr_fd
);
return
null
;
}
});
/*
*
For
each
subprocess
forked
a
corresponding
reaper
thread
*
is
started
.
That
thread
is
the
only
thread
which
waits
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
* locks while doing so. This design allows waitFor() and
* exitStatus() to be safely executed in parallel (and they
* need no native code).
*/
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
Thread t = new Thread("process reaper") {
public void run() {
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
hasExited = true;
exitcode = res;
UNIXProcess.this.notifyAll();
}
}
};
t.setDaemon(true);
t.start();
return null;
}
});
pid
=
forkAndExec
(
prog
,
argBlock
,
argc
,
envBlock
,
envc
,
dir
,
std_fds
,
redirectErrorStream
);
java
.
security
.
AccessController
.
doPrivileged
(
new
java
.
security
.
PrivilegedAction
<
Void
>()
{
public
Void
run
()
{
if
(
std_fds
[
0
]
==
-
1
)
stdin_stream
=
new
ProcessBuilder
.
NullOutputStream
();
else
{
FileDescriptor
stdin_fd
=
new
FileDescriptor
();
fdAccess
.
set
(
stdin_fd
,
std_fds
[
0
]);
stdin_stream
=
new
BufferedOutputStream
(
new
FileOutputStream
(
stdin_fd
));
}
if
(
std_fds
[
1
]
==
-
1
)
stdout_stream
=
new
ProcessBuilder
.
NullInputStream
();
else
{
FileDescriptor
stdout_fd
=
new
FileDescriptor
();
fdAccess
.
set
(
stdout_fd
,
std_fds
[
1
]);
stdout_inner_stream
=
new
DeferredCloseInputStream
(
stdout_fd
);
stdout_stream
=
new
BufferedInputStream
(
stdout_inner_stream
);
}
if
(
std_fds
[
2
]
==
-
1
)
stderr_stream
=
new
ProcessBuilder
.
NullInputStream
();
else
{
FileDescriptor
stderr_fd
=
new
FileDescriptor
();
fdAccess
.
set
(
stderr_fd
,
std_fds
[
2
]);
stderr_stream
=
new
DeferredCloseInputStream
(
stderr_fd
);
}
return
null
;
}});
/*
*
For
each
subprocess
forked
a
corresponding
reaper
thread
*
is
started
.
That
thread
is
the
only
thread
which
waits
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
* locks while doing so. This design allows waitFor() and
* exitStatus() to be safely executed in parallel (and they
* need no native code).
*/
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() { public Void run() {
Thread t = new Thread("process reaper") {
public void run() {
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
hasExited = true;
exitcode = res;
UNIXProcess.this.notifyAll();
}
}
};
t.setDaemon(true);
t.start();
return null; }});
}
public OutputStream getOutputStream() {
return stdin_stream;
return stdin_stream;
}
public InputStream getInputStream() {
return stdout_stream;
return stdout_stream;
}
public InputStream getErrorStream() {
return stderr_stream;
return stderr_stream;
}
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
wait();
}
return exitcode;
wait();
}
return exitcode;
}
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn'
t
exited
");
}
return exitcode;
if (!hasExited) {
throw new IllegalThreadStateException("process hasn'
t
exited
");
}
return exitcode;
}
private static native void destroyProcess(int pid);
public synchronized void destroy() {
// 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,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
if (!hasExited)
destroyProcess(pid);
try {
// 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,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
if (!hasExited)
destroyProcess(pid);
try {
stdin_stream.close();
stdout_inner_stream.closeDeferred(stdout_stream);
stderr_stream.closeDeferred(stderr_stream);
if (stdout_inner_stream != null)
stdout_inner_stream.closeDeferred(stdout_stream);
if (stderr_stream instanceof DeferredCloseInputStream)
((DeferredCloseInputStream) stderr_stream)
.closeDeferred(stderr_stream);
} catch (IOException e) {
// ignore
}
...
...
@@ -172,99 +198,99 @@ final class UNIXProcess extends Process {
// (EOF) as they did before.
//
private static class DeferredCloseInputStream
extends FileInputStream
extends FileInputStream
{
private DeferredCloseInputStream(FileDescriptor fd) {
super(fd);
}
private Object lock = new Object();
// For the following fields
private boolean closePending = false;
private int useCount = 0;
private InputStream streamToClose;
private void raise() {
synchronized (lock) {
useCount++;
}
}
private void lower() throws IOException {
synchronized (lock) {
useCount--;
if (useCount == 0 && closePending) {
streamToClose.close();
}
}
}
// stc is the actual stream to be closed; it might be this object, or
// it might be an upstream object for which this object is downstream.
//
private void closeDeferred(InputStream stc) throws IOException {
synchronized (lock) {
if (useCount == 0) {
stc.close();
} else {
closePending = true;
streamToClose = stc;
}
}
}
public void close() throws IOException {
synchronized (lock) {
useCount = 0;
closePending = false;
}
super.close();
}
public int read() throws IOException {
raise();
try {
return super.read();
} finally {
lower();
}
}
public int read(byte[] b) throws IOException {
raise();
try {
return super.read(b);
} finally {
lower();
}
}
public int read(byte[] b, int off, int len) throws IOException {
raise();
try {
return super.read(b, off, len);
} finally {
lower();
}
}
public long skip(long n) throws IOException {
raise();
try {
return super.skip(n);
} finally {
lower();
}
}
public int available() throws IOException {
raise();
try {
return super.available();
} finally {
lower();
}
}
private DeferredCloseInputStream(FileDescriptor fd) {
super(fd);
}
private Object lock = new Object();
// For the following fields
private boolean closePending = false;
private int useCount = 0;
private InputStream streamToClose;
private void raise() {
synchronized (lock) {
useCount++;
}
}
private void lower() throws IOException {
synchronized (lock) {
useCount--;
if (useCount == 0 && closePending) {
streamToClose.close();
}
}
}
// stc is the actual stream to be closed; it might be this object, or
// it might be an upstream object for which this object is downstream.
//
private void closeDeferred(InputStream stc) throws IOException {
synchronized (lock) {
if (useCount == 0) {
stc.close();
} else {
closePending = true;
streamToClose = stc;
}
}
}
public void close() throws IOException {
synchronized (lock) {
useCount = 0;
closePending = false;
}
super.close();
}
public int read() throws IOException {
raise();
try {
return super.read();
} finally {
lower();
}
}
public int read(byte[] b) throws IOException {
raise();
try {
return super.read(b);
} finally {
lower();
}
}
public int read(byte[] b, int off, int len) throws IOException {
raise();
try {
return super.read(b, off, len);
} finally {
lower();
}
}
public long skip(long n) throws IOException {
raise();
try {
return super.skip(n);
} finally {
lower();
}
}
public int available() throws IOException {
raise();
try {
return super.available();
} finally {
lower();
}
}
}
...
...
@@ -272,6 +298,6 @@ final class UNIXProcess extends Process {
private static native void initIDs();
static {
initIDs();
initIDs();
}
}
src/solaris/native/java/lang/UNIXProcess_md.c
浏览文件 @
095ce48d
/*
* Copyright 1995-200
6
Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1995-200
8
Sun Microsystems, Inc. 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
...
...
@@ -491,10 +491,8 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
jbyteArray
argBlock
,
jint
argc
,
jbyteArray
envBlock
,
jint
envc
,
jbyteArray
dir
,
jboolean
redirectErrorStream
,
jobject
stdin_fd
,
jobject
stdout_fd
,
jobject
stderr_fd
)
jintArray
std_fds
,
jboolean
redirectErrorStream
)
{
int
errnum
;
int
resultPid
=
-
1
;
...
...
@@ -505,6 +503,7 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
const
char
*
pargBlock
=
getBytes
(
env
,
argBlock
);
const
char
*
penvBlock
=
getBytes
(
env
,
envBlock
);
const
char
*
pdir
=
getBytes
(
env
,
dir
);
jint
*
fds
=
NULL
;
in
[
0
]
=
in
[
1
]
=
out
[
0
]
=
out
[
1
]
=
err
[
0
]
=
err
[
1
]
=
fail
[
0
]
=
fail
[
1
]
=
-
1
;
...
...
@@ -527,9 +526,13 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
initVectorFromBlock
(
envv
,
penvBlock
,
envc
);
}
if
((
pipe
(
in
)
<
0
)
||
(
pipe
(
out
)
<
0
)
||
(
pipe
(
err
)
<
0
)
||
assert
(
std_fds
!=
NULL
);
fds
=
(
*
env
)
->
GetIntArrayElements
(
env
,
std_fds
,
NULL
);
if
(
fds
==
NULL
)
goto
Catch
;
if
((
fds
[
0
]
==
-
1
&&
pipe
(
in
)
<
0
)
||
(
fds
[
1
]
==
-
1
&&
pipe
(
out
)
<
0
)
||
(
fds
[
2
]
==
-
1
&&
pipe
(
err
)
<
0
)
||
(
pipe
(
fail
)
<
0
))
{
throwIOException
(
env
,
errno
,
"Bad file descriptor"
);
goto
Catch
;
...
...
@@ -544,23 +547,26 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
if
(
resultPid
==
0
)
{
/* Child process */
/* Close the parent sides of the pipe.
Give the child sides of the pipes the right fileno's.
/* Close the parent sides of the pipes.
Closing pipe fds here is redundant, since closeDescriptors()
would do it anyways, but a little paranoia is a good thing. */
closeSafely
(
in
[
1
]);
closeSafely
(
out
[
0
]);
closeSafely
(
err
[
0
]);
closeSafely
(
fail
[
0
]);
/* Give the child sides of the pipes the right fileno's. */
/* Note: it is possible for in[0] == 0 */
close
(
in
[
1
]);
moveDescriptor
(
in
[
0
],
STDIN_FILENO
);
close
(
out
[
0
]);
moveDescriptor
(
out
[
1
],
STDOUT_FILENO
);
close
(
err
[
0
]);
moveDescriptor
(
in
[
0
]
!=
-
1
?
in
[
0
]
:
fds
[
0
],
STDIN_FILENO
);
moveDescriptor
(
out
[
1
]
!=
-
1
?
out
[
1
]
:
fds
[
1
],
STDOUT_FILENO
);
if
(
redirectErrorStream
)
{
close
(
err
[
1
]);
close
Safely
(
err
[
1
]);
dup2
(
STDOUT_FILENO
,
STDERR_FILENO
);
}
else
{
moveDescriptor
(
err
[
1
],
STDERR_FILENO
);
moveDescriptor
(
err
[
1
]
!=
-
1
?
err
[
1
]
:
fds
[
2
]
,
STDERR_FILENO
);
}
close
(
fail
[
0
]);
moveDescriptor
(
fail
[
1
],
FAIL_FILENO
);
/* close everything */
...
...
@@ -606,9 +612,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
goto
Catch
;
}
(
*
env
)
->
SetIntField
(
env
,
stdin_fd
,
IO_fd_fdID
,
in
[
1
])
;
(
*
env
)
->
SetIntField
(
env
,
stdout_fd
,
IO_fd_fdID
,
out
[
0
])
;
(
*
env
)
->
SetIntField
(
env
,
stderr_fd
,
IO_fd_fdID
,
err
[
0
])
;
fds
[
0
]
=
(
in
[
1
]
!=
-
1
)
?
in
[
1
]
:
-
1
;
fds
[
1
]
=
(
out
[
0
]
!=
-
1
)
?
out
[
0
]
:
-
1
;
fds
[
2
]
=
(
err
[
0
]
!=
-
1
)
?
err
[
0
]
:
-
1
;
Finally:
/* Always clean up the child's side of the pipes */
...
...
@@ -628,6 +634,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
releaseBytes
(
env
,
envBlock
,
penvBlock
);
releaseBytes
(
env
,
dir
,
pdir
);
if
(
fds
!=
NULL
)
(
*
env
)
->
ReleaseIntArrayElements
(
env
,
std_fds
,
fds
,
0
);
return
resultPid
;
Catch:
...
...
src/windows/classes/java/io/FileDescriptor.java
浏览文件 @
095ce48d
...
...
@@ -29,17 +29,14 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Instances of the file descriptor class serve as an opaque handle
* to the underlying machine-specific structure representing an open
* file, an open socket, or another source or sink of bytes. The
* main practical use for a file descriptor is to create a
* <code>FileInputStream</code> or <code>FileOutputStream</code> to
* contain it.
* <p>
* Applications should not create their own file descriptors.
* to the underlying machine-specific structure representing an
* open file, an open socket, or another source or sink of bytes.
* The main practical use for a file descriptor is to create a
* {@link FileInputStream} or {@link FileOutputStream} to contain it.
*
* <p>Applications should not create their own file descriptors.
*
* @author Pavani Diwanji
* @see java.io.FileInputStream
* @see java.io.FileOutputStream
* @since JDK1.0
*/
public
final
class
FileDescriptor
{
...
...
@@ -81,6 +78,14 @@ public final class FileDescriptor {
public
int
get
(
FileDescriptor
obj
)
{
return
obj
.
fd
;
}
public
void
setHandle
(
FileDescriptor
obj
,
long
handle
)
{
obj
.
handle
=
handle
;
}
public
long
getHandle
(
FileDescriptor
obj
)
{
return
obj
.
handle
;
}
}
);
}
...
...
@@ -88,7 +93,7 @@ public final class FileDescriptor {
/**
* A handle to the standard input stream. Usually, this file
* descriptor is not used directly, but rather via the input stream
* known as
<code>System.in</code>
.
* known as
{@code System.in}
.
*
* @see java.lang.System#in
*/
...
...
@@ -97,7 +102,7 @@ public final class FileDescriptor {
/**
* A handle to the standard output stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* known as
<code>System.out</code>
.
* known as
{@code System.out}
.
* @see java.lang.System#out
*/
public
static
final
FileDescriptor
out
=
standardStream
(
1
);
...
...
@@ -105,7 +110,7 @@ public final class FileDescriptor {
/**
* A handle to the standard error stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* known as
<code>System.err</code>
.
* known as
{@code System.err}
.
*
* @see java.lang.System#err
*/
...
...
@@ -114,9 +119,9 @@ public final class FileDescriptor {
/**
* Tests if this file descriptor object is valid.
*
* @return
<code>true</code>
if the file descriptor object represents a
* @return
{@code true}
if the file descriptor object represents a
* valid, open file, socket, or other active I/O connection;
*
<code>false</code>
otherwise.
*
{@code false}
otherwise.
*/
public
boolean
valid
()
{
return
((
handle
!=
-
1
)
||
(
fd
!=
-
1
));
...
...
src/windows/classes/java/lang/ProcessImpl.java
浏览文件 @
095ce48d
...
...
@@ -25,7 +25,16 @@
package
java.lang
;
import
java.io.*
;
import
java.io.IOException
;
import
java.io.File
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.FileDescriptor
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedOutputStream
;
import
java.lang.ProcessBuilder.Redirect
;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
...
...
@@ -35,30 +44,82 @@ import java.io.*;
*/
final
class
ProcessImpl
extends
Process
{
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
();
// System-dependent portion of ProcessBuilder.start()
static
Process
start
(
String
cmdarray
[],
java
.
util
.
Map
<
String
,
String
>
environment
,
String
dir
,
ProcessBuilder
.
Redirect
[]
redirects
,
boolean
redirectErrorStream
)
throws
IOException
{
String
envblock
=
ProcessEnvironment
.
toEnvironmentBlock
(
environment
);
return
new
ProcessImpl
(
cmdarray
,
envblock
,
dir
,
redirectErrorStream
);
FileInputStream
f0
=
null
;
FileOutputStream
f1
=
null
;
FileOutputStream
f2
=
null
;
try
{
long
[]
stdHandles
;
if
(
redirects
==
null
)
{
stdHandles
=
new
long
[]
{
-
1L
,
-
1L
,
-
1L
};
}
else
{
stdHandles
=
new
long
[
3
];
if
(
redirects
[
0
]
==
Redirect
.
PIPE
)
stdHandles
[
0
]
=
-
1L
;
else
if
(
redirects
[
0
]
==
Redirect
.
INHERIT
)
stdHandles
[
0
]
=
fdAccess
.
getHandle
(
FileDescriptor
.
in
);
else
{
f0
=
new
FileInputStream
(
redirects
[
0
].
file
());
stdHandles
[
0
]
=
fdAccess
.
getHandle
(
f0
.
getFD
());
}
if
(
redirects
[
1
]
==
Redirect
.
PIPE
)
stdHandles
[
1
]
=
-
1L
;
else
if
(
redirects
[
1
]
==
Redirect
.
INHERIT
)
stdHandles
[
1
]
=
fdAccess
.
getHandle
(
FileDescriptor
.
out
);
else
{
f1
=
redirects
[
1
].
toFileOutputStream
();
stdHandles
[
1
]
=
fdAccess
.
getHandle
(
f1
.
getFD
());
}
if
(
redirects
[
2
]
==
Redirect
.
PIPE
)
stdHandles
[
2
]
=
-
1L
;
else
if
(
redirects
[
2
]
==
Redirect
.
INHERIT
)
stdHandles
[
2
]
=
fdAccess
.
getHandle
(
FileDescriptor
.
err
);
else
{
f2
=
redirects
[
2
].
toFileOutputStream
();
stdHandles
[
2
]
=
fdAccess
.
getHandle
(
f2
.
getFD
());
}
}
return
new
ProcessImpl
(
cmdarray
,
envblock
,
dir
,
stdHandles
,
redirectErrorStream
);
}
finally
{
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
try
{
if
(
f0
!=
null
)
f0
.
close
();
}
finally
{
try
{
if
(
f1
!=
null
)
f1
.
close
();
}
finally
{
if
(
f2
!=
null
)
f2
.
close
();
}
}
}
}
private
long
handle
=
0
;
private
FileDescriptor
stdin_fd
;
private
FileDescriptor
stdout_fd
;
private
FileDescriptor
stderr_fd
;
private
OutputStream
stdin_stream
;
private
InputStream
stdout_stream
;
private
InputStream
stderr_stream
;
private
ProcessImpl
(
String
cmd
[],
String
envblock
,
String
path
,
boolean
redirectErrorStream
)
private
ProcessImpl
(
final
String
cmd
[],
final
String
envblock
,
final
String
path
,
final
long
[]
stdHandles
,
final
boolean
redirectErrorStream
)
throws
IOException
{
// Win32 CreateProcess requires cmd[0] to be normalized
...
...
@@ -91,25 +152,39 @@ final class ProcessImpl extends Process {
}
String
cmdstr
=
cmdbuf
.
toString
();
stdin_fd
=
new
FileDescriptor
();
stdout_fd
=
new
FileDescriptor
();
stderr_fd
=
new
FileDescriptor
();
handle
=
create
(
cmdstr
,
envblock
,
path
,
redirectErrorStream
,
stdin_fd
,
stdout_fd
,
stderr_fd
);
handle
=
create
(
cmdstr
,
envblock
,
path
,
stdHandles
,
redirectErrorStream
);
java
.
security
.
AccessController
.
doPrivileged
(
new
java
.
security
.
PrivilegedAction
()
{
public
Object
run
()
{
stdin_stream
=
new
BufferedOutputStream
(
new
FileOutputStream
(
stdin_fd
)
);
stdout_stream
=
new
BufferedInputStream
(
new
FileInputStream
(
stdout_fd
)
);
stderr_stream
=
new
FileInputStream
(
stderr_fd
);
return
null
;
new
java
.
security
.
PrivilegedAction
<
Void
>
()
{
public
Void
run
()
{
if
(
stdHandles
[
0
]
==
-
1L
)
stdin_stream
=
new
ProcessBuilder
.
NullOutputStream
(
);
else
{
FileDescriptor
stdin_fd
=
new
FileDescriptor
(
);
fdAccess
.
setHandle
(
stdin_fd
,
stdHandles
[
0
]);
stdin_stream
=
new
BufferedOutputStream
(
new
FileOutputStream
(
stdin_fd
))
;
}
});
if
(
stdHandles
[
1
]
==
-
1L
)
stdout_stream
=
new
ProcessBuilder
.
NullInputStream
();
else
{
FileDescriptor
stdout_fd
=
new
FileDescriptor
();
fdAccess
.
setHandle
(
stdout_fd
,
stdHandles
[
1
]);
stdout_stream
=
new
BufferedInputStream
(
new
FileInputStream
(
stdout_fd
));
}
if
(
stdHandles
[
2
]
==
-
1L
)
stderr_stream
=
new
ProcessBuilder
.
NullInputStream
();
else
{
FileDescriptor
stderr_fd
=
new
FileDescriptor
();
fdAccess
.
setHandle
(
stderr_fd
,
stdHandles
[
2
]);
stderr_stream
=
new
FileInputStream
(
stderr_fd
);
}
return
null
;
}});
}
public
OutputStream
getOutputStream
()
{
...
...
@@ -150,13 +225,30 @@ final class ProcessImpl extends Process {
public
void
destroy
()
{
terminateProcess
(
handle
);
}
private
static
native
void
terminateProcess
(
long
handle
);
/**
* Create a process using the win32 function CreateProcess.
*
* @param cmdstr the Windows commandline
* @param envblock NUL-separated, double-NUL-terminated list of
* environment strings in VAR=VALUE form
* @param dir the working directory of the process, or null if
* inheriting the current directory from the parent process
* @param stdHandles array of windows HANDLEs. Indexes 0, 1, and
* 2 correspond to standard input, standard output and
* standard error, respectively. On input, a value of -1
* means to create a pipe to connect child and parent
* processes. On output, a value which is not -1 is the
* parent pipe handle corresponding to the pipe which has
* been created. An element of this array is -1 on input
* if and only if it is <em>not</em> -1 on output.
* @param redirectErrorStream redirectErrorStream attribute
* @return the native subprocess HANDLE returned by CreateProcess
*/
private
static
native
long
create
(
String
cmdstr
,
String
envblock
,
String
dir
,
boolean
redirectErrorStream
,
FileDescriptor
in_fd
,
FileDescriptor
out_fd
,
FileDescriptor
err_fd
)
long
[]
stdHandles
,
boolean
redirectErrorStream
)
throws
IOException
;
private
static
native
boolean
closeHandle
(
long
handle
);
...
...
src/windows/native/java/lang/ProcessImpl_md.c
浏览文件 @
095ce48d
...
...
@@ -125,7 +125,7 @@ win32Error(JNIEnv *env, const char *functionName)
static
void
closeSafely
(
HANDLE
handle
)
{
if
(
handle
)
if
(
handle
!=
INVALID_HANDLE_VALUE
)
CloseHandle
(
handle
);
}
...
...
@@ -134,23 +134,22 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
jstring
cmd
,
jstring
envBlock
,
jstring
dir
,
jboolean
redirectErrorStream
,
jobject
in_fd
,
jobject
out_fd
,
jobject
err_fd
)
jlongArray
stdHandles
,
jboolean
redirectErrorStream
)
{
HANDLE
inRead
=
0
;
HANDLE
inWrite
=
0
;
HANDLE
outRead
=
0
;
HANDLE
outWrite
=
0
;
HANDLE
errRead
=
0
;
HANDLE
errWrite
=
0
;
HANDLE
inRead
=
INVALID_HANDLE_VALUE
;
HANDLE
inWrite
=
INVALID_HANDLE_VALUE
;
HANDLE
outRead
=
INVALID_HANDLE_VALUE
;
HANDLE
outWrite
=
INVALID_HANDLE_VALUE
;
HANDLE
errRead
=
INVALID_HANDLE_VALUE
;
HANDLE
errWrite
=
INVALID_HANDLE_VALUE
;
SECURITY_ATTRIBUTES
sa
;
PROCESS_INFORMATION
pi
;
STARTUPINFO
si
;
LPTSTR
pcmd
=
NULL
;
LPCTSTR
pdir
=
NULL
;
LPVOID
penvBlock
=
NULL
;
jlong
*
handles
=
NULL
;
jlong
ret
=
0
;
OSVERSIONINFO
ver
;
jboolean
onNT
=
JNI_FALSE
;
...
...
@@ -161,17 +160,6 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
if
(
ver
.
dwPlatformId
==
VER_PLATFORM_WIN32_NT
)
onNT
=
JNI_TRUE
;
sa
.
nLength
=
sizeof
(
sa
);
sa
.
lpSecurityDescriptor
=
0
;
sa
.
bInheritHandle
=
TRUE
;
if
(
!
(
CreatePipe
(
&
inRead
,
&
inWrite
,
&
sa
,
PIPE_SIZE
)
&&
CreatePipe
(
&
outRead
,
&
outWrite
,
&
sa
,
PIPE_SIZE
)
&&
CreatePipe
(
&
errRead
,
&
errWrite
,
&
sa
,
PIPE_SIZE
)))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
assert
(
cmd
!=
NULL
);
pcmd
=
(
LPTSTR
)
JNU_GetStringPlatformChars
(
env
,
cmd
,
NULL
);
if
(
pcmd
==
NULL
)
goto
Catch
;
...
...
@@ -189,19 +177,62 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
if
(
penvBlock
==
NULL
)
goto
Catch
;
}
assert
(
stdHandles
!=
NULL
);
handles
=
(
*
env
)
->
GetLongArrayElements
(
env
,
stdHandles
,
NULL
);
if
(
handles
==
NULL
)
goto
Catch
;
memset
(
&
si
,
0
,
sizeof
(
si
));
si
.
cb
=
sizeof
(
si
);
si
.
dwFlags
=
STARTF_USESTDHANDLES
;
si
.
hStdInput
=
inRead
;
si
.
hStdOutput
=
outWrite
;
si
.
hStdError
=
redirectErrorStream
?
outWrite
:
errWrite
;
SetHandleInformation
(
inWrite
,
HANDLE_FLAG_INHERIT
,
FALSE
);
SetHandleInformation
(
outRead
,
HANDLE_FLAG_INHERIT
,
FALSE
)
;
SetHandleInformation
(
errRead
,
HANDLE_FLAG_INHERIT
,
FALSE
)
;
sa
.
nLength
=
sizeof
(
sa
);
sa
.
lpSecurityDescriptor
=
0
;
sa
.
bInheritHandle
=
TRUE
;
if
(
redirectErrorStream
)
SetHandleInformation
(
errWrite
,
HANDLE_FLAG_INHERIT
,
FALSE
);
if
(
handles
[
0
]
!=
(
jlong
)
-
1
)
{
si
.
hStdInput
=
(
HANDLE
)
handles
[
0
];
handles
[
0
]
=
(
jlong
)
-
1
;
}
else
{
if
(
!
CreatePipe
(
&
inRead
,
&
inWrite
,
&
sa
,
PIPE_SIZE
))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
si
.
hStdInput
=
inRead
;
SetHandleInformation
(
inWrite
,
HANDLE_FLAG_INHERIT
,
FALSE
);
handles
[
0
]
=
(
jlong
)
inWrite
;
}
SetHandleInformation
(
si
.
hStdInput
,
HANDLE_FLAG_INHERIT
,
TRUE
);
if
(
handles
[
1
]
!=
(
jlong
)
-
1
)
{
si
.
hStdOutput
=
(
HANDLE
)
handles
[
1
];
handles
[
1
]
=
(
jlong
)
-
1
;
}
else
{
if
(
!
CreatePipe
(
&
outRead
,
&
outWrite
,
&
sa
,
PIPE_SIZE
))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
si
.
hStdOutput
=
outWrite
;
SetHandleInformation
(
outRead
,
HANDLE_FLAG_INHERIT
,
FALSE
);
handles
[
1
]
=
(
jlong
)
outRead
;
}
SetHandleInformation
(
si
.
hStdOutput
,
HANDLE_FLAG_INHERIT
,
TRUE
);
if
(
redirectErrorStream
)
{
si
.
hStdError
=
si
.
hStdOutput
;
handles
[
2
]
=
(
jlong
)
-
1
;
}
else
if
(
handles
[
2
]
!=
(
jlong
)
-
1
)
{
si
.
hStdError
=
(
HANDLE
)
handles
[
2
];
handles
[
2
]
=
(
jlong
)
-
1
;
}
else
{
if
(
!
CreatePipe
(
&
errRead
,
&
errWrite
,
&
sa
,
PIPE_SIZE
))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
si
.
hStdError
=
errWrite
;
SetHandleInformation
(
errRead
,
HANDLE_FLAG_INHERIT
,
FALSE
);
handles
[
2
]
=
(
jlong
)
errRead
;
}
SetHandleInformation
(
si
.
hStdError
,
HANDLE_FLAG_INHERIT
,
TRUE
);
if
(
onNT
)
processFlag
=
CREATE_NO_WINDOW
|
CREATE_UNICODE_ENVIRONMENT
;
...
...
@@ -237,9 +268,6 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
CloseHandle
(
pi
.
hThread
);
ret
=
(
jlong
)
pi
.
hProcess
;
(
*
env
)
->
SetLongField
(
env
,
in_fd
,
IO_handle_fdID
,
(
jlong
)
inWrite
);
(
*
env
)
->
SetLongField
(
env
,
out_fd
,
IO_handle_fdID
,
(
jlong
)
outRead
);
(
*
env
)
->
SetLongField
(
env
,
err_fd
,
IO_handle_fdID
,
(
jlong
)
errRead
);
Finally:
/* Always clean up the child's side of the pipes */
...
...
@@ -257,6 +285,9 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
else
JNU_ReleaseStringPlatformChars
(
env
,
dir
,
(
char
*
)
penvBlock
);
}
if
(
handles
!=
NULL
)
(
*
env
)
->
ReleaseLongArrayElements
(
env
,
stdHandles
,
handles
,
0
);
return
ret
;
Catch:
...
...
test/java/lang/ProcessBuilder/Basic.java
浏览文件 @
095ce48d
...
...
@@ -25,12 +25,15 @@
* @test
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
* 6464154 6523983 6206031
* 6464154 6523983 6206031
4960438 6631352 6631966
* @summary Basic tests for Process and Environment Variable code
* @run main/othervm Basic
* @author Martin Buchholz
*/
import
java.lang.ProcessBuilder.Redirect
;
import
static
java
.
lang
.
ProcessBuilder
.
Redirect
.*;
import
java.io.*
;
import
java.util.*
;
import
java.security.*
;
...
...
@@ -257,7 +260,29 @@ public class Basic {
public
static
class
JavaChild
{
public
static
void
main
(
String
args
[])
throws
Throwable
{
String
action
=
args
[
0
];
if
(
action
.
equals
(
"System.getenv(String)"
))
{
if
(
action
.
equals
(
"testIO"
))
{
String
expected
=
"standard input"
;
char
[]
buf
=
new
char
[
expected
.
length
()+
1
];
int
n
=
new
InputStreamReader
(
System
.
in
).
read
(
buf
,
0
,
buf
.
length
);
if
(
n
!=
expected
.
length
())
System
.
exit
(
5
);
if
(!
new
String
(
buf
,
0
,
n
).
equals
(
expected
))
System
.
exit
(
5
);
System
.
err
.
print
(
"standard error"
);
System
.
out
.
print
(
"standard output"
);
}
else
if
(
action
.
equals
(
"testInheritIO"
))
{
List
<
String
>
childArgs
=
new
ArrayList
<
String
>(
javaChildArgs
);
childArgs
.
add
(
"testIO"
);
ProcessBuilder
pb
=
new
ProcessBuilder
(
childArgs
);
pb
.
inheritIO
();
ProcessResults
r
=
run
(
pb
);
if
(!
r
.
out
().
equals
(
""
))
System
.
exit
(
7
);
if
(!
r
.
err
().
equals
(
""
))
System
.
exit
(
8
);
if
(
r
.
exitValue
()
!=
0
)
System
.
exit
(
9
);
}
else
if
(
action
.
equals
(
"System.getenv(String)"
))
{
String
val
=
System
.
getenv
(
args
[
1
]);
printUTF8
(
val
==
null
?
"null"
:
val
);
}
else
if
(
action
.
equals
(
"System.getenv(\\u1234)"
))
{
...
...
@@ -599,6 +624,333 @@ public class Basic {
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
static
void
checkRedirects
(
ProcessBuilder
pb
,
Redirect
in
,
Redirect
out
,
Redirect
err
)
{
equal
(
pb
.
redirectInput
(),
in
);
equal
(
pb
.
redirectOutput
(),
out
);
equal
(
pb
.
redirectError
(),
err
);
}
static
void
redirectIO
(
ProcessBuilder
pb
,
Redirect
in
,
Redirect
out
,
Redirect
err
)
{
pb
.
redirectInput
(
in
);
pb
.
redirectOutput
(
out
);
pb
.
redirectError
(
err
);
}
static
void
setFileContents
(
File
file
,
String
contents
)
{
try
{
Writer
w
=
new
FileWriter
(
file
);
w
.
write
(
contents
);
w
.
close
();
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
static
String
fileContents
(
File
file
)
{
try
{
Reader
r
=
new
FileReader
(
file
);
StringBuilder
sb
=
new
StringBuilder
();
char
[]
buffer
=
new
char
[
1024
];
int
n
;
while
((
n
=
r
.
read
(
buffer
))
!=
-
1
)
sb
.
append
(
buffer
,
0
,
n
);
r
.
close
();
return
new
String
(
sb
);
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
return
""
;
}
}
static
void
testIORedirection
()
throws
Throwable
{
final
File
ifile
=
new
File
(
"ifile"
);
final
File
ofile
=
new
File
(
"ofile"
);
final
File
efile
=
new
File
(
"efile"
);
ifile
.
delete
();
ofile
.
delete
();
efile
.
delete
();
//----------------------------------------------------------------
// Check mutual inequality of different types of Redirect
//----------------------------------------------------------------
Redirect
[]
redirects
=
{
PIPE
,
INHERIT
,
Redirect
.
from
(
ifile
),
Redirect
.
to
(
ifile
),
Redirect
.
appendTo
(
ifile
),
Redirect
.
from
(
ofile
),
Redirect
.
to
(
ofile
),
Redirect
.
appendTo
(
ofile
),
};
for
(
int
i
=
0
;
i
<
redirects
.
length
;
i
++)
for
(
int
j
=
0
;
j
<
redirects
.
length
;
j
++)
equal
(
redirects
[
i
].
equals
(
redirects
[
j
]),
(
i
==
j
));
//----------------------------------------------------------------
// Check basic properties of different types of Redirect
//----------------------------------------------------------------
equal
(
PIPE
.
type
(),
Redirect
.
Type
.
PIPE
);
equal
(
PIPE
.
toString
(),
"PIPE"
);
equal
(
PIPE
.
file
(),
null
);
equal
(
INHERIT
.
type
(),
Redirect
.
Type
.
INHERIT
);
equal
(
INHERIT
.
toString
(),
"INHERIT"
);
equal
(
INHERIT
.
file
(),
null
);
equal
(
Redirect
.
from
(
ifile
).
type
(),
Redirect
.
Type
.
READ
);
equal
(
Redirect
.
from
(
ifile
).
toString
(),
"redirect to read from file \"ifile\""
);
equal
(
Redirect
.
from
(
ifile
).
file
(),
ifile
);
equal
(
Redirect
.
from
(
ifile
),
Redirect
.
from
(
ifile
));
equal
(
Redirect
.
from
(
ifile
).
hashCode
(),
Redirect
.
from
(
ifile
).
hashCode
());
equal
(
Redirect
.
to
(
ofile
).
type
(),
Redirect
.
Type
.
WRITE
);
equal
(
Redirect
.
to
(
ofile
).
toString
(),
"redirect to write to file \"ofile\""
);
equal
(
Redirect
.
to
(
ofile
).
file
(),
ofile
);
equal
(
Redirect
.
to
(
ofile
),
Redirect
.
to
(
ofile
));
equal
(
Redirect
.
to
(
ofile
).
hashCode
(),
Redirect
.
to
(
ofile
).
hashCode
());
equal
(
Redirect
.
appendTo
(
ofile
).
type
(),
Redirect
.
Type
.
APPEND
);
equal
(
Redirect
.
appendTo
(
efile
).
toString
(),
"redirect to append to file \"efile\""
);
equal
(
Redirect
.
appendTo
(
efile
).
file
(),
efile
);
equal
(
Redirect
.
appendTo
(
efile
),
Redirect
.
appendTo
(
efile
));
equal
(
Redirect
.
appendTo
(
efile
).
hashCode
(),
Redirect
.
appendTo
(
efile
).
hashCode
());
//----------------------------------------------------------------
// Check initial values of redirects
//----------------------------------------------------------------
List
<
String
>
childArgs
=
new
ArrayList
<
String
>(
javaChildArgs
);
childArgs
.
add
(
"testIO"
);
final
ProcessBuilder
pb
=
new
ProcessBuilder
(
childArgs
);
checkRedirects
(
pb
,
PIPE
,
PIPE
,
PIPE
);
//----------------------------------------------------------------
// Check inheritIO
//----------------------------------------------------------------
pb
.
inheritIO
();
checkRedirects
(
pb
,
INHERIT
,
INHERIT
,
INHERIT
);
//----------------------------------------------------------------
// Check setters and getters agree
//----------------------------------------------------------------
pb
.
redirectInput
(
ifile
);
equal
(
pb
.
redirectInput
().
file
(),
ifile
);
equal
(
pb
.
redirectInput
(),
Redirect
.
from
(
ifile
));
pb
.
redirectOutput
(
ofile
);
equal
(
pb
.
redirectOutput
().
file
(),
ofile
);
equal
(
pb
.
redirectOutput
(),
Redirect
.
to
(
ofile
));
pb
.
redirectError
(
efile
);
equal
(
pb
.
redirectError
().
file
(),
efile
);
equal
(
pb
.
redirectError
(),
Redirect
.
to
(
efile
));
THROWS
(
IllegalArgumentException
.
class
,
new
Fun
(){
void
f
()
{
pb
.
redirectInput
(
Redirect
.
to
(
ofile
));
}},
new
Fun
(){
void
f
()
{
pb
.
redirectInput
(
Redirect
.
appendTo
(
ofile
));
}},
new
Fun
(){
void
f
()
{
pb
.
redirectOutput
(
Redirect
.
from
(
ifile
));
}},
new
Fun
(){
void
f
()
{
pb
.
redirectError
(
Redirect
.
from
(
ifile
));
}});
THROWS
(
IOException
.
class
,
// Input file does not exist
new
Fun
(){
void
f
()
throws
Throwable
{
pb
.
start
();
}});
setFileContents
(
ifile
,
"standard input"
);
//----------------------------------------------------------------
// Writing to non-existent files
//----------------------------------------------------------------
{
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Both redirectErrorStream + redirectError
//----------------------------------------------------------------
{
pb
.
redirectErrorStream
(
true
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"standard error"
+
"standard output"
);
equal
(
fileContents
(
efile
),
""
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Appending to existing files
//----------------------------------------------------------------
{
setFileContents
(
ofile
,
"ofile-contents"
);
setFileContents
(
efile
,
"efile-contents"
);
pb
.
redirectOutput
(
Redirect
.
appendTo
(
ofile
));
pb
.
redirectError
(
Redirect
.
appendTo
(
efile
));
pb
.
redirectErrorStream
(
false
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"ofile-contents"
+
"standard output"
);
equal
(
fileContents
(
efile
),
"efile-contents"
+
"standard error"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Replacing existing files
//----------------------------------------------------------------
{
setFileContents
(
ofile
,
"ofile-contents"
);
setFileContents
(
efile
,
"efile-contents"
);
pb
.
redirectOutput
(
ofile
);
pb
.
redirectError
(
Redirect
.
to
(
efile
));
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Appending twice to the same file?
//----------------------------------------------------------------
{
setFileContents
(
ofile
,
"ofile-contents"
);
setFileContents
(
efile
,
"efile-contents"
);
Redirect
appender
=
Redirect
.
appendTo
(
ofile
);
pb
.
redirectOutput
(
appender
);
pb
.
redirectError
(
appender
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"ofile-contents"
+
"standard error"
+
"standard output"
);
equal
(
fileContents
(
efile
),
"efile-contents"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ifile
.
delete
();
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Testing INHERIT is harder.
// Note that this requires __FOUR__ nested JVMs involved in one test,
// if you count the harness JVM.
//----------------------------------------------------------------
{
redirectIO
(
pb
,
PIPE
,
PIPE
,
PIPE
);
List
<
String
>
command
=
pb
.
command
();
command
.
set
(
command
.
size
()
-
1
,
"testInheritIO"
);
Process
p
=
pb
.
start
();
new
PrintStream
(
p
.
getOutputStream
()).
print
(
"standard input"
);
p
.
getOutputStream
().
close
();
ProcessResults
r
=
run
(
p
);
equal
(
r
.
exitValue
(),
0
);
equal
(
r
.
out
(),
"standard output"
);
equal
(
r
.
err
(),
"standard error"
);
}
//----------------------------------------------------------------
// Test security implications of I/O redirection
//----------------------------------------------------------------
// Read access to current directory is always granted;
// So create a tmpfile for input instead.
final
File
tmpFile
=
File
.
createTempFile
(
"Basic"
,
"tmp"
);
setFileContents
(
tmpFile
,
"standard input"
);
final
Policy
policy
=
new
Policy
();
Policy
.
setPolicy
(
policy
);
System
.
setSecurityManager
(
new
SecurityManager
());
try
{
final
Permission
xPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"execute"
);
final
Permission
rxPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"read,execute"
);
final
Permission
wxPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"write,execute"
);
final
Permission
rwxPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"read,write,execute"
);
THROWS
(
SecurityException
.
class
,
new
Fun
()
{
void
f
()
throws
IOException
{
policy
.
setPermissions
(
xPermission
);
redirectIO
(
pb
,
from
(
tmpFile
),
PIPE
,
PIPE
);
pb
.
start
();}},
new
Fun
()
{
void
f
()
throws
IOException
{
policy
.
setPermissions
(
rxPermission
);
redirectIO
(
pb
,
PIPE
,
to
(
ofile
),
PIPE
);
pb
.
start
();}},
new
Fun
()
{
void
f
()
throws
IOException
{
policy
.
setPermissions
(
rxPermission
);
redirectIO
(
pb
,
PIPE
,
PIPE
,
to
(
efile
));
pb
.
start
();}});
{
policy
.
setPermissions
(
rxPermission
);
redirectIO
(
pb
,
from
(
tmpFile
),
PIPE
,
PIPE
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
out
(),
"standard output"
);
equal
(
r
.
err
(),
"standard error"
);
}
{
policy
.
setPermissions
(
wxPermission
);
redirectIO
(
pb
,
PIPE
,
to
(
ofile
),
to
(
efile
));
Process
p
=
pb
.
start
();
new
PrintStream
(
p
.
getOutputStream
()).
print
(
"standard input"
);
p
.
getOutputStream
().
close
();
ProcessResults
r
=
run
(
p
);
policy
.
setPermissions
(
rwxPermission
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
}
{
policy
.
setPermissions
(
rwxPermission
);
redirectIO
(
pb
,
from
(
tmpFile
),
to
(
ofile
),
to
(
efile
));
ProcessResults
r
=
run
(
pb
);
policy
.
setPermissions
(
rwxPermission
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
}
}
finally
{
policy
.
setPermissions
(
new
RuntimePermission
(
"setSecurityManager"
));
System
.
setSecurityManager
(
null
);
tmpFile
.
delete
();
ifile
.
delete
();
ofile
.
delete
();
efile
.
delete
();
}
}
private
static
void
realMain
(
String
[]
args
)
throws
Throwable
{
if
(
Windows
.
is
())
System
.
out
.
println
(
"This appears to be a Windows system."
);
...
...
@@ -607,6 +959,9 @@ public class Basic {
if
(
UnicodeOS
.
is
())
System
.
out
.
println
(
"This appears to be a Unicode-based OS."
);
try
{
testIORedirection
();
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
//----------------------------------------------------------------
// Basic tests for setting, replacing and deleting envvars
//----------------------------------------------------------------
...
...
@@ -1354,7 +1709,8 @@ public class Basic {
execPermission
);
ProcessBuilder
pb
=
new
ProcessBuilder
(
"env"
);
pb
.
environment
().
put
(
"foo"
,
"bar"
);
pb
.
start
();
Process
p
=
pb
.
start
();
closeStreams
(
p
);
}
catch
(
IOException
e
)
{
// OK
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
...
...
@@ -1378,6 +1734,14 @@ public class Basic {
}
static
void
closeStreams
(
Process
p
)
{
try
{
p
.
getOutputStream
().
close
();
p
.
getInputStream
().
close
();
p
.
getErrorStream
().
close
();
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
//----------------------------------------------------------------
// A Policy class designed to make permissions fiddling very easy.
//----------------------------------------------------------------
...
...
@@ -1432,10 +1796,19 @@ public class Basic {
}
}
catch
(
Throwable
t
)
{
throwable
=
t
;
}
finally
{
try
{
is
.
close
();
}
catch
(
Throwable
t
)
{
throwable
=
t
;
}
}
}
}
static
ProcessResults
run
(
ProcessBuilder
pb
)
{
try
{
return
run
(
pb
.
start
());
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
return
null
;
}
}
private
static
ProcessResults
run
(
Process
p
)
{
Throwable
throwable
=
null
;
int
exitValue
=
-
1
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录