Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell11
提交
7a70c520
D
dragonwell11
项目概览
openanolis
/
dragonwell11
通知
7
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell11
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7a70c520
编写于
6月 02, 2016
作者:
R
rfield
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8131029: JShell: recover from VMConnection launch failure
Reviewed-by: vromero
上级
a992a9f3
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
513 addition
and
218 deletion
+513
-218
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/ClassTracker.java
...l/share/classes/jdk/internal/jshell/jdi/ClassTracker.java
+5
-4
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/FailOverExecutionControl.java
...ses/jdk/internal/jshell/jdi/FailOverExecutionControl.java
+119
-0
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIConnection.java
.../share/classes/jdk/internal/jshell/jdi/JDIConnection.java
+100
-110
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIEventHandler.java
...hare/classes/jdk/internal/jshell/jdi/JDIEventHandler.java
+17
-16
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIExecutionControl.java
.../classes/jdk/internal/jshell/jdi/JDIExecutionControl.java
+58
-58
langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
...tools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
+9
-2
langtools/test/jdk/jshell/ExecutionControlTestBase.java
langtools/test/jdk/jshell/ExecutionControlTestBase.java
+1
-28
langtools/test/jdk/jshell/FailOverExecutionControlTest.java
langtools/test/jdk/jshell/FailOverExecutionControlTest.java
+104
-0
langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java
...ols/test/jdk/jshell/JDIListeningExecutionControlTest.java
+46
-0
langtools/test/jdk/jshell/ToolBasicTest.java
langtools/test/jdk/jshell/ToolBasicTest.java
+1
-0
langtools/test/jdk/jshell/UserExecutionControlTest.java
langtools/test/jdk/jshell/UserExecutionControlTest.java
+53
-0
未找到文件。
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/ClassTracker.java
浏览文件 @
7a70c520
...
...
@@ -28,17 +28,18 @@ import java.util.HashMap;
import
java.util.Objects
;
import
com.sun.jdi.ReferenceType
;
import
java.util.List
;
import
com.sun.jdi.VirtualMachine
;
/**
* Tracks the state of a class.
*/
class
ClassTracker
{
private
final
JDIEnv
jdiEnv
;
private
final
VirtualMachine
vm
;
private
final
HashMap
<
String
,
ClassInfo
>
map
;
ClassTracker
(
JDIEnv
jdiEnv
)
{
this
.
jdiEnv
=
jdiEnv
;
ClassTracker
(
VirtualMachine
vm
)
{
this
.
vm
=
vm
;
this
.
map
=
new
HashMap
<>();
}
...
...
@@ -96,7 +97,7 @@ class ClassTracker {
}
private
ReferenceType
nameToRef
(
String
name
)
{
List
<
ReferenceType
>
rtl
=
jdiEnv
.
vm
()
.
classesByName
(
name
);
List
<
ReferenceType
>
rtl
=
vm
.
classesByName
(
name
);
if
(
rtl
.
size
()
!=
1
)
{
return
null
;
}
...
...
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/FailOverExecutionControl.java
0 → 100644
浏览文件 @
7a70c520
/*
* Copyright (c) 2016, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package
jdk.internal.jshell.jdi
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.List
;
import
jdk.internal.jshell.debug.InternalDebugControl
;
import
jdk.jshell.JShellException
;
import
jdk.jshell.spi.ExecutionControl
;
import
jdk.jshell.spi.ExecutionEnv
;
/**
* A meta implementation of ExecutionControl which cycles through the specified
* ExecutionControl instances until it finds one that starts.
*/
public
class
FailOverExecutionControl
implements
ExecutionControl
{
private
final
List
<
ExecutionControl
>
ecl
=
new
ArrayList
<>();
private
ExecutionControl
active
=
null
;
private
final
List
<
Exception
>
thrown
=
new
ArrayList
<>();
/**
* Create the ExecutionControl instance with at least one actual
* ExecutionControl instance.
*
* @param ec0 the first instance to try
* @param ecs the second and on instance to try
*/
public
FailOverExecutionControl
(
ExecutionControl
ec0
,
ExecutionControl
...
ecs
)
{
ecl
.
add
(
ec0
);
for
(
ExecutionControl
ec
:
ecs
)
{
ecl
.
add
(
ec
);
}
}
@Override
public
void
start
(
ExecutionEnv
env
)
throws
Exception
{
for
(
ExecutionControl
ec
:
ecl
)
{
try
{
ec
.
start
(
env
);
// Success! This is our active ExecutionControl
active
=
ec
;
return
;
}
catch
(
Exception
ex
)
{
thrown
.
add
(
ex
);
}
catch
(
Throwable
ex
)
{
thrown
.
add
(
new
RuntimeException
(
ex
));
}
InternalDebugControl
.
debug
(
env
.
state
(),
env
.
userErr
(),
thrown
.
get
(
thrown
.
size
()
-
1
),
"failed one in FailOverExecutionControl"
);
}
// They have all failed -- rethrow the first exception we encountered
throw
thrown
.
get
(
0
);
}
@Override
public
void
close
()
{
active
.
close
();
}
@Override
public
boolean
addToClasspath
(
String
path
)
{
return
active
.
addToClasspath
(
path
);
}
@Override
public
String
invoke
(
String
classname
,
String
methodname
)
throws
JShellException
{
return
active
.
invoke
(
classname
,
methodname
);
}
@Override
public
boolean
load
(
Collection
<
String
>
classes
)
{
return
active
.
load
(
classes
);
}
@Override
public
boolean
redefine
(
Collection
<
String
>
classes
)
{
return
active
.
redefine
(
classes
);
}
@Override
public
ClassStatus
getClassStatus
(
String
classname
)
{
return
active
.
getClassStatus
(
classname
);
}
@Override
public
void
stop
()
{
active
.
stop
();
}
@Override
public
String
varValue
(
String
classname
,
String
varname
)
{
return
active
.
varValue
(
classname
,
varname
);
}
}
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIConnection.java
浏览文件 @
7a70c520
...
...
@@ -49,6 +49,8 @@ import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
*/
class
JDIConnection
{
private
static
final
String
REMOTE_AGENT
=
"jdk.internal.jshell.remote.RemoteAgent"
;
private
VirtualMachine
vm
;
private
boolean
active
=
true
;
private
Process
process
=
null
;
...
...
@@ -59,12 +61,12 @@ class JDIConnection {
private
final
Map
<
String
,
com
.
sun
.
jdi
.
connect
.
Connector
.
Argument
>
connectorArgs
;
private
final
int
traceFlags
;
synchronized
void
notifyOutputComplete
()
{
private
synchronized
void
notifyOutputComplete
()
{
outputCompleteCount
++;
notifyAll
();
}
synchronized
void
waitOutputComplete
()
{
private
synchronized
void
waitOutputComplete
()
{
// Wait for stderr and stdout
if
(
process
!=
null
)
{
while
(
outputCompleteCount
<
2
)
{
...
...
@@ -102,61 +104,72 @@ class JDIConnection {
return
arguments
;
}
JDIConnection
(
JDIExecutionControl
ec
,
String
connectorName
,
Map
<
String
,
String
>
argumentName2Value
,
int
traceFlags
)
{
this
.
ec
=
ec
;
this
.
connector
=
findConnector
(
connectorName
);
if
(
connector
==
null
)
{
throw
new
IllegalArgumentException
(
"No connector named: "
+
connectorName
);
}
connectorArgs
=
mergeConnectorArgs
(
connector
,
argumentName2Value
);
this
.
traceFlags
=
traceFlags
;
/**
* The JShell specific Connector args for the LaunchingConnector.
*
* @param portthe socket port for (non-JDI) commands
* @param remoteVMOptions any user requested VM options
* @return the argument map
*/
private
static
Map
<
String
,
String
>
launchArgs
(
int
port
,
String
remoteVMOptions
)
{
Map
<
String
,
String
>
argumentName2Value
=
new
HashMap
<>();
argumentName2Value
.
put
(
"main"
,
REMOTE_AGENT
+
" "
+
port
);
argumentName2Value
.
put
(
"options"
,
remoteVMOptions
);
return
argumentName2Value
;
}
synchronized
VirtualMachine
open
()
{
if
(
connector
instanceof
LaunchingConnector
)
{
/**
* Start the remote agent and establish a JDI connection to it.
*
* @param ec the execution control instance
* @param port the socket port for (non-JDI) commands
* @param remoteVMOptions any user requested VM options
* @param isLaunch does JDI do the launch? That is, LaunchingConnector,
* otherwise we start explicitly and use ListeningConnector
*/
JDIConnection
(
JDIExecutionControl
ec
,
int
port
,
List
<
String
>
remoteVMOptions
,
boolean
isLaunch
)
{
this
(
ec
,
isLaunch
?
"com.sun.jdi.CommandLineLaunch"
:
"com.sun.jdi.SocketListen"
,
isLaunch
?
launchArgs
(
port
,
String
.
join
(
" "
,
remoteVMOptions
))
:
new
HashMap
<>(),
0
);
if
(
isLaunch
)
{
vm
=
launchTarget
();
}
else
if
(
connector
instanceof
AttachingConnector
)
{
vm
=
attachTarget
();
}
else
if
(
connector
instanceof
ListeningConnector
)
{
vm
=
listenTarget
();
}
else
{
throw
new
InternalError
(
"Invalid connect type"
);
}
vm
.
setDebugTraceMode
(
traceFlags
);
// Uncomment here and below to enable event requests
// installEventRequests(vm);
return
vm
;
}
synchronized
boolean
setConnectorArg
(
String
name
,
String
value
)
{
/*
* Too late if the connection already made
*/
if
(
vm
!=
null
)
{
return
false
;
vm
=
listenTarget
(
port
,
remoteVMOptions
);
}
Connector
.
Argument
argument
=
connectorArgs
.
get
(
name
);
if
(
argument
==
null
)
{
return
false
;
if
(
isOpen
()
&&
vm
().
canBeModified
())
{
/*
* Connection opened on startup.
*/
new
JDIEventHandler
(
vm
(),
(
b
)
->
ec
.
handleVMExit
())
.
start
();
}
argument
.
setValue
(
value
);
return
true
;
}
String
connectorArg
(
String
name
)
{
Connector
.
Argument
argument
=
connectorArgs
.
get
(
name
);
if
(
argument
==
null
)
{
return
""
;
/**
* Base constructor -- set-up a JDI connection.
*
* @param ec the execution control instance
* @param connectorName the standardized name of the connector
* @param argumentName2Value the argument map
* @param traceFlags should we trace JDI behavior
*/
JDIConnection
(
JDIExecutionControl
ec
,
String
connectorName
,
Map
<
String
,
String
>
argumentName2Value
,
int
traceFlags
)
{
this
.
ec
=
ec
;
this
.
connector
=
findConnector
(
connectorName
);
if
(
connector
==
null
)
{
throw
new
IllegalArgumentException
(
"No connector named: "
+
connectorName
);
}
return
argument
.
value
();
connectorArgs
=
mergeConnectorArgs
(
connector
,
argumentName2Value
);
this
.
traceFlags
=
traceFlags
;
}
public
synchronized
VirtualMachine
vm
()
{
final
synchronized
VirtualMachine
vm
()
{
if
(
vm
==
null
)
{
throw
new
JDINotConnectedException
();
}
else
{
...
...
@@ -164,14 +177,10 @@ class JDIConnection {
}
}
synchronized
boolean
isOpen
()
{
private
synchronized
boolean
isOpen
()
{
return
(
vm
!=
null
);
}
boolean
isLaunch
()
{
return
(
connector
instanceof
LaunchingConnector
);
}
synchronized
boolean
isRunning
()
{
return
process
!=
null
&&
process
.
isAlive
();
}
...
...
@@ -181,7 +190,7 @@ class JDIConnection {
active
=
false
;
}
public
synchronized
void
disposeVM
()
{
synchronized
void
disposeVM
()
{
try
{
if
(
vm
!=
null
)
{
vm
.
dispose
();
// This could NPE, so it is caught below
...
...
@@ -189,6 +198,8 @@ class JDIConnection {
}
}
catch
(
VMDisconnectedException
ex
)
{
// Ignore if already closed
}
catch
(
Throwable
e
)
{
ec
.
debug
(
DBG_GEN
,
null
,
"disposeVM threw: "
+
e
);
}
finally
{
if
(
process
!=
null
)
{
process
.
destroy
();
...
...
@@ -198,41 +209,6 @@ class JDIConnection {
}
}
/*** Preserved for possible future support of event requests
private void installEventRequests(VirtualMachine vm) {
if (vm.canBeModified()){
setEventRequests(vm);
resolveEventRequests();
}
}
private void setEventRequests(VirtualMachine vm) {
EventRequestManager erm = vm.eventRequestManager();
// Normally, we want all uncaught exceptions. We request them
// via the same mechanism as Commands.commandCatchException()
// so the user can ignore them later if they are not
// interested.
// FIXME: this works but generates spurious messages on stdout
// during startup:
// Set uncaught java.lang.Throwable
// Set deferred uncaught java.lang.Throwable
Commands evaluator = new Commands();
evaluator.commandCatchException
(new StringTokenizer("uncaught java.lang.Throwable"));
ThreadStartRequest tsr = erm.createThreadStartRequest();
tsr.enable();
ThreadDeathRequest tdr = erm.createThreadDeathRequest();
tdr.enable();
}
private void resolveEventRequests() {
Env.specList.resolveAll();
}
***/
private
void
dumpStream
(
InputStream
inStream
,
final
PrintStream
pStream
)
throws
IOException
{
BufferedReader
in
=
new
BufferedReader
(
new
InputStreamReader
(
inStream
));
...
...
@@ -270,7 +246,7 @@ class JDIConnection {
dumpStream
(
inStream
,
pStream
);
}
catch
(
IOException
ex
)
{
ec
.
debug
(
ex
,
"Failed reading output"
);
ec
.
jdiEnv
.
shutdown
();
ec
.
handleVMExit
();
}
finally
{
notifyOutputComplete
();
}
...
...
@@ -297,7 +273,7 @@ class JDIConnection {
}
}
catch
(
IOException
ex
)
{
ec
.
debug
(
ex
,
"Failed reading output"
);
ec
.
jdiEnv
.
shutdown
();
ec
.
handleVMExit
();
}
}
};
...
...
@@ -305,15 +281,19 @@ class JDIConnection {
thr
.
start
();
}
private
void
forwardIO
()
{
displayRemoteOutput
(
process
.
getErrorStream
(),
ec
.
execEnv
.
userErr
());
displayRemoteOutput
(
process
.
getInputStream
(),
ec
.
execEnv
.
userOut
());
readRemoteInput
(
process
.
getOutputStream
(),
ec
.
execEnv
.
userIn
());
}
/* launch child target vm */
private
VirtualMachine
launchTarget
()
{
LaunchingConnector
launcher
=
(
LaunchingConnector
)
connector
;
try
{
VirtualMachine
new_vm
=
launcher
.
launch
(
connectorArgs
);
process
=
new_vm
.
process
();
displayRemoteOutput
(
process
.
getErrorStream
(),
ec
.
execEnv
.
userErr
());
displayRemoteOutput
(
process
.
getInputStream
(),
ec
.
execEnv
.
userOut
());
readRemoteInput
(
process
.
getOutputStream
(),
ec
.
execEnv
.
userIn
());
forwardIO
();
return
new_vm
;
}
catch
(
Exception
ex
)
{
reportLaunchFail
(
ex
,
"launch"
);
...
...
@@ -321,25 +301,35 @@ class JDIConnection {
return
null
;
}
/* JShell currently uses only launch, preserved for futures: */
/* attach to running target vm */
private
VirtualMachine
attachTarget
()
{
AttachingConnector
attacher
=
(
AttachingConnector
)
connector
;
try
{
return
attacher
.
attach
(
connectorArgs
);
}
catch
(
Exception
ex
)
{
reportLaunchFail
(
ex
,
"attach"
);
}
return
null
;
}
/* JShell currently uses only launch, preserved for futures: */
/* listen for connection from target vm */
private
VirtualMachine
listenTarget
()
{
ListeningConnector
listener
=
(
ListeningConnector
)
connector
;
/**
* Directly launch the remote agent and connect JDI to it with a
* ListeningConnector.
*/
private
VirtualMachine
listenTarget
(
int
port
,
List
<
String
>
remoteVMOptions
)
{
ListeningConnector
listener
=
(
ListeningConnector
)
connector
;
try
{
String
retAddress
=
listener
.
startListening
(
connectorArgs
);
ec
.
debug
(
DBG_GEN
,
"Listening at address: "
+
retAddress
);
// Start listening, get the JDI connection address
String
addr
=
listener
.
startListening
(
connectorArgs
);
ec
.
debug
(
DBG_GEN
,
"Listening at address: "
+
addr
);
// Launch the RemoteAgent requesting a connection on that address
String
javaHome
=
System
.
getProperty
(
"java.home"
);
List
<
String
>
args
=
new
ArrayList
<>();
args
.
add
(
javaHome
==
null
?
"java"
:
javaHome
+
File
.
separator
+
"bin"
+
File
.
separator
+
"java"
);
args
.
add
(
"-agentlib:jdwp=transport="
+
connector
.
transport
().
name
()
+
",address="
+
addr
);
args
.
addAll
(
remoteVMOptions
);
args
.
add
(
REMOTE_AGENT
);
args
.
add
(
""
+
port
);
ProcessBuilder
pb
=
new
ProcessBuilder
(
args
);
process
=
pb
.
start
();
// Forward out, err, and in
forwardIO
();
// Accept the connection from the remote agent
vm
=
listener
.
accept
(
connectorArgs
);
listener
.
stopListening
(
connectorArgs
);
return
vm
;
...
...
@@ -353,4 +343,4 @@ class JDIConnection {
throw
new
InternalError
(
"Failed remote "
+
context
+
": "
+
connector
+
" -- "
+
connectorArgs
,
ex
);
}
}
}
\ No newline at end of file
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIEventHandler.java
浏览文件 @
7a70c520
...
...
@@ -25,6 +25,7 @@
package
jdk.internal.jshell.jdi
;
import
java.util.function.Consumer
;
import
com.sun.jdi.*
;
import
com.sun.jdi.event.*
;
...
...
@@ -34,16 +35,20 @@ import com.sun.jdi.event.*;
*/
class
JDIEventHandler
implements
Runnable
{
Thread
thread
;
volatile
boolean
connected
=
true
;
boolean
completed
=
false
;
String
shutdownMessageKey
;
final
JDIEnv
env
;
private
final
Thread
thread
;
private
volatile
boolean
connected
=
true
;
private
boolean
completed
=
false
;
private
final
VirtualMachine
vm
;
private
final
Consumer
<
Boolean
>
reportVMExit
;
JDIEventHandler
(
JDIEnv
env
)
{
this
.
env
=
env
;
JDIEventHandler
(
VirtualMachine
vm
,
Consumer
<
Boolean
>
reportVMExit
)
{
this
.
vm
=
vm
;
this
.
reportVMExit
=
reportVMExit
;
this
.
thread
=
new
Thread
(
this
,
"event-handler"
);
this
.
thread
.
start
();
}
void
start
()
{
thread
.
start
();
}
synchronized
void
shutdown
()
{
...
...
@@ -56,7 +61,7 @@ class JDIEventHandler implements Runnable {
@Override
public
void
run
()
{
EventQueue
queue
=
env
.
vm
()
.
eventQueue
();
EventQueue
queue
=
vm
.
eventQueue
();
while
(
connected
)
{
try
{
EventSet
eventSet
=
queue
.
remove
();
...
...
@@ -111,27 +116,23 @@ class JDIEventHandler implements Runnable {
private
void
handleExitEvent
(
Event
event
)
{
if
(
event
instanceof
VMDeathEvent
)
{
vmDied
=
true
;
shutdownMessageKey
=
"The application exited"
;
}
else
if
(
event
instanceof
VMDisconnectEvent
)
{
connected
=
false
;
if
(!
vmDied
)
{
shutdownMessageKey
=
"The application has been disconnected"
;
}
}
else
{
throw
new
InternalError
(
"Unexpected event type: "
+
event
.
getClass
());
}
env
.
shutdown
(
);
reportVMExit
.
accept
(
vmDied
);
}
synchronized
void
handleDisconnectedException
()
{
private
synchronized
void
handleDisconnectedException
()
{
/*
* A VMDisconnectedException has happened while dealing with
* another event. We need to flush the event queue, dealing only
* with exit events (VMDeath, VMDisconnect) so that we terminate
* correctly.
*/
EventQueue
queue
=
env
.
vm
()
.
eventQueue
();
EventQueue
queue
=
vm
.
eventQueue
();
while
(
connected
)
{
try
{
EventSet
eventSet
=
queue
.
remove
();
...
...
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIExecutionControl.java
浏览文件 @
7a70c520
...
...
@@ -34,13 +34,20 @@ import java.io.ObjectOutputStream;
import
java.io.PrintStream
;
import
java.net.ServerSocket
;
import
java.net.Socket
;
import
com.sun.jdi.*
;
import
java.io.EOFException
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
com.sun.jdi.BooleanValue
;
import
com.sun.jdi.ClassNotLoadedException
;
import
com.sun.jdi.IncompatibleThreadStateException
;
import
com.sun.jdi.InvalidTypeException
;
import
com.sun.jdi.ObjectReference
;
import
com.sun.jdi.ReferenceType
;
import
com.sun.jdi.StackFrame
;
import
com.sun.jdi.ThreadReference
;
import
com.sun.jdi.VirtualMachine
;
import
static
java
.
util
.
stream
.
Collectors
.
toList
;
import
jdk.jshell.JShellException
;
import
jdk.jshell.spi.ExecutionControl
;
...
...
@@ -59,13 +66,28 @@ import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
public
class
JDIExecutionControl
implements
ExecutionControl
{
ExecutionEnv
execEnv
;
JDIEnv
jdiEnv
;
private
ClassTracker
tracker
;
private
JDIEventHandler
handl
er
;
private
final
boolean
isLaunch
;
private
JDIConnection
connection
;
private
ClassTracker
classTrack
er
;
private
Socket
socket
;
private
ObjectInputStream
remoteIn
;
private
ObjectOutputStream
remoteOut
;
private
String
remoteVMOptions
;
/**
* Creates an ExecutionControl instance based on JDI.
*
* @param isLaunch true for LaunchingConnector; false for ListeningConnector
*/
public
JDIExecutionControl
(
boolean
isLaunch
)
{
this
.
isLaunch
=
isLaunch
;
}
/**
* Creates an ExecutionControl instance based on a JDI LaunchingConnector.
*/
public
JDIExecutionControl
()
{
this
.
isLaunch
=
true
;
}
/**
* Initializes the launching JDI execution engine. Initialize JDI and use it
...
...
@@ -79,20 +101,12 @@ public class JDIExecutionControl implements ExecutionControl {
@Override
public
void
start
(
ExecutionEnv
execEnv
)
throws
IOException
{
this
.
execEnv
=
execEnv
;
this
.
jdiEnv
=
new
JDIEnv
(
this
);
this
.
tracker
=
new
ClassTracker
(
jdiEnv
);
StringBuilder
sb
=
new
StringBuilder
();
execEnv
.
extraRemoteVMOptions
().
stream
()
.
forEach
(
s
->
{
sb
.
append
(
" "
);
sb
.
append
(
s
);
});
this
.
remoteVMOptions
=
sb
.
toString
();
try
(
ServerSocket
listener
=
new
ServerSocket
(
0
))
{
// timeout after 60 seconds
listener
.
setSoTimeout
(
60000
);
int
port
=
listener
.
getLocalPort
();
jdiGo
(
port
);
connection
=
new
JDIConnection
(
this
,
port
,
execEnv
.
extraRemoteVMOptions
(),
isLaunch
);
this
.
socket
=
listener
.
accept
();
// out before in -- match remote creation so we don't hang
this
.
remoteOut
=
new
ObjectOutputStream
(
socket
.
getOutputStream
());
...
...
@@ -109,16 +123,15 @@ public class JDIExecutionControl implements ExecutionControl {
@Override
public
void
close
()
{
try
{
JDIConnection
c
=
jdiEnv
.
connection
();
if
(
c
!=
null
)
{
c
.
beginShutdown
();
if
(
connection
!=
null
)
{
connection
.
beginShutdown
();
}
if
(
remoteOut
!=
null
)
{
remoteOut
.
writeInt
(
CMD_EXIT
);
remoteOut
.
flush
();
}
if
(
c
!=
null
)
{
c
.
disposeVM
();
if
(
c
onnection
!=
null
)
{
c
onnection
.
disposeVM
();
}
}
catch
(
IOException
ex
)
{
debug
(
DBG_GEN
,
"Exception on JDI exit: %s\n"
,
ex
);
...
...
@@ -185,9 +198,9 @@ public class JDIExecutionControl implements ExecutionControl {
return
result
;
}
}
catch
(
IOException
|
RuntimeException
ex
)
{
if
(!
jdiEnv
.
connection
()
.
isRunning
())
{
if
(!
connection
.
isRunning
())
{
// The JDI connection is no longer live, shutdown.
jdiEnv
.
shutdown
();
handleVMExit
();
}
else
{
debug
(
DBG_GEN
,
"Exception on remote invoke: %s\n"
,
ex
);
return
"Execution failure: "
+
ex
.
getMessage
();
...
...
@@ -221,7 +234,7 @@ public class JDIExecutionControl implements ExecutionControl {
return
result
;
}
}
catch
(
EOFException
ex
)
{
jdiEnv
.
shutdown
();
handleVMExit
();
}
catch
(
IOException
ex
)
{
debug
(
DBG_GEN
,
"Exception on remote var value: %s\n"
,
ex
);
return
"Execution failure: "
+
ex
.
getMessage
();
...
...
@@ -273,7 +286,7 @@ public class JDIExecutionControl implements ExecutionControl {
ci
->
ci
.
getReferenceTypeOrNull
(),
ci
->
ci
.
getBytes
()));
// Attempt redefine. Throws exceptions on failure.
jdiEnv
.
vm
().
redefineClasses
(
rmp
);
connection
.
vm
().
redefineClasses
(
rmp
);
// Successful: mark the bytes as loaded.
infos
.
stream
()
.
forEach
(
ci
->
ci
.
markLoaded
());
...
...
@@ -287,6 +300,24 @@ public class JDIExecutionControl implements ExecutionControl {
}
}
// the VM has gone down in flames or because user evaled System.exit() or the like
void
handleVMExit
()
{
if
(
connection
!=
null
)
{
// If there is anything left dispose of it
connection
.
disposeVM
();
}
// Tell JShell-core that the VM has died
execEnv
.
closeDown
();
}
// Lazy init class tracker
private
ClassTracker
classTracker
()
{
if
(
classTracker
==
null
)
{
classTracker
=
new
ClassTracker
(
connection
.
vm
());
}
return
classTracker
;
}
/**
* Converts a collection of class names into ClassInfo instances associated
* with the most recently compiled class bytes.
...
...
@@ -296,7 +327,7 @@ public class JDIExecutionControl implements ExecutionControl {
*/
private
List
<
ClassInfo
>
withBytes
(
Collection
<
String
>
classes
)
{
return
classes
.
stream
()
.
map
(
cn
->
tracker
.
classInfo
(
cn
,
execEnv
.
getClassBytes
(
cn
)))
.
map
(
cn
->
classTracker
()
.
classInfo
(
cn
,
execEnv
.
getClassBytes
(
cn
)))
.
collect
(
toList
());
}
...
...
@@ -310,7 +341,7 @@ public class JDIExecutionControl implements ExecutionControl {
*/
@Override
public
ClassStatus
getClassStatus
(
String
classname
)
{
ClassInfo
ci
=
tracker
.
get
(
classname
);
ClassInfo
ci
=
classTracker
()
.
get
(
classname
);
if
(
ci
.
getReferenceTypeOrNull
()
==
null
)
{
// If the class does not have a JDI ReferenceType it has not been loaded
return
ClassStatus
.
UNKNOWN
;
...
...
@@ -403,37 +434,6 @@ public class JDIExecutionControl implements ExecutionControl {
return
elems
;
}
/**
* Launch the remote agent as a JDI connection.
*
* @param port the socket port for (non-JDI) commands
*/
private
void
jdiGo
(
int
port
)
{
//MessageOutput.textResources = ResourceBundle.getBundle("impl.TTYResources",
// Locale.getDefault());
// Set-up for a fresh launch of a remote agent with any user-specified VM options.
String
connectorName
=
"com.sun.jdi.CommandLineLaunch"
;
Map
<
String
,
String
>
argumentName2Value
=
new
HashMap
<>();
argumentName2Value
.
put
(
"main"
,
"jdk.internal.jshell.remote.RemoteAgent "
+
port
);
argumentName2Value
.
put
(
"options"
,
remoteVMOptions
);
boolean
launchImmediately
=
true
;
int
traceFlags
=
0
;
// VirtualMachine.TRACE_SENDS | VirtualMachine.TRACE_EVENTS;
// Launch.
jdiEnv
.
init
(
connectorName
,
argumentName2Value
,
launchImmediately
,
traceFlags
);
if
(
jdiEnv
.
connection
().
isOpen
()
&&
jdiEnv
.
vm
().
canBeModified
())
{
/*
* Connection opened on startup. Start event handler
* immediately, telling it (through arg 2) to stop on the
* VM start event.
*/
handler
=
new
JDIEventHandler
(
jdiEnv
);
}
}
private
final
Object
STOP_LOCK
=
new
Object
();
private
boolean
userCodeRunning
=
false
;
...
...
@@ -447,7 +447,7 @@ public class JDIExecutionControl implements ExecutionControl {
return
;
}
VirtualMachine
vm
=
handler
.
env
.
vm
();
VirtualMachine
vm
=
connection
.
vm
();
vm
.
suspend
();
try
{
OUTER:
...
...
langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
浏览文件 @
7a70c520
...
...
@@ -44,6 +44,7 @@ import java.util.function.Consumer;
import
java.util.function.Supplier
;
import
jdk.internal.jshell.debug.InternalDebugControl
;
import
jdk.internal.jshell.jdi.FailOverExecutionControl
;
import
static
java
.
util
.
stream
.
Collectors
.
collectingAndThen
;
import
static
java
.
util
.
stream
.
Collectors
.
toList
;
import
static
jdk
.
jshell
.
Util
.
expunge
;
...
...
@@ -112,7 +113,9 @@ public class JShell implements AutoCloseable {
this
.
idGenerator
=
b
.
idGenerator
;
this
.
extraRemoteVMOptions
=
b
.
extraRemoteVMOptions
;
this
.
executionControl
=
b
.
executionControl
==
null
?
new
JDIExecutionControl
()
?
new
FailOverExecutionControl
(
new
JDIExecutionControl
(),
new
JDIExecutionControl
(
false
))
:
b
.
executionControl
;
this
.
maps
=
new
SnippetMaps
(
this
);
...
...
@@ -759,7 +762,11 @@ public class JShell implements AutoCloseable {
if
(!
closed
)
{
// Send only once
closed
=
true
;
notifyShutdownEvent
(
this
);
try
{
notifyShutdownEvent
(
this
);
}
catch
(
Throwable
thr
)
{
// Don't care about dying exceptions
}
}
}
...
...
langtools/test/jdk/jshell/ExecutionControlTest.java
→
langtools/test/jdk/jshell/ExecutionControlTest
Base
.java
浏览文件 @
7a70c520
...
...
@@ -21,40 +21,14 @@
* questions.
*/
/*
* @test
* @bug 8156101
* @summary Tests for ExecutionControl SPI
* @build KullaTesting LocalExecutionControl
* @run testng ExecutionControlTest
*/
import
javax.tools.Diagnostic
;
import
jdk.jshell.VarSnippet
;
import
org.testng.annotations.Test
;
import
static
jdk
.
jshell
.
Snippet
.
Status
.
VALID
;
import
static
jdk
.
jshell
.
Snippet
.
SubKind
.*;
import
static
org
.
testng
.
Assert
.
assertEquals
;
import
org.testng.annotations.BeforeMethod
;
@Test
public
class
ExecutionControlTest
extends
KullaTesting
{
@BeforeMethod
@Override
public
void
setUp
()
{
setUp
(
new
LocalExecutionControl
());
}
public
void
verifyLocal
()
throws
ClassNotFoundException
,
NoSuchFieldException
,
IllegalArgumentException
,
IllegalAccessException
{
System
.
setProperty
(
"LOCAL_CHECK"
,
"TBD"
);
assertEquals
(
System
.
getProperty
(
"LOCAL_CHECK"
),
"TBD"
);
assertEval
(
"System.setProperty(\"LOCAL_CHECK\", \"local\")"
);
assertEquals
(
System
.
getProperty
(
"LOCAL_CHECK"
),
"local"
);
}
public
class
ExecutionControlTestBase
extends
KullaTesting
{
public
void
classesDeclaration
()
{
assertEval
(
"interface A { }"
);
...
...
@@ -71,7 +45,6 @@ public class ExecutionControlTest extends KullaTesting {
assertActiveKeys
();
}
@Test
public
void
interfaceTest
()
{
String
interfaceSource
=
"interface A {\n"
...
...
langtools/test/jdk/jshell/FailOverExecutionControlTest.java
0 → 100644
浏览文件 @
7a70c520
/*
* Copyright (c) 2016, 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 8131029
* @summary Test that fail-over works for FailOverExecutionControl
* @modules jdk.jshell/jdk.internal.jshell.jdi
* jdk.jshell/jdk.jshell.spi
* @build KullaTesting ExecutionControlTestBase
* @run testng FailOverExecutionControlTest
*/
import
java.util.Collection
;
import
org.testng.annotations.Test
;
import
org.testng.annotations.BeforeMethod
;
import
jdk.internal.jshell.jdi.FailOverExecutionControl
;
import
jdk.internal.jshell.jdi.JDIExecutionControl
;
import
jdk.jshell.JShellException
;
import
jdk.jshell.spi.ExecutionControl
;
import
jdk.jshell.spi.ExecutionEnv
;
@Test
public
class
FailOverExecutionControlTest
extends
ExecutionControlTestBase
{
@BeforeMethod
@Override
public
void
setUp
()
{
setUp
(
new
FailOverExecutionControl
(
new
AlwaysFailingExecutionControl
(),
new
AlwaysFailingExecutionControl
(),
new
JDIExecutionControl
()));
}
class
AlwaysFailingExecutionControl
implements
ExecutionControl
{
@Override
public
void
start
(
ExecutionEnv
env
)
throws
Exception
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
void
close
()
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
boolean
addToClasspath
(
String
path
)
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
String
invoke
(
String
classname
,
String
methodname
)
throws
JShellException
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
boolean
load
(
Collection
<
String
>
classes
)
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
boolean
redefine
(
Collection
<
String
>
classes
)
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
ClassStatus
getClassStatus
(
String
classname
)
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
void
stop
()
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
@Override
public
String
varValue
(
String
classname
,
String
varname
)
{
throw
new
UnsupportedOperationException
(
"This operation intentionally broken."
);
}
}
}
langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java
0 → 100644
浏览文件 @
7a70c520
/*
* Copyright (c) 2016, 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 8131029
* @summary Tests for alternate JDI connector -- listening
* @modules jdk.jshell/jdk.internal.jshell.jdi
* @build KullaTesting ExecutionControlTestBase
* @run testng JDIListeningExecutionControlTest
*/
import
org.testng.annotations.Test
;
import
org.testng.annotations.BeforeMethod
;
import
jdk.internal.jshell.jdi.JDIExecutionControl
;
@Test
public
class
JDIListeningExecutionControlTest
extends
ExecutionControlTestBase
{
@BeforeMethod
@Override
public
void
setUp
()
{
setUp
(
new
JDIExecutionControl
(
false
));
}
}
langtools/test/jdk/jshell/ToolBasicTest.java
浏览文件 @
7a70c520
...
...
@@ -560,6 +560,7 @@ public class ToolBasicTest extends ReplToolTesting {
);
}
@Test
(
enabled
=
false
)
// TODO 8158197
public
void
testHeadlessEditPad
()
{
String
prevHeadless
=
System
.
getProperty
(
"java.awt.headless"
);
try
{
...
...
langtools/
src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIEnv
.java
→
langtools/
test/jdk/jshell/UserExecutionControlTest
.java
浏览文件 @
7a70c520
/*
* Copyright (c)
1998, 2015
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c)
2016
, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
* 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
...
...
@@ -23,58 +21,33 @@
* questions.
*/
package
jdk.internal.jshell.jdi
;
import
java.util.Map
;
import
com.sun.jdi.*
;
import
static
jdk
.
internal
.
jshell
.
debug
.
InternalDebugControl
.
DBG_GEN
;
/**
* Representation of a Java Debug Interface environment
* Select methods extracted from jdb Env; shutdown() adapted to JShell shutdown.
/*
* @test
* @bug 8156101
* @summary Tests for ExecutionControl SPI
* @build KullaTesting LocalExecutionControl ExecutionControlTestBase
* @run testng UserExecutionControlTest
*/
class
JDIEnv
{
private
JDIConnection
connection
;
private
final
JDIExecutionControl
ec
;
JDIEnv
(
JDIExecutionControl
ec
)
{
this
.
ec
=
ec
;
}
import
org.testng.annotations.Test
;
import
static
org
.
testng
.
Assert
.
assertEquals
;
import
org.testng.annotations.BeforeMethod
;
void
init
(
String
connectorName
,
Map
<
String
,
String
>
argumentName2Value
,
boolean
openNow
,
int
flags
)
{
connection
=
new
JDIConnection
(
ec
,
connectorName
,
argumentName2Value
,
flags
);
if
(!
connection
.
isLaunch
()
||
openNow
)
{
connection
.
open
();
}
}
@Test
public
class
UserExecutionControlTest
extends
ExecutionControlTestBase
{
JDIConnection
connection
()
{
return
connection
;
@BeforeMethod
@Override
public
void
setUp
()
{
setUp
(
new
LocalExecutionControl
());
}
VirtualMachine
vm
()
{
return
connection
.
vm
();
public
void
verifyLocal
()
throws
ClassNotFoundException
,
NoSuchFieldException
,
IllegalArgumentException
,
IllegalAccessException
{
System
.
setProperty
(
"LOCAL_CHECK"
,
"TBD"
);
assertEquals
(
System
.
getProperty
(
"LOCAL_CHECK"
),
"TBD"
);
assertEval
(
"System.setProperty(\"LOCAL_CHECK\", \"local\")"
);
assertEquals
(
System
.
getProperty
(
"LOCAL_CHECK"
),
"local"
);
}
void
shutdown
()
{
if
(
connection
!=
null
)
{
try
{
connection
.
disposeVM
();
}
catch
(
VMDisconnectedException
e
)
{
// Shutting down after the VM has gone away. This is
// not an error, and we just ignore it.
}
catch
(
Throwable
e
)
{
ec
.
debug
(
DBG_GEN
,
null
,
"disposeVM threw: "
+
e
);
}
}
if
(
ec
.
execEnv
.
state
()
!=
null
)
{
// If state has been set-up
try
{
ec
.
execEnv
.
closeDown
();
}
catch
(
Throwable
e
)
{
ec
.
debug
(
DBG_GEN
,
null
,
"state().closeDown() threw: "
+
e
);
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录