提交 3247f053 编写于 作者: D drchase

Merge

......@@ -3619,13 +3619,14 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
"possibility of dangling Thread pointer");
OSThread* osthread = thread->osthread();
bool interrupted = osthread->interrupted();
// There is no synchronization between the setting of the interrupt
// and it being cleared here. It is critical - see 6535709 - that
// we only clear the interrupt state, and reset the interrupt event,
// if we are going to report that we were indeed interrupted - else
// an interrupt can be "lost", leading to spurious wakeups or lost wakeups
// depending on the timing
// depending on the timing. By checking thread interrupt event to see
// if the thread gets real interrupt thus prevent spurious wakeup.
bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0);
if (interrupted && clear_interrupted) {
osthread->set_interrupted(false);
ResetEvent(osthread->interrupt_event());
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, 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
......@@ -273,8 +273,8 @@ class DebugInfoReadStream : public CompressedReadStream {
}
Method* read_method() {
Method* o = (Method*)(code()->metadata_at(read_int()));
assert(o == NULL ||
o->is_metaspace_object(), "meta data only");
// is_metadata() is a faster check than is_metaspace_object()
assert(o == NULL || o->is_metadata(), "meta data only");
return o;
}
ScopeValue* read_object_value();
......
......@@ -1295,6 +1295,7 @@ void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i,
} break;
case JVM_CONSTANT_UnresolvedClass:
case JVM_CONSTANT_UnresolvedClassInError:
{
// Can be resolved after checking tag, so check the slot first.
CPSlot entry = from_cp->slot_at(from_i);
......
......@@ -42,6 +42,7 @@ class Metadata : public MetaspaceObj {
// Rehashing support for tables containing pointers to this
unsigned int new_hash(juint seed) { ShouldNotReachHere(); return 0; }
virtual bool is_metadata() const volatile { return true; }
virtual bool is_klass() const volatile { return false; }
virtual bool is_method() const volatile { return false; }
virtual bool is_methodData() const volatile { return false; }
......
......@@ -3180,7 +3180,8 @@ bool LibraryCallKit::inline_native_currentThread() {
// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted);
bool LibraryCallKit::inline_native_isInterrupted() {
// Add a fast path to t.isInterrupted(clear_int):
// (t == Thread.current() && (!TLS._osthread._interrupted || !clear_int))
// (t == Thread.current() &&
// (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int)))
// ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int)
// So, in the common case that the interrupt bit is false,
// we avoid making a call into the VM. Even if the interrupt bit
......@@ -3237,6 +3238,7 @@ bool LibraryCallKit::inline_native_isInterrupted() {
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_bit)));
#ifndef TARGET_OS_FAMILY_windows
// (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path.
Node* clr_arg = argument(1);
Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0)));
......@@ -3250,6 +3252,10 @@ bool LibraryCallKit::inline_native_isInterrupted() {
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_arg)));
#else
// To return true on Windows you must read the _interrupted field
// and check the the event state i.e. take the slow path.
#endif // TARGET_OS_FAMILY_windows
// (d) Otherwise, go to the slow path.
slow_region->add_req(control());
......
......@@ -4360,7 +4360,7 @@ JVM_END
JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size))
{
memset(info, 0, sizeof(info_size));
memset(info, 0, info_size);
info->jvm_version = Abstract_VM_Version::jvm_version();
info->update_version = 0; /* 0 in HotSpot Express VM */
......
......@@ -1464,7 +1464,19 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) {
// It's fine to update the thread state here because no JVMTI events
// shall be posted for this PopFrame.
state->update_for_pop_top_frame();
// It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a vm-safepoint-op for safety.
if (java_thread == JavaThread::current()) {
state->update_for_pop_top_frame();
} else {
VM_UpdateForPopTopFrame op(state);
VMThread::execute(&op);
jvmtiError err = op.result();
if (err != JVMTI_ERROR_NONE) {
return err;
}
}
java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
// Set pending step flag for this popframe and it is cleared when next
// step event is posted.
......@@ -1505,6 +1517,7 @@ JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* metho
// depth - pre-checked as non-negative
jvmtiError
JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
jvmtiError err = JVMTI_ERROR_NONE;
ResourceMark rm;
uint32_t debug_bits = 0;
......@@ -1532,10 +1545,17 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL");
int frame_number = state->count_frames() - depth;
state->env_thread_state(this)->set_frame_pop(frame_number);
return JVMTI_ERROR_NONE;
// It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a vm-safepoint-op for safety.
if (java_thread == JavaThread::current()) {
int frame_number = state->count_frames() - depth;
state->env_thread_state(this)->set_frame_pop(frame_number);
} else {
VM_SetFramePop op(this, state, depth);
VMThread::execute(&op);
err = op.result();
}
return err;
} /* end NotifyFramePop */
......
......@@ -29,6 +29,7 @@
#include "prims/jvmtiEnvThreadState.hpp"
#include "prims/jvmtiEventController.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "prims/jvmtiThreadState.inline.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/frame.hpp"
#include "runtime/handles.inline.hpp"
......@@ -334,6 +335,60 @@ class JvmtiEnvIterator : public StackObj {
JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); }
};
// VM operation to update for pop top frame.
class VM_UpdateForPopTopFrame : public VM_Operation {
private:
JvmtiThreadState* _state;
jvmtiError _result;
public:
VM_UpdateForPopTopFrame(JvmtiThreadState* state) {
_state = state;
_result = JVMTI_ERROR_NONE;
}
VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; }
jvmtiError result() { return _result; }
void doit() {
JavaThread* jt = _state->get_thread();
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
_state->update_for_pop_top_frame();
} else {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
};
// VM operation to set frame pop.
class VM_SetFramePop : public VM_Operation {
private:
JvmtiEnv *_env;
JvmtiThreadState* _state;
jint _depth;
jvmtiError _result;
public:
VM_SetFramePop(JvmtiEnv *env, JvmtiThreadState* state, jint depth) {
_env = env;
_state = state;
_depth = depth;
_result = JVMTI_ERROR_NONE;
}
// Nested operation must be allowed for the VM_EnterInterpOnlyMode that is
// called from the JvmtiEventControllerPrivate::recompute_thread_enabled.
bool allow_nested_vm_operations() const { return true; }
VMOp_Type type() const { return VMOp_SetFramePop; }
jvmtiError result() { return _result; }
void doit() {
JavaThread* jt = _state->get_thread();
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
int frame_number = _state->count_frames() - _depth;
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
} else {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
};
// VM operation to get monitor information with stack depth.
class VM_GetOwnedMonitorInfo : public VM_Operation {
......
......@@ -190,12 +190,8 @@ void JvmtiEnvThreadState::compare_and_set_current_location(Method* new_method,
JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() {
#ifdef ASSERT
uint32_t debug_bits = 0;
#endif
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"frame pop data only accessible from same thread or while suspended");
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"frame pop data only accessible from same thread or at safepoint");
if (_frame_pops == NULL) {
_frame_pops = new JvmtiFramePops();
assert(_frame_pops != NULL, "_frame_pops != NULL");
......@@ -209,44 +205,32 @@ bool JvmtiEnvThreadState::has_frame_pops() {
}
void JvmtiEnvThreadState::set_frame_pop(int frame_number) {
#ifdef ASSERT
uint32_t debug_bits = 0;
#endif
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"frame pop data only accessible from same thread or while suspended");
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"frame pop data only accessible from same thread or at safepoint");
JvmtiFramePop fpop(frame_number);
JvmtiEventController::set_frame_pop(this, fpop);
}
void JvmtiEnvThreadState::clear_frame_pop(int frame_number) {
#ifdef ASSERT
uint32_t debug_bits = 0;
#endif
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"frame pop data only accessible from same thread or while suspended");
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"frame pop data only accessible from same thread or at safepoint");
JvmtiFramePop fpop(frame_number);
JvmtiEventController::clear_frame_pop(this, fpop);
}
void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) {
#ifdef ASSERT
uint32_t debug_bits = 0;
#endif
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"frame pop data only accessible from same thread or while suspended");
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"frame pop data only accessible from same thread or at safepoint");
JvmtiFramePop fpop(frame_number);
JvmtiEventController::clear_to_frame_pop(this, fpop);
}
bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) {
#ifdef ASSERT
uint32_t debug_bits = 0;
#endif
assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"frame pop data only accessible from same thread or while suspended");
assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"frame pop data only accessible from same thread or at safepoint");
if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) {
return false;
}
......
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2014, 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
......@@ -989,21 +989,21 @@ JvmtiEventController::set_extension_event_callback(JvmtiEnvBase *env,
void
JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
MutexLocker mu(JvmtiThreadState_lock);
MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
JvmtiEventControllerPrivate::set_frame_pop(ets, fpop);
}
void
JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
MutexLocker mu(JvmtiThreadState_lock);
MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop);
}
void
JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
MutexLocker mu(JvmtiThreadState_lock);
MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
JvmtiEventControllerPrivate::clear_to_frame_pop(ets, fpop);
}
......
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2014, 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
......@@ -63,6 +63,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread)
_vm_object_alloc_event_collector = NULL;
_the_class_for_redefinition_verification = NULL;
_scratch_class_for_redefinition_verification = NULL;
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
// JVMTI ForceEarlyReturn support
_pending_step_for_earlyret = false;
......@@ -213,12 +214,9 @@ void JvmtiThreadState::leave_interp_only_mode() {
// Helper routine used in several places
int JvmtiThreadState::count_frames() {
#ifdef ASSERT
uint32_t debug_bits = 0;
#endif
assert(SafepointSynchronize::is_at_safepoint() ||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"at safepoint or must be suspended");
guarantee(SafepointSynchronize::is_at_safepoint() ||
(JavaThread *)Thread::current() == get_thread(),
"must be current thread or at safepoint");
if (!get_thread()->has_last_Java_frame()) return 0; // no Java frames
......@@ -243,15 +241,9 @@ int JvmtiThreadState::count_frames() {
void JvmtiThreadState::invalidate_cur_stack_depth() {
Thread *cur = Thread::current();
uint32_t debug_bits = 0;
// The caller can be the VMThread at a safepoint, the current thread
// or the target thread must be suspended.
guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) ||
(JavaThread *)cur == get_thread() ||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"sanity check");
guarantee(SafepointSynchronize::is_at_safepoint() ||
(JavaThread *)Thread::current() == get_thread(),
"must be current thread or at safepoint");
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
}
......@@ -280,10 +272,9 @@ void JvmtiThreadState::decr_cur_stack_depth() {
}
int JvmtiThreadState::cur_stack_depth() {
uint32_t debug_bits = 0;
guarantee(JavaThread::current() == get_thread() ||
JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
"must be current thread or suspended");
guarantee(SafepointSynchronize::is_at_safepoint() ||
(JavaThread *)Thread::current() == get_thread(),
"must be current thread or at safepoint");
if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) {
_cur_stack_depth = count_frames();
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, 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
......@@ -74,6 +74,8 @@
template(PopulateDumpSharedSpace) \
template(JNIFunctionTableCopier) \
template(RedefineClasses) \
template(UpdateForPopTopFrame) \
template(SetFramePop) \
template(GetOwnedMonitorInfo) \
template(GetObjectMonitorUsage) \
template(GetCurrentContendedMonitor) \
......
......@@ -25,7 +25,7 @@
* @test
* @bug 6294277
* @summary java -Xdebug crashes on SourceDebugExtension attribute larger than 64K
* @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=n SourceDebugExtension
* @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n SourceDebugExtension
*/
import java.io.*;
......
/*
* Copyright (c) 2014, 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
* @summary Redefine a class with an UnresolvedClass reference in the constant pool.
* @bug 8035150
* @library /testlibrary
* @build UnresolvedClassAgent com.oracle.java.testlibrary.ProcessTools com.oracle.java.testlibrary.OutputAnalyzer
* @run main TestRedefineWithUnresolvedClass
*/
import java.io.File;
import java.util.Arrays;
import com.oracle.java.testlibrary.OutputAnalyzer;
import com.oracle.java.testlibrary.ProcessTools;
public class TestRedefineWithUnresolvedClass {
final static String slash = File.separator;
final static String testClasses = System.getProperty("test.classes") + slash;
public static void main(String... args) throws Throwable {
// delete this class to cause a NoClassDefFoundError
File unresolved = new File(testClasses, "MyUnresolvedClass.class");
if (unresolved.exists() && !unresolved.delete()) {
throw new Exception("Could not delete: " + unresolved);
}
// build the javaagent
buildJar("UnresolvedClassAgent");
// launch a VM with the javaagent
launchTest();
}
private static void buildJar(String jarName) throws Throwable {
String testSrc = System.getProperty("test.src", "?") + slash;
String jarPath = String.format("%s%s.jar", testClasses, jarName);
String manifestPath = String.format("%s%s.mf", testSrc, jarName);
String className = String.format("%s.class", jarName);
String[] args = new String[] {"-cfm", jarPath, manifestPath, "-C", testClasses, className};
System.out.println("Running jar " + Arrays.toString(args));
sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
if (!jarTool.run(args)) {
throw new Exception("jar failed: args=" + Arrays.toString(args));
}
}
private static void launchTest() throws Throwable {
String[] args = {
"-javaagent:" + testClasses + "UnresolvedClassAgent.jar",
"-Dtest.classes=" + testClasses,
"UnresolvedClassAgent" };
OutputAnalyzer output = ProcessTools.executeTestJvm(args);
output.shouldHaveExitValue(0);
}
}
/*
* Copyright (c) 2014, 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.
*/
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
/*
* This class is present during compilation, but will be deleted before execution.
*/
class MyUnresolvedClass {
static void bar() {
}
}
class MyRedefinedClass {
static void foo() {
MyUnresolvedClass.bar();
}
}
public class UnresolvedClassAgent {
public static void main(String... args) {
}
public static void premain(String args, Instrumentation inst) throws Exception {
try {
MyRedefinedClass.foo();
} catch(NoClassDefFoundError err) {
System.out.println("NoClassDefFoundError (expected)");
}
File f = new File(System.getProperty("test.classes"), "MyRedefinedClass.class");
byte[] buf = new byte[(int)f.length()];
try (DataInputStream dis = new DataInputStream(new FileInputStream(f))) {
dis.readFully(buf);
}
ClassDefinition cd = new ClassDefinition(MyRedefinedClass.class, buf);
inst.redefineClasses(new ClassDefinition[] {cd});
try {
MyRedefinedClass.foo();
} catch(NoClassDefFoundError err) {
System.out.println("NoClassDefFoundError (expected again)");
}
}
}
Manifest-Version: 1.0
Premain-Class: UnresolvedClassAgent
Can-Redefine-Classes: true
......@@ -163,10 +163,87 @@ public final class ProcessTools {
// Reporting
StringBuilder cmdLine = new StringBuilder();
for (String cmd : args)
cmdLine.append(cmd).append(' ');
for (String cmd : args) {
cmdLine.append(cmd).append(' ');
}
System.out.println("Command line: [" + cmdLine.toString() + "]");
return new ProcessBuilder(args.toArray(new String[args.size()]));
}
/**
* Executes a test jvm process, waits for it to finish and returns the process output.
* The default jvm options from jtreg, test.vm.opts and test.java.opts, are added.
* The java from the test.jdk is used to execute the command.
*
* The command line will be like:
* {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds
*
* @param cmds User specifed arguments.
* @return The output from the process.
*/
public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable {
ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
return executeProcess(pb);
}
/**
* Executes a process, waits for it to finish and returns the process output.
* @param pb The ProcessBuilder to execute.
* @return The output from the process.
*/
public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable {
OutputAnalyzer output = null;
try {
output = new OutputAnalyzer(pb.start());
return output;
} catch (Throwable t) {
System.out.println("executeProcess() failed: " + t);
throw t;
} finally {
System.out.println(getProcessLog(pb, output));
}
}
/**
* Executes a process, waits for it to finish and returns the process output.
* @param cmds The command line to execute.
* @return The output from the process.
*/
public static OutputAnalyzer executeProcess(String... cmds) throws Throwable {
return executeProcess(new ProcessBuilder(cmds));
}
/**
* Used to log command line, stdout, stderr and exit code from an executed process.
* @param pb The executed process.
* @param output The output from the process.
*/
public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) {
String stderr = output == null ? "null" : output.getStderr();
String stdout = output == null ? "null" : output.getStdout();
String exitValue = output == null ? "null": Integer.toString(output.getExitValue());
StringBuilder logMsg = new StringBuilder();
final String nl = System.getProperty("line.separator");
logMsg.append("--- ProcessLog ---" + nl);
logMsg.append("cmd: " + getCommandLine(pb) + nl);
logMsg.append("exitvalue: " + exitValue + nl);
logMsg.append("stderr: " + stderr + nl);
logMsg.append("stdout: " + stdout + nl);
return logMsg.toString();
}
/**
* @return The full command line for the ProcessBuilder.
*/
public static String getCommandLine(ProcessBuilder pb) {
if (pb == null) {
return "null";
}
StringBuilder cmd = new StringBuilder();
for (String s : pb.command()) {
cmd.append(s).append(" ");
}
return cmd.toString().trim();
}
}
/*
* Copyright (c) 2013, 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.
*/
package com.oracle.java.testlibrary;
import static com.oracle.java.testlibrary.Asserts.assertTrue;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import java.util.Collections;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Common library for various test helper functions.
*/
public final class Utils {
/**
* Returns the sequence used by operating system to separate lines.
*/
public static final String NEW_LINE = System.getProperty("line.separator");
/**
* Returns the value of 'test.vm.opts'system property.
*/
public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim();
/**
* Returns the value of 'test.java.opts'system property.
*/
public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim();
/**
* Returns the value of 'test.timeout.factor' system property
* converted to {@code double}.
*/
public static final double TIMEOUT_FACTOR;
static {
String toFactor = System.getProperty("test.timeout.factor", "1.0");
TIMEOUT_FACTOR = Double.parseDouble(toFactor);
}
private Utils() {
// Private constructor to prevent class instantiation
}
/**
* Returns the list of VM options.
*
* @return List of VM options
*/
public static List<String> getVmOptions() {
return Arrays.asList(safeSplitString(VM_OPTIONS));
}
/**
* Returns the list of VM options with -J prefix.
*
* @return The list of VM options with -J prefix
*/
public static List<String> getForwardVmOptions() {
String[] opts = safeSplitString(VM_OPTIONS);
for (int i = 0; i < opts.length; i++) {
opts[i] = "-J" + opts[i];
}
return Arrays.asList(opts);
}
/**
* Returns the default JTReg arguments for a jvm running a test.
* This is the combination of JTReg arguments test.vm.opts and test.java.opts.
* @return An array of options, or an empty array if no opptions.
*/
public static String[] getTestJavaOpts() {
List<String> opts = new ArrayList<String>();
Collections.addAll(opts, safeSplitString(VM_OPTIONS));
Collections.addAll(opts, safeSplitString(JAVA_OPTIONS));
return opts.toArray(new String[0]);
}
/**
* Combines given arguments with default JTReg arguments for a jvm running a test.
* This is the combination of JTReg arguments test.vm.opts and test.java.opts
* @return The combination of JTReg test java options and user args.
*/
public static String[] addTestJavaOpts(String... userArgs) {
List<String> opts = new ArrayList<String>();
Collections.addAll(opts, getTestJavaOpts());
Collections.addAll(opts, userArgs);
return opts.toArray(new String[0]);
}
/**
* Splits a string by white space.
* Works like String.split(), but returns an empty array
* if the string is null or empty.
*/
private static String[] safeSplitString(String s) {
if (s == null || s.trim().isEmpty()) {
return new String[] {};
}
return s.trim().split("\\s+");
}
/**
* @return The full command line for the ProcessBuilder.
*/
public static String getCommandLine(ProcessBuilder pb) {
StringBuilder cmd = new StringBuilder();
for (String s : pb.command()) {
cmd.append(s).append(" ");
}
return cmd.toString();
}
/**
* Returns the free port on the local host.
* The function will spin until a valid port number is found.
*
* @return The port number
* @throws InterruptedException if any thread has interrupted the current thread
* @throws IOException if an I/O error occurs when opening the socket
*/
public static int getFreePort() throws InterruptedException, IOException {
int port = -1;
while (port <= 0) {
Thread.sleep(100);
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(0);
port = serverSocket.getLocalPort();
} finally {
serverSocket.close();
}
}
return port;
}
/**
* Returns the name of the local host.
*
* @return The host name
* @throws UnknownHostException if IP address of a host could not be determined
*/
public static String getHostname() throws UnknownHostException {
InetAddress inetAddress = InetAddress.getLocalHost();
String hostName = inetAddress.getHostName();
assertTrue((hostName != null && !hostName.isEmpty()),
"Cannot get hostname");
return hostName;
}
/**
* Uses "jcmd -l" to search for a jvm pid. This function will wait
* forever (until jtreg timeout) for the pid to be found.
* @param key Regular expression to search for
* @return The found pid.
*/
public static int waitForJvmPid(String key) throws Throwable {
final long iterationSleepMillis = 250;
System.out.println("waitForJvmPid: Waiting for key '" + key + "'");
System.out.flush();
while (true) {
int pid = tryFindJvmPid(key);
if (pid >= 0) {
return pid;
}
Thread.sleep(iterationSleepMillis);
}
}
/**
* Searches for a jvm pid in the output from "jcmd -l".
*
* Example output from jcmd is:
* 12498 sun.tools.jcmd.JCmd -l
* 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar
*
* @param key A regular expression to search for.
* @return The found pid, or -1 if Enot found.
* @throws Exception If multiple matching jvms are found.
*/
public static int tryFindJvmPid(String key) throws Throwable {
OutputAnalyzer output = null;
try {
JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd");
jcmdLauncher.addToolArg("-l");
output = ProcessTools.executeProcess(jcmdLauncher.getCommand());
output.shouldHaveExitValue(0);
// Search for a line starting with numbers (pid), follwed by the key.
Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n");
Matcher matcher = pattern.matcher(output.getStdout());
int pid = -1;
if (matcher.find()) {
pid = Integer.parseInt(matcher.group(1));
System.out.println("findJvmPid.pid: " + pid);
if (matcher.find()) {
throw new Exception("Found multiple JVM pids for key: " + key);
}
}
return pid;
} catch (Throwable t) {
System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t));
throw t;
}
}
/**
* Returns file content as a list of strings
*
* @param file File to operate on
* @return List of strings
* @throws IOException
*/
public static List<String> fileAsList(File file) throws IOException {
assertTrue(file.exists() && file.isFile(),
file.getAbsolutePath() + " does not exist or not a file");
List<String> output = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) {
while (reader.ready()) {
output.add(reader.readLine().replace(NEW_LINE, ""));
}
}
return output;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册