--- a/hotspot/make/windows/makefiles/compile.make Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/make/windows/makefiles/compile.make Mon Sep 28 15:05:02 2015 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2015, 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
@@ -31,6 +31,7 @@
# /nologo Supress copyright message at every cl.exe startup
# /W3 Warning level 3
# /Zi Include debugging information
+# /d2Zi+ Extended debugging symbols for optimized code (/Zo in VS2013 Update 3 and later)
# /WX Treat any warning error as a fatal error
# /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*NN.dll)
# /MTd Use static multi-threaded runtime debug versions
@@ -57,7 +58,7 @@
# Let's add debug information when Full Debug Symbols is enabled
!if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1"
-CXX_FLAGS=$(CXX_FLAGS) /Zi
+CXX_FLAGS=$(CXX_FLAGS) /Zi /d2Zi+
!endif
# Based on BUILDARCH we add some flags and select the default compiler name
--- a/hotspot/make/windows/makefiles/vm.make Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/make/windows/makefiles/vm.make Mon Sep 28 15:05:02 2015 +0200
@@ -163,6 +163,7 @@
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/cms
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/g1
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/asm
+VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/logging
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/memory
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/oops
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims
@@ -250,6 +251,9 @@
{$(COMMONSRC)\share\vm\asm}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+{$(COMMONSRC)\share\vm\logging}.cpp.obj::
+ $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+
{$(COMMONSRC)\share\vm\memory}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
@@ -330,6 +334,9 @@
{$(ALTSRC)\share\vm\asm}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+{$(ALTSRC)\share\vm\logging}.cpp.obj::
+ $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+
{$(ALTSRC)\share\vm\memory}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -3063,11 +3063,15 @@
if (UseCondCardMark) {
Label L_already_dirty;
+ membar(StoreLoad);
ldrb(rscratch2, Address(obj, rscratch1));
cbz(rscratch2, L_already_dirty);
strb(zr, Address(obj, rscratch1));
bind(L_already_dirty);
} else {
+ if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
+ membar(StoreStore);
+ }
strb(zr, Address(obj, rscratch1));
}
}
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -746,6 +746,9 @@
const Register count = end; // 'end' register contains bytes count now
__ mov(scratch, (address)ct->byte_map_base);
__ add(start, start, scratch);
+ if (UseConcMarkSweepGC) {
+ __ membar(__ StoreStore);
+ }
__ BIND(L_loop);
__ strb(zr, Address(start, count));
__ subs(count, count, 1);
--- a/hotspot/src/share/vm/Xusage.txt Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/Xusage.txt Mon Sep 28 15:05:02 2015 +0200
@@ -7,6 +7,7 @@
-Xbootclasspath/p:<directories and zip/jar files separated by ;>
prepend in front of bootstrap class path
-Xnoclassgc disable class garbage collection
+ -Xlog:<opts> control JVM logging, use -Xlog:help for details
-Xloggc:<file> log GC status to a file with time stamps
-Xbatch disable background compilation
-Xms<size> set initial Java heap size
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -1630,6 +1630,9 @@
__ move(dirty, card_addr);
__ branch_destination(L_already_dirty->label());
} else {
+ if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
+ __ membar_storestore();
+ }
__ move(dirty, card_addr);
}
#endif
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -1235,7 +1235,8 @@
}
// Helper class to get rid of some boilerplate code.
-class G1CMTraceTime : public GCTraceTime {
+class G1CMTraceTime : public StackObj {
+ GCTraceTimeImpl _gc_trace_time;
static bool doit_and_prepend(bool doit) {
if (doit) {
gclog_or_tty->put(' ');
@@ -1245,7 +1246,7 @@
public:
G1CMTraceTime(const char* title, bool doit)
- : GCTraceTime(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm(),
+ : _gc_trace_time(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm(),
G1CollectedHeap::heap()->concurrent_mark()->concurrent_gc_id()) {
}
};
--- a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -197,7 +197,9 @@
}
void G1CodeRootSet::allocate_small_table() {
- _table = new CodeRootSetTable(SmallSize);
+ CodeRootSetTable* temp = new CodeRootSetTable(SmallSize);
+
+ OrderAccess::release_store_ptr(&_table, temp);
}
void CodeRootSetTable::purge_list_append(CodeRootSetTable* table) {
--- a/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -35,7 +35,7 @@
#include "utilities/ticks.inline.hpp"
-GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id) :
+GCTraceTimeImpl::GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id) :
_title(title), _doit(doit), _print_cr(print_cr), _timer(timer), _start_counter() {
if (_doit || _timer != NULL) {
_start_counter.stamp();
@@ -59,7 +59,7 @@
}
}
-GCTraceTime::~GCTraceTime() {
+GCTraceTimeImpl::~GCTraceTimeImpl() {
Ticks stop_counter;
if (_doit || _timer != NULL) {
--- a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -26,12 +26,13 @@
#define SHARE_VM_GC_SHARED_GCTRACETIME_HPP
#include "gc/shared/gcTrace.hpp"
+#include "memory/allocation.hpp"
#include "prims/jni_md.h"
#include "utilities/ticks.hpp"
class GCTimer;
-class GCTraceTime {
+class GCTraceTimeImpl VALUE_OBJ_CLASS_SPEC {
const char* _title;
bool _doit;
bool _print_cr;
@@ -39,8 +40,16 @@
Ticks _start_counter;
public:
- GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id);
- ~GCTraceTime();
+ GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id);
+ ~GCTraceTimeImpl();
+};
+
+class GCTraceTime : public StackObj {
+ GCTraceTimeImpl _gc_trace_time_impl;
+
+ public:
+ GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id) :
+ _gc_trace_time_impl(title, doit, print_cr, timer, gc_id) {};
};
#endif // SHARE_VM_GC_SHARED_GCTRACETIME_HPP
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -31,6 +31,7 @@
#include "gc/shared/gcTraceTime.hpp"
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessor.hpp"
+#include "memory/allocation.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/jniHandles.hpp"
@@ -182,6 +183,21 @@
return total;
}
+static void log_ref_count(size_t count, bool doit) {
+ if (doit) {
+ gclog_or_tty->print(", " SIZE_FORMAT " refs", count);
+ }
+}
+
+class GCRefTraceTime : public StackObj {
+ GCTraceTimeImpl _gc_trace_time;
+ public:
+ GCRefTraceTime(const char* title, bool doit, GCTimer* timer, GCId gc_id, size_t count) :
+ _gc_trace_time(title, doit, false, timer, gc_id) {
+ log_ref_count(count, doit);
+ }
+};
+
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
@@ -206,48 +222,48 @@
bool trace_time = PrintGCDetails && PrintReferenceGC;
+ // Include cleaners in phantom statistics. We expect Cleaner
+ // references to be temporary, and don't want to deal with
+ // possible incompatibilities arising from making it more visible.
+ ReferenceProcessorStats stats(
+ total_count(_discoveredSoftRefs),
+ total_count(_discoveredWeakRefs),
+ total_count(_discoveredFinalRefs),
+ total_count(_discoveredPhantomRefs) + total_count(_discoveredCleanerRefs));
+
// Soft references
- size_t soft_count = 0;
{
- GCTraceTime tt("SoftReference", trace_time, false, gc_timer, gc_id);
- soft_count =
- process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCRefTraceTime tt("SoftReference", trace_time, gc_timer, gc_id, stats.soft_count());
+ process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
+ is_alive, keep_alive, complete_gc, task_executor);
}
update_soft_ref_master_clock();
// Weak references
- size_t weak_count = 0;
{
- GCTraceTime tt("WeakReference", trace_time, false, gc_timer, gc_id);
- weak_count =
- process_discovered_reflist(_discoveredWeakRefs, NULL, true,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCRefTraceTime tt("WeakReference", trace_time, gc_timer, gc_id, stats.weak_count());
+ process_discovered_reflist(_discoveredWeakRefs, NULL, true,
+ is_alive, keep_alive, complete_gc, task_executor);
}
// Final references
- size_t final_count = 0;
{
- GCTraceTime tt("FinalReference", trace_time, false, gc_timer, gc_id);
- final_count =
- process_discovered_reflist(_discoveredFinalRefs, NULL, false,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCRefTraceTime tt("FinalReference", trace_time, gc_timer, gc_id, stats.final_count());
+ process_discovered_reflist(_discoveredFinalRefs, NULL, false,
+ is_alive, keep_alive, complete_gc, task_executor);
}
// Phantom references
- size_t phantom_count = 0;
{
- GCTraceTime tt("PhantomReference", trace_time, false, gc_timer, gc_id);
- phantom_count =
- process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCRefTraceTime tt("PhantomReference", trace_time, gc_timer, gc_id, stats.phantom_count());
+ process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
+ is_alive, keep_alive, complete_gc, task_executor);
- // Process cleaners, but include them in phantom statistics. We expect
+ // Process cleaners, but include them in phantom timing. We expect
// Cleaner references to be temporary, and don't want to deal with
// possible incompatibilities arising from making it more visible.
- phantom_count +=
- process_discovered_reflist(_discoveredCleanerRefs, NULL, true,
+ process_discovered_reflist(_discoveredCleanerRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}
@@ -258,13 +274,14 @@
// resurrect a "post-mortem" object.
{
GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer, gc_id);
+ NOT_PRODUCT(log_ref_count(count_jni_refs(), trace_time);)
if (task_executor != NULL) {
task_executor->set_single_threaded_mode();
}
process_phaseJNI(is_alive, keep_alive, complete_gc);
}
- return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count);
+ return stats;
}
#ifndef PRODUCT
@@ -294,12 +311,6 @@
void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc) {
-#ifndef PRODUCT
- if (PrintGCDetails && PrintReferenceGC) {
- unsigned int count = count_jni_refs();
- gclog_or_tty->print(", %u refs", count);
- }
-#endif
JNIHandles::weak_oops_do(is_alive, keep_alive);
complete_gc->do_void();
}
@@ -826,8 +837,7 @@
balance_queues(_discoveredCleanerRefs);
}
-size_t
-ReferenceProcessor::process_discovered_reflist(
+void ReferenceProcessor::process_discovered_reflist(
DiscoveredList refs_lists[],
ReferencePolicy* policy,
bool clear_referent,
@@ -850,12 +860,6 @@
balance_queues(refs_lists);
}
- size_t total_list_count = total_count(refs_lists);
-
- if (PrintReferenceGC && PrintGCDetails) {
- gclog_or_tty->print(", " SIZE_FORMAT " refs", total_list_count);
- }
-
// Phase 1 (soft refs only):
// . Traverse the list and remove any SoftReferences whose
// referents are not alive, but that should be kept alive for
@@ -898,8 +902,6 @@
is_alive, keep_alive, complete_gc);
}
}
-
- return total_list_count;
}
inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -263,13 +263,13 @@
}
// Process references with a certain reachability level.
- size_t process_discovered_reflist(DiscoveredList refs_lists[],
- ReferencePolicy* policy,
- bool clear_referent,
- BoolObjectClosure* is_alive,
- OopClosure* keep_alive,
- VoidClosure* complete_gc,
- AbstractRefProcTaskExecutor* task_executor);
+ void process_discovered_reflist(DiscoveredList refs_lists[],
+ ReferencePolicy* policy,
+ bool clear_referent,
+ BoolObjectClosure* is_alive,
+ OopClosure* keep_alive,
+ VoidClosure* complete_gc,
+ AbstractRefProcTaskExecutor* task_executor);
void process_phaseJNI(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/log.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOG_HPP
+#define SHARE_VM_LOGGING_LOG_HPP
+
+#include "logging/logLevel.hpp"
+#include "logging/logPrefix.hpp"
+#include "logging/logTagSet.hpp"
+#include "logging/logTag.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/ostream.hpp"
+
+//
+// Logging macros
+//
+// Usage:
+// log_<level>(<comma separated log tags>)(<printf-style log arguments>);
+// e.g.
+// log_debug(logging)("message %d", i);
+//
+// Note that these macros will not evaluate the arguments unless the logging is enabled.
+//
+#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Error>
+#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Warning>
+#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
+#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
+#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
+#ifndef PRODUCT
+#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Develop>
+#else
+#define DUMMY_ARGUMENT_CONSUMER(...)
+#define log_develop(...) DUMMY_ARGUMENT_CONSUMER
+#endif
+
+// Convenience macro to test if the logging is enabled on the specified level for given tags.
+#define log_is_enabled(level, ...) (Log<LOG_TAGS(__VA_ARGS__)>::is_level(LogLevel::level))
+
+//
+// Log class for more advanced logging scenarios.
+// Has printf-style member functions for each log level (trace(), debug(), etc).
+//
+// Also has outputStream compatible API for the different log-levels.
+// The streams are resource allocated when requested and are accessed through
+// calls to <level>_stream() functions (trace_stream(), debug_stream(), etc).
+//
+// Example usage:
+// LogHandle(logging) log;
+// if (log.is_debug()) {
+// ...
+// log.debug("result = %d", result).trace(" tracing info");
+// obj->print_on(log.debug_stream());
+// }
+//
+#define LogHandle(...) Log<LOG_TAGS(__VA_ARGS__)>
+
+template <LogTagType T0, LogTagType T1 = LogTag::__NO_TAG, LogTagType T2 = LogTag::__NO_TAG, LogTagType T3 = LogTag::__NO_TAG,
+ LogTagType T4 = LogTag::__NO_TAG, LogTagType GuardTag = LogTag::__NO_TAG>
+class Log VALUE_OBJ_CLASS_SPEC {
+ private:
+ static const size_t LogBufferSize = 512;
+ public:
+ // Make sure no more than the maximum number of tags have been given.
+ // The GuardTag allows this to be detected if/when it happens. If the GuardTag
+ // is not __NO_TAG, the number of tags given exceeds the maximum allowed.
+ STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported!
+
+ static bool is_level(LogLevelType level) {
+ return LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().is_level(level);
+ }
+
+ template <LogLevelType Level>
+ ATTRIBUTE_PRINTF(1, 2)
+ static void write(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vwrite<Level>(fmt, args);
+ va_end(args);
+ };
+
+ template <LogLevelType Level>
+ ATTRIBUTE_PRINTF(1, 0)
+ static void vwrite(const char* fmt, va_list args) {
+ char buf[LogBufferSize];
+ size_t prefix_len = LogPrefix<T0, T1, T2, T3, T4>::prefix(buf, sizeof(buf));
+ int ret = vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args);
+ assert(ret >= 0 && (size_t)ret < sizeof(buf), "Log message too long");
+ puts<Level>(buf);
+ }
+
+ template <LogLevelType Level>
+ static void puts(const char* string) {
+ LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().log(Level, string);
+ }
+
+#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \
+ Log& v##name(const char* fmt, va_list args) { \
+ vwrite<LogLevel::level>(fmt, args); \
+ return *this; \
+ } \
+ Log& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \
+ va_list args; \
+ va_start(args, fmt); \
+ vwrite<LogLevel::level>(fmt, args); \
+ va_end(args); \
+ return *this; \
+ } \
+ static bool is_##name() { \
+ return is_level(LogLevel::level); \
+ } \
+ static outputStream* name##_stream() { \
+ return new logStream(write<LogLevel::level>); \
+ }
+ LOG_LEVEL_LIST
+#undef LOG_LEVEL
+};
+
+#endif // SHARE_VM_LOGGING_LOG_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "logging/logConfiguration.hpp"
+#include "logging/logDecorations.hpp"
+#include "logging/logDecorators.hpp"
+#include "logging/logDiagnosticCommand.hpp"
+#include "logging/logFileOutput.hpp"
+#include "logging/logOutput.hpp"
+#include "logging/logTagLevelExpression.hpp"
+#include "logging/logTagSet.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/os.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+LogOutput** LogConfiguration::_outputs = NULL;
+size_t LogConfiguration::_n_outputs = 0;
+
+void LogConfiguration::post_initialize() {
+ assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization");
+ LogDiagnosticCommand::registerCommand();
+ LogHandle(logging) log;
+ log.info("Log configuration fully initialized.");
+ if (log.is_trace()) {
+ ResourceMark rm;
+ MutexLocker ml(LogConfiguration_lock);
+ describe(log.trace_stream());
+ }
+}
+
+void LogConfiguration::initialize(jlong vm_start_time) {
+ LogFileOutput::set_file_name_parameters(vm_start_time);
+ LogDecorations::set_vm_start_time_millis(vm_start_time);
+
+ assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
+ _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
+ _outputs[0] = LogOutput::Stdout;
+ _outputs[1] = LogOutput::Stderr;
+ _n_outputs = 2;
+}
+
+void LogConfiguration::finalize() {
+ for (size_t i = 2; i < _n_outputs; i++) {
+ delete _outputs[i];
+ }
+ FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
+}
+
+size_t LogConfiguration::find_output(const char* name) {
+ for (size_t i = 0; i < _n_outputs; i++) {
+ if (strcmp(_outputs[i]->name(), name) == 0) {
+ return i;
+ }
+ }
+ return SIZE_MAX;
+}
+
+LogOutput* LogConfiguration::new_output(char* name, const char* options) {
+ const char* type;
+ char* equals_pos = strchr(name, '=');
+ if (equals_pos == NULL) {
+ type = "file";
+ } else {
+ *equals_pos = '\0';
+ type = name;
+ name = equals_pos + 1;
+ }
+
+ LogOutput* output;
+ if (strcmp(type, "file") == 0) {
+ output = new LogFileOutput(name);
+ } else {
+ // unsupported log output type
+ return NULL;
+ }
+
+ bool success = output->initialize(options);
+ if (!success) {
+ delete output;
+ return NULL;
+ }
+ return output;
+}
+
+size_t LogConfiguration::add_output(LogOutput* output) {
+ size_t idx = _n_outputs++;
+ _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
+ _outputs[idx] = output;
+ return idx;
+}
+
+void LogConfiguration::delete_output(size_t idx) {
+ assert(idx > 1 && idx < _n_outputs,
+ err_msg("idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT
+ " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs));
+ LogOutput* output = _outputs[idx];
+ // Swap places with the last output and shrink the array
+ _outputs[idx] = _outputs[--_n_outputs];
+ _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
+ delete output;
+}
+
+void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) {
+ assert(idx < _n_outputs, err_msg("Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs));
+ LogOutput* output = _outputs[idx];
+ output->set_decorators(decorators);
+ output->set_config_string(tag_level_expression.to_string());
+ bool enabled = false;
+ for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
+ LogLevelType level = tag_level_expression.level_for(*ts);
+ if (level != LogLevel::Off) {
+ enabled = true;
+ }
+ ts->update_decorators(decorators);
+ ts->set_output_level(output, level);
+ }
+
+ // If the output is not used by any tagset it should be removed, unless it is stdout/stderr.
+ if (!enabled && idx > 1) {
+ delete_output(idx);
+ }
+}
+
+void LogConfiguration::disable_output(size_t idx) {
+ LogOutput* out = _outputs[idx];
+ LogDecorators empty_decorators;
+ empty_decorators.clear();
+
+ // Remove the output from all tagsets.
+ for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
+ ts->set_output_level(out, LogLevel::Off);
+ ts->update_decorators(empty_decorators);
+ }
+
+ // Delete the output unless stdout/stderr
+ if (out != LogOutput::Stderr && out != LogOutput::Stdout) {
+ delete_output(find_output(out->name()));
+ } else {
+ out->set_config_string("all=off");
+ }
+}
+
+void LogConfiguration::disable_logging() {
+ assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
+ "LogConfiguration lock must be held when calling this function");
+ for (size_t i = 0; i < _n_outputs; i++) {
+ disable_output(i);
+ }
+}
+
+bool LogConfiguration::parse_command_line_arguments(const char* opts) {
+ char* copy = os::strdup_check_oom(opts, mtLogging);
+
+ // Split the option string to its colon separated components.
+ char* what = NULL;
+ char* output_str = NULL;
+ char* decorators_str = NULL;
+ char* output_options = NULL;
+
+ what = copy;
+ char* colon = strchr(what, ':');
+ if (colon != NULL) {
+ *colon = '\0';
+ output_str = colon + 1;
+ colon = strchr(output_str, ':');
+ if (colon != NULL) {
+ *colon = '\0';
+ decorators_str = colon + 1;
+ colon = strchr(decorators_str, ':');
+ if (colon != NULL) {
+ *colon = '\0';
+ output_options = colon + 1;
+ }
+ }
+ }
+
+ // Parse each argument
+ char errbuf[512];
+ stringStream ss(errbuf, sizeof(errbuf));
+ bool success = parse_log_arguments(output_str, what, decorators_str, output_options, &ss);
+ if (!success) {
+ errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline.
+ log_error(logging)("%s", errbuf);
+ }
+
+ os::free(copy);
+ return success;
+}
+
+bool LogConfiguration::parse_log_arguments(const char* outputstr,
+ const char* what,
+ const char* decoratorstr,
+ const char* output_options,
+ outputStream* errstream) {
+ assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
+ "LogConfiguration lock must be held when calling this function");
+ if (outputstr == NULL || strlen(outputstr) == 0) {
+ outputstr = "stdout";
+ }
+
+ size_t idx;
+ if (outputstr[0] == '#') {
+ int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx);
+ if (ret != 1 || idx >= _n_outputs) {
+ errstream->print_cr("Invalid output index '%s'", outputstr);
+ return false;
+ }
+ } else {
+ idx = find_output(outputstr);
+ if (idx == SIZE_MAX) {
+ char* tmp = os::strdup_check_oom(outputstr, mtLogging);
+ LogOutput* output = new_output(tmp, output_options);
+ os::free(tmp);
+ if (output == NULL) {
+ errstream->print("Unable to add output '%s'", outputstr);
+ if (output_options != NULL && strlen(output_options) > 0) {
+ errstream->print(" with options '%s'", output_options);
+ }
+ errstream->cr();
+ return false;
+ }
+ idx = add_output(output);
+ } else if (output_options != NULL && strlen(output_options) > 0) {
+ errstream->print_cr("Output options for existing outputs are ignored.");
+ }
+ }
+
+ LogTagLevelExpression expr;
+ if (!expr.parse(what, errstream)) {
+ return false;
+ }
+
+ LogDecorators decorators;
+ if (!decorators.parse(decoratorstr, errstream)) {
+ return false;
+ }
+
+ configure_output(idx, expr, decorators);
+ return true;
+}
+
+void LogConfiguration::describe(outputStream* out) {
+ assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
+ "LogConfiguration lock must be held when calling this function");
+
+ out->print("Available log levels:");
+ for (size_t i = 0; i < LogLevel::Count; i++) {
+ out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
+ }
+ out->cr();
+
+ out->print("Available log decorators:");
+ for (size_t i = 0; i < LogDecorators::Count; i++) {
+ LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
+ out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
+ }
+ out->cr();
+
+ out->print("Available log tags:");
+ for (size_t i = 1; i < LogTag::Count; i++) {
+ out->print("%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i)));
+ }
+ out->cr();
+
+ out->print_cr("Log output configuration:");
+ for (size_t i = 0; i < _n_outputs; i++) {
+ out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string());
+ for (size_t d = 0; d < LogDecorators::Count; d++) {
+ LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
+ if (_outputs[i]->decorators().is_decorator(decorator)) {
+ out->print("%s,", LogDecorators::name(decorator));
+ }
+ }
+ out->cr();
+ }
+}
+
+void LogConfiguration::print_command_line_help(FILE* out) {
+ jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n"
+ "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n"
+ "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n");
+
+ jio_fprintf(out, "Available log levels:\n");
+ for (size_t i = 0; i < LogLevel::Count; i++) {
+ jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
+ }
+
+ jio_fprintf(out, "\n\nAvailable log decorators: \n");
+ for (size_t i = 0; i < LogDecorators::Count; i++) {
+ LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
+ jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
+ }
+ jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n");
+
+ jio_fprintf(out, "Available log tags:\n");
+ for (size_t i = 1; i < LogTag::Count; i++) {
+ jio_fprintf(out, "%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i)));
+ }
+ jio_fprintf(out, "\n Specifying 'all' instead of a tag combination matches all tag combinations.\n\n");
+
+ jio_fprintf(out, "Available log outputs:\n"
+ " stdout, stderr, file=<filename>\n"
+ " Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n"
+
+ "Some examples:\n"
+ " -Xlog\n"
+ "\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n"
+ "\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n"
+
+ " -Xlog:gc\n"
+ "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n"
+
+ " -Xlog:gc=debug:file=gc.txt:none\n"
+ "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n"
+
+ " -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1024\n"
+ "\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n"
+ "\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n"
+
+ " -Xlog:gc::uptime,tid\n"
+ "\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n"
+
+ " -Xlog:gc*=info,rt*=off\n"
+ "\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'rt'.\n"
+ "\t (Messages tagged with both 'gc' and 'rt' will not be logged.)\n\n"
+
+ " -Xlog:disable -Xlog:rt=trace:rttrace.txt\n"
+ "\t Turn off all logging, including warnings and errors,\n"
+ "\t and then enable messages tagged with 'rt' using 'trace' level to file 'rttrace.txt'.\n");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logConfiguration.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
+#define SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogOutput;
+class LogDecorators;
+class LogTagLevelExpression;
+
+// Global configuration of logging. Handles parsing and configuration of the logging framework,
+// and manages the list of configured log outputs. The actual tag and level configuration is
+// kept implicitly in the LogTagSets and their LogOutputLists. During configuration the tagsets
+// are iterated over and updated accordingly.
+class LogConfiguration : public AllStatic {
+ private:
+ static LogOutput** _outputs;
+ static size_t _n_outputs;
+
+ // Create a new output. Returns NULL if failed.
+ static LogOutput* new_output(char* name, const char* options = NULL);
+
+ // Add an output to the list of configured outputs. Returns the assigned index.
+ static size_t add_output(LogOutput* out);
+
+ // Delete a configured output. The stderr/stdout outputs can not be removed.
+ // Output should be completely disabled before it is deleted.
+ static void delete_output(size_t idx);
+
+ // Disable all logging to the specified output and then delete it (unless it is stdout/stderr).
+ static void disable_output(size_t idx);
+
+ // Get output index by name. Returns SIZE_MAX if output not found.
+ static size_t find_output(const char* name);
+
+ // Configure output (add or update existing configuration) to log on tag-level combination using specified decorators.
+ static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators);
+
+ public:
+ // Initialization and finalization of log configuration, to be run at vm startup and shutdown respectively.
+ static void initialize(jlong vm_start_time);
+ static void finalize();
+
+ // Perform necessary post-initialization after VM startup. Enables reconfiguration of logging.
+ static void post_initialize();
+
+ // Disable all logging, equivalent to -Xlog:disable.
+ static void disable_logging();
+
+ // Parse command line configuration. Parameter 'opts' is the string immediately following the -Xlog: argument ("gc" for -Xlog:gc).
+ static bool parse_command_line_arguments(const char* opts = "all");
+
+ // Parse separated configuration arguments (from JCmd/MBean and command line).
+ static bool parse_log_arguments(const char* outputstr,
+ const char* what,
+ const char* decoratorstr,
+ const char* output_options,
+ outputStream* errstream);
+
+ // Prints log configuration to outputStream, used by JCmd/MBean.
+ static void describe(outputStream* out);
+
+ // Prints usage help for command line log configuration.
+ static void print_command_line_help(FILE* out);
+};
+
+#endif // SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorations.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logConfiguration.hpp"
+#include "logging/logDecorations.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/thread.inline.hpp"
+#include "services/management.hpp"
+
+jlong LogDecorations::_vm_start_time_millis = 0;
+
+LogDecorations::LogDecorations(LogLevelType level, const LogTagSet &tagset, const LogDecorators &decorators)
+ : _level(level), _tagset(tagset), _millis(-1) {
+ create_decorations(decorators);
+}
+
+void LogDecorations::create_decorations(const LogDecorators &decorators) {
+ char* position = _decorations_buffer;
+ #define DECORATOR(full_name, abbr) \
+ if (decorators.is_decorator(LogDecorators::full_name##_decorator)) { \
+ _decoration_offset[LogDecorators::full_name##_decorator] = position; \
+ position = create_##full_name##_decoration(position) + 1; \
+ }
+ DECORATOR_LIST
+#undef DECORATOR
+}
+
+jlong LogDecorations::java_millis() {
+ if (_millis < 0) {
+ _millis = os::javaTimeMillis();
+ }
+ return _millis;
+}
+
+#define ASSERT_AND_RETURN(written, pos) \
+ assert(written >= 0, "Decorations buffer overflow"); \
+ return pos + written;
+
+char* LogDecorations::create_time_decoration(char* pos) {
+ char* buf = os::iso8601_time(pos, 29);
+ int written = buf == NULL ? -1 : 29;
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_uptime_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%.3fs", os::elapsedTime());
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_timemillis_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ms", java_millis());
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_uptimemillis_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer),
+ INT64_FORMAT "ms", java_millis() - _vm_start_time_millis);
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_timenanos_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::javaTimeNanos());
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_uptimenanos_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::elapsed_counter());
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_pid_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%d", os::current_process_id());
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char * LogDecorations::create_tid_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer),
+ INTX_FORMAT, Thread::current()->osthread()->thread_id());
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char* LogDecorations::create_level_decoration(char* pos) {
+ int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%s", LogLevel::name(_level));
+ ASSERT_AND_RETURN(written, pos)
+}
+
+char* LogDecorations::create_tags_decoration(char* pos) {
+ int written = _tagset.label(pos, DecorationsBufferSize - (pos - _decorations_buffer));
+ ASSERT_AND_RETURN(written, pos)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorations.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGDECORATIONS_HPP
+#define SHARE_VM_LOGGING_LOGDECORATIONS_HPP
+
+#include "logging/logDecorators.hpp"
+#include "logging/logTagSet.hpp"
+#include "memory/allocation.hpp"
+
+// Temporary object containing the necessary data for a log call's decorations (timestamps, etc).
+class LogDecorations VALUE_OBJ_CLASS_SPEC {
+ public:
+ static const int DecorationsBufferSize = 256;
+ private:
+ char _decorations_buffer[DecorationsBufferSize];
+ char* _decoration_offset[LogDecorators::Count];
+ LogLevelType _level;
+ LogTagSet _tagset;
+ jlong _millis;
+ static jlong _vm_start_time_millis;
+
+ jlong java_millis();
+ void create_decorations(const LogDecorators& decorators);
+
+#define DECORATOR(name, abbr) char* create_##name##_decoration(char* pos);
+ DECORATOR_LIST
+#undef DECORATOR
+
+ public:
+ LogDecorations(LogLevelType level, const LogTagSet& tagset, const LogDecorators& decorators);
+
+ const char* decoration(LogDecorators::Decorator decorator) const {
+ return _decoration_offset[decorator];
+ }
+
+ static void set_vm_start_time_millis(jlong start_time) {
+ _vm_start_time_millis = start_time;
+ }
+};
+
+#endif // SHARE_VM_LOGGING_LOGDECORATIONS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorators.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logDecorators.hpp"
+#include "runtime/os.inline.hpp"
+
+const char* LogDecorators::_name[][2] = {
+#define DECORATOR(n, a) {#n, #a},
+ DECORATOR_LIST
+#undef DECORATOR
+};
+
+LogDecorators::Decorator LogDecorators::from_string(const char* str) {
+ for (size_t i = 0; i < Count; i++) {
+ Decorator d = static_cast<Decorator>(i);
+ if (strcasecmp(str, name(d)) == 0 || strcasecmp(str, abbreviation(d)) == 0) {
+ return d;
+ }
+ }
+ return Invalid;
+}
+
+bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) {
+ if (decorator_args == NULL || strlen(decorator_args) == 0) {
+ _decorators = DefaultDecoratorsMask;
+ return true;
+ }
+
+ if (strcasecmp(decorator_args, "none") == 0 ) {
+ _decorators = 0;
+ return true;
+ }
+
+ bool result = true;
+ uint tmp_decorators = 0;
+ char* args_copy = os::strdup_check_oom(decorator_args, mtLogging);
+ char* token = args_copy;
+ char* comma_pos;
+ do {
+ comma_pos = strchr(token, ',');
+ if (comma_pos != NULL) {
+ *comma_pos = '\0';
+ }
+ Decorator d = from_string(token);
+ if (d == Invalid) {
+ if (errstream != NULL) {
+ errstream->print_cr("Invalid decorator '%s'.", token);
+ }
+ result = false;
+ break;
+ }
+ tmp_decorators |= mask(d);
+ token = comma_pos + 1;
+ } while (comma_pos != NULL);
+ os::free(args_copy);
+ if (result) {
+ _decorators = tmp_decorators;
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorators.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGDECORATORS_HPP
+#define SHARE_VM_LOGGING_LOGDECORATORS_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// The list of available decorators:
+// time - Current time and date in ISO-8601 format
+// uptime - Time since the start of the JVM in seconds and milliseconds (e.g., 6.567s)
+// timemillis - The same value as generated by System.currentTimeMillis()
+// uptimemillis - Milliseconds since the JVM started
+// timenanos - The same value as generated by System.nanoTime()
+// uptimenanos - Nanoseconds since the JVM started
+// pid - The process identifier
+// tid - The thread identifier
+// level - The level associated with the log message
+// tags - The tag-set associated with the log message
+#define DECORATOR_LIST \
+ DECORATOR(time, t) \
+ DECORATOR(uptime, u) \
+ DECORATOR(timemillis, tm) \
+ DECORATOR(uptimemillis, um) \
+ DECORATOR(timenanos, tn) \
+ DECORATOR(uptimenanos, un) \
+ DECORATOR(pid, p) \
+ DECORATOR(tid, ti) \
+ DECORATOR(level, l) \
+ DECORATOR(tags, tg)
+
+// LogDecorators represents a selection of decorators that should be prepended to
+// each log message for a given output. Decorators are always prepended in the order
+// declared above. For example, logging with 'uptime, level, tags' decorators results in:
+// [0,943s][info ][logging] message.
+class LogDecorators VALUE_OBJ_CLASS_SPEC {
+ public:
+ enum Decorator {
+#define DECORATOR(name, abbr) name##_decorator,
+ DECORATOR_LIST
+#undef DECORATOR
+ Count,
+ Invalid
+ };
+
+ private:
+ uint _decorators;
+ static const char* _name[][2];
+ static const uint DefaultDecoratorsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator);
+
+ static uint mask(LogDecorators::Decorator decorator) {
+ return 1 << decorator;
+ }
+
+ public:
+ LogDecorators() : _decorators(DefaultDecoratorsMask) {
+ };
+
+ void clear() {
+ _decorators = 0;
+ }
+
+ static const char* name(LogDecorators::Decorator decorator) {
+ return _name[decorator][0];
+ }
+
+ static const char* abbreviation(LogDecorators::Decorator decorator) {
+ return _name[decorator][1];
+ }
+
+ static LogDecorators::Decorator from_string(const char* str);
+
+ void combine_with(const LogDecorators &source) {
+ _decorators |= source._decorators;
+ }
+
+ bool is_decorator(LogDecorators::Decorator decorator) const {
+ return (_decorators & mask(decorator)) != 0;
+ }
+
+ bool parse(const char* decorator_args, outputStream* errstream = NULL);
+};
+
+#endif // SHARE_VM_LOGGING_LOGDECORATORS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logConfiguration.hpp"
+#include "logging/logDiagnosticCommand.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+LogDiagnosticCommand::LogDiagnosticCommand(outputStream* output, bool heap_allocated)
+ : DCmdWithParser(output, heap_allocated),
+ _output("output", "The name or index (#<index>) of output to configure.", "STRING", false),
+ _output_options("output_options", "Options for the output.", "STRING", false),
+ _what("what", "Configures what tags to log.", "STRING", false),
+ _decorators("decorators", "Configures which decorators to use. Use 'none' or an empty value to remove all.", "STRING", false),
+ _disable("disable", "Turns off all logging and clears the log configuration.", "BOOLEAN", false),
+ _list("list", "Lists current log configuration.", "BOOLEAN", false) {
+ _dcmdparser.add_dcmd_option(&_output);
+ _dcmdparser.add_dcmd_option(&_output_options);
+ _dcmdparser.add_dcmd_option(&_what);
+ _dcmdparser.add_dcmd_option(&_decorators);
+ _dcmdparser.add_dcmd_option(&_disable);
+ _dcmdparser.add_dcmd_option(&_list);
+}
+
+int LogDiagnosticCommand::num_arguments() {
+ ResourceMark rm;
+ LogDiagnosticCommand* dcmd = new LogDiagnosticCommand(NULL, false);
+ if (dcmd != NULL) {
+ DCmdMark mark(dcmd);
+ return dcmd->_dcmdparser.num_arguments();
+ } else {
+ return 0;
+ }
+}
+
+void LogDiagnosticCommand::registerCommand() {
+ uint32_t full_visibility = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean;
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<LogDiagnosticCommand>(full_visibility, true, false));
+}
+
+void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) {
+ bool any_command = false;
+ if (_disable.has_value()) {
+ MutexLocker ml(LogConfiguration_lock);
+ LogConfiguration::disable_logging();
+ any_command = true;
+ }
+
+ if (_output.has_value() || _what.has_value() || _decorators.has_value()) {
+ MutexLocker ml(LogConfiguration_lock);
+ if (!LogConfiguration::parse_log_arguments(_output.value(),
+ _what.value(),
+ _decorators.value(),
+ _output_options.value(),
+ output())) {
+ return;
+ }
+ any_command = true;
+ }
+
+ if (_list.has_value()) {
+ MutexLocker ml(LogConfiguration_lock);
+ LogConfiguration::describe(output());
+ any_command = true;
+ }
+
+ if (!any_command) {
+ // If no argument was provided, print usage
+ print_help(LogDiagnosticCommand::name());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP
+#define SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP
+
+#include "services/diagnosticCommand.hpp"
+
+// The LogDiagnosticCommand represents the 'VM.log' DCMD
+// that allows configuration of the logging at runtime.
+// It can be used to view or modify the current log configuration.
+// VM.log without additional arguments prints the usage description.
+// The 'list' argument will list all available log tags,
+// levels, decorators and currently configured log outputs.
+// Specifying 'disable' will disable logging completely.
+// The remaining arguments are used to set a log output to log everything
+// with the specified tags and levels using the given decorators.
+class LogDiagnosticCommand : public DCmdWithParser {
+ protected:
+ DCmdArgument<char *> _output;
+ DCmdArgument<char *> _output_options;
+ DCmdArgument<char *> _what;
+ DCmdArgument<char *> _decorators;
+ DCmdArgument<bool> _disable;
+ DCmdArgument<bool> _list;
+
+ public:
+ LogDiagnosticCommand(outputStream* output, bool heap_allocated);
+ void execute(DCmdSource source, TRAPS);
+ static void registerCommand();
+ static int num_arguments();
+
+ static const char* name() {
+ return "VM.log";
+ }
+
+ static const char* description() {
+ return "Lists, enables, disables or changes a log output configuration.";
+ }
+
+ // Used by SecurityManager. This DCMD requires ManagementPermission = control.
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission", "control", NULL};
+ return p;
+ }
+};
+
+#endif // SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileOutput.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "logging/logConfiguration.hpp"
+#include "logging/logFileOutput.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/defaultStream.hpp"
+
+const char* LogFileOutput::FileOpenMode = "a";
+const char* LogFileOutput::PidFilenamePlaceholder = "%p";
+const char* LogFileOutput::TimestampFilenamePlaceholder = "%t";
+const char* LogFileOutput::TimestampFormat = "%Y-%m-%d_%H-%M-%S";
+const char* LogFileOutput::FileSizeOptionKey = "filesize";
+const char* LogFileOutput::FileCountOptionKey = "filecount";
+char LogFileOutput::_pid_str[PidBufferSize];
+char LogFileOutput::_vm_start_time_str[StartTimeBufferSize];
+
+LogFileOutput::LogFileOutput(const char* name)
+ : LogFileStreamOutput(NULL), _name(os::strdup_check_oom(name, mtLogging)),
+ _file_name(NULL), _archive_name(NULL), _archive_name_len(0), _current_size(0),
+ _rotate_size(0), _current_file(1), _file_count(0),
+ _rotation_lock(Mutex::leaf, "LogFileOutput rotation lock", true, Mutex::_safepoint_check_sometimes) {
+ _file_name = make_file_name(name, _pid_str, _vm_start_time_str);
+}
+
+void LogFileOutput::set_file_name_parameters(jlong vm_start_time) {
+ int res = jio_snprintf(_pid_str, sizeof(_pid_str), "%d", os::current_process_id());
+ assert(res > 0, "PID buffer too small");
+
+ struct tm local_time;
+ time_t utc_time = vm_start_time / 1000;
+ os::localtime_pd(&utc_time, &local_time);
+ res = (int)strftime(_vm_start_time_str, sizeof(_vm_start_time_str), TimestampFormat, &local_time);
+ assert(res > 0, "VM start time buffer too small.");
+}
+
+LogFileOutput::~LogFileOutput() {
+ if (_stream != NULL) {
+ if (_archive_name != NULL) {
+ archive();
+ }
+ if (fclose(_stream) != 0) {
+ jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n",
+ _file_name, strerror(errno));
+ }
+ }
+ os::free(_archive_name);
+ os::free(_file_name);
+ os::free(const_cast<char*>(_name));
+}
+
+size_t LogFileOutput::parse_value(const char* value_str) {
+ char* end;
+ unsigned long long value = strtoull(value_str, &end, 10);
+ if (!isdigit(*value_str) || end != value_str + strlen(value_str) || value >= SIZE_MAX) {
+ return SIZE_MAX;
+ }
+ return value;
+}
+
+bool LogFileOutput::configure_rotation(const char* options) {
+ if (options == NULL || strlen(options) == 0) {
+ return true;
+ }
+ bool success = true;
+ char* opts = os::strdup_check_oom(options, mtLogging);
+
+ char* comma_pos;
+ char* pos = opts;
+ do {
+ comma_pos = strchr(pos, ',');
+ if (comma_pos != NULL) {
+ *comma_pos = '\0';
+ }
+
+ char* equals_pos = strchr(pos, '=');
+ if (equals_pos == NULL) {
+ success = false;
+ break;
+ }
+ char* key = pos;
+ char* value_str = equals_pos + 1;
+ *equals_pos = '\0';
+
+ if (strcmp(FileCountOptionKey, key) == 0) {
+ size_t value = parse_value(value_str);
+ if (value == SIZE_MAX || value >= UINT_MAX) {
+ success = false;
+ break;
+ }
+ _file_count = static_cast<uint>(value);
+ _file_count_max_digits = static_cast<uint>(log10(static_cast<double>(_file_count)) + 1);
+ _archive_name_len = 2 + strlen(_file_name) + _file_count_max_digits;
+ _archive_name = NEW_C_HEAP_ARRAY(char, _archive_name_len, mtLogging);
+ } else if (strcmp(FileSizeOptionKey, key) == 0) {
+ size_t value = parse_value(value_str);
+ if (value == SIZE_MAX || value > SIZE_MAX / K) {
+ success = false;
+ break;
+ }
+ _rotate_size = value * K;
+ } else {
+ success = false;
+ break;
+ }
+ pos = comma_pos + 1;
+ } while (comma_pos != NULL);
+
+ os::free(opts);
+ return success;
+}
+
+bool LogFileOutput::initialize(const char* options) {
+ if (!configure_rotation(options)) {
+ return false;
+ }
+ _stream = fopen(_file_name, FileOpenMode);
+ if (_stream == NULL) {
+ log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+int LogFileOutput::write(const LogDecorations& decorations, const char* msg) {
+ if (_stream == NULL) {
+ // An error has occurred with this output, avoid writing to it.
+ return 0;
+ }
+ int written = LogFileStreamOutput::write(decorations, msg);
+ _current_size += written;
+
+ if (should_rotate()) {
+ MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */);
+ if (should_rotate()) {
+ rotate();
+ }
+ }
+
+ return written;
+}
+
+void LogFileOutput::archive() {
+ assert(_archive_name != NULL && _archive_name_len > 0, "Rotation must be configured before using this function.");
+ int ret = jio_snprintf(_archive_name, _archive_name_len, "%s.%0*u",
+ _file_name, _file_count_max_digits, _current_file);
+ assert(ret >= 0, "Buffer should always be large enough");
+
+ // Attempt to remove possibly existing archived log file before we rename.
+ // Don't care if it fails, we really only care about the rename that follows.
+ remove(_archive_name);
+
+ // Rename the file from ex hotspot.log to hotspot.log.2
+ if (rename(_file_name, _archive_name) == -1) {
+ jio_fprintf(defaultStream::error_stream(), "Could not rename log file '%s' to '%s' (%s).\n",
+ _file_name, _archive_name, strerror(errno));
+ }
+}
+
+void LogFileOutput::rotate() {
+ // Archive the current log file
+ archive();
+
+ // Open the active log file using the same stream as before
+ _stream = freopen(_file_name, FileOpenMode, _stream);
+ if (_stream == NULL) {
+ jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n",
+ _file_name, strerror(errno));
+ return;
+ }
+
+ // Reset accumulated size, increase current file counter, and check for file count wrap-around.
+ _current_size = 0;
+ _current_file = (_current_file >= _file_count ? 1 : _current_file + 1);
+}
+
+char* LogFileOutput::make_file_name(const char* file_name,
+ const char* pid_string,
+ const char* timestamp_string) {
+ char* result = NULL;
+
+ // Lets start finding out if we have any %d and/or %t in the name.
+ // We will only replace the first occurrence of any placeholder
+ const char* pid = strstr(file_name, PidFilenamePlaceholder);
+ const char* timestamp = strstr(file_name, TimestampFilenamePlaceholder);
+
+ if (pid == NULL && timestamp == NULL) {
+ // We found no place-holders, return the simple filename
+ return os::strdup_check_oom(file_name, mtLogging);
+ }
+
+ // At least one of the place-holders were found in the file_name
+ const char* first = "";
+ size_t first_pos = -1;
+ size_t first_replace_len = 0;
+
+ const char* second = "";
+ size_t second_pos = -1;
+ size_t second_replace_len = 0;
+
+ // If we found a %p, then setup our variables accordingly
+ if (pid != NULL) {
+ if (timestamp == NULL || pid < timestamp) {
+ first = pid_string;
+ first_pos = pid - file_name;
+ first_replace_len = strlen(PidFilenamePlaceholder);
+ } else {
+ second = pid_string;
+ second_pos = pid - file_name;
+ second_replace_len = strlen(PidFilenamePlaceholder);
+ }
+ }
+
+ if (timestamp != NULL) {
+ if (pid == NULL || timestamp < pid) {
+ first = timestamp_string;
+ first_pos = timestamp - file_name;
+ first_replace_len = strlen(TimestampFilenamePlaceholder);
+ } else {
+ second = timestamp_string;
+ second_pos = timestamp - file_name;
+ second_replace_len = strlen(TimestampFilenamePlaceholder);
+ }
+ }
+
+ size_t first_len = strlen(first);
+ size_t second_len = strlen(second);
+
+ // Allocate the new buffer, size it to hold all we want to put in there +1.
+ size_t result_len = strlen(file_name) + first_len - first_replace_len + second_len - second_replace_len;
+ result = NEW_C_HEAP_ARRAY(char, result_len + 1, mtLogging);
+
+ // Assemble the strings
+ size_t file_name_pos = 0;
+ size_t i = 0;
+ while (i < result_len) {
+ if (file_name_pos == first_pos) {
+ // We are in the range of the first placeholder
+ strcpy(result + i, first);
+ // Bump output buffer position with length of replacing string
+ i += first_len;
+ // Bump source buffer position to skip placeholder
+ file_name_pos += first_replace_len;
+ } else if (file_name_pos == second_pos) {
+ // We are in the range of the second placeholder
+ strcpy(result + i, second);
+ i += second_len;
+ file_name_pos += second_replace_len;
+ } else {
+ // Else, copy char by char of the original file
+ result[i] = file_name[file_name_pos++];
+ i++;
+ }
+ }
+ // Add terminating char
+ result[result_len] = '\0';
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileOutput.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP
+#define SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP
+
+#include "logging/logFileStreamOutput.hpp"
+#include "runtime/mutex.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogDecorations;
+
+// The log file output, with support for file rotation based on a target size.
+class LogFileOutput : public LogFileStreamOutput {
+ private:
+ static const char* FileOpenMode;
+ static const char* FileCountOptionKey;
+ static const char* FileSizeOptionKey;
+ static const char* PidFilenamePlaceholder;
+ static const char* TimestampFilenamePlaceholder;
+ static const char* TimestampFormat;
+ static const size_t StartTimeBufferSize = 20;
+ static const size_t PidBufferSize = 21;
+ static char _pid_str[PidBufferSize];
+ static char _vm_start_time_str[StartTimeBufferSize];
+
+ Mutex _rotation_lock;
+ const char* _name;
+ char* _file_name;
+ char* _archive_name;
+
+ uint _current_file;
+ uint _file_count;
+ uint _file_count_max_digits;
+
+ size_t _archive_name_len;
+ size_t _rotate_size;
+ size_t _current_size;
+
+ void archive();
+ void rotate();
+ bool configure_rotation(const char* options);
+ char *make_file_name(const char* file_name, const char* pid_string, const char* timestamp_string);
+ static size_t parse_value(const char* value_str);
+
+ bool should_rotate() const {
+ return _file_count > 0 && _rotate_size > 0 && _current_size >= _rotate_size;
+ }
+
+ public:
+ LogFileOutput(const char *name);
+ virtual ~LogFileOutput();
+ virtual bool initialize(const char* options);
+ virtual int write(const LogDecorations& decorations, const char* msg);
+
+ virtual const char* name() const {
+ return _name;
+ }
+
+ static void set_file_name_parameters(jlong start_time);
+};
+
+#endif // SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileStreamOutput.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logDecorators.hpp"
+#include "logging/logDecorations.hpp"
+#include "logging/logFileStreamOutput.hpp"
+#include "memory/allocation.inline.hpp"
+
+LogStdoutOutput LogStdoutOutput::_instance;
+LogStderrOutput LogStderrOutput::_instance;
+
+int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) {
+ char decoration_buf[LogDecorations::DecorationsBufferSize];
+ char* position = decoration_buf;
+ int total_written = 0;
+
+ for (uint i = 0; i < LogDecorators::Count; i++) {
+ LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(i);
+ if (!_decorators.is_decorator(decorator)) {
+ continue;
+ }
+ int written = jio_snprintf(position, sizeof(decoration_buf) - total_written, "[%-*s]",
+ _decorator_padding[decorator],
+ decorations.decoration(decorator));
+ if (written <= 0) {
+ return -1;
+ } else if (static_cast<size_t>(written - 2) > _decorator_padding[decorator]) {
+ _decorator_padding[decorator] = written - 2;
+ }
+ position += written;
+ total_written += written;
+ }
+
+ if (total_written == 0) {
+ total_written = jio_fprintf(_stream, "%s\n", msg);
+ } else {
+ total_written = jio_fprintf(_stream, "%s %s\n", decoration_buf, msg);
+ }
+ fflush(_stream);
+ return total_written;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileStreamOutput.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP
+#define SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP
+
+#include "logging/logDecorators.hpp"
+#include "logging/logOutput.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogDecorations;
+
+// Base class for all FileStream-based log outputs.
+class LogFileStreamOutput : public LogOutput {
+ protected:
+ FILE* _stream;
+ size_t _decorator_padding[LogDecorators::Count];
+
+ LogFileStreamOutput(FILE *stream) : _stream(stream) {
+ for (size_t i = 0; i < LogDecorators::Count; i++) {
+ _decorator_padding[i] = 0;
+ }
+ _decorator_padding[LogDecorators::level_decorator] = 7;
+ }
+
+ public:
+ virtual int write(const LogDecorations &decorations, const char* msg);
+};
+
+class LogStdoutOutput : public LogFileStreamOutput {
+ friend class LogOutput;
+ private:
+ static LogStdoutOutput _instance;
+ LogStdoutOutput() : LogFileStreamOutput(stdout) {
+ set_config_string("all=off");
+ }
+ virtual bool initialize(const char* options) {
+ return false;
+ }
+ public:
+ virtual const char* name() const {
+ return "stdout";
+ }
+};
+
+class LogStderrOutput : public LogFileStreamOutput {
+ friend class LogOutput;
+ private:
+ static LogStderrOutput _instance;
+ LogStderrOutput() : LogFileStreamOutput(stderr) {
+ set_config_string("all=warning");
+ }
+ virtual bool initialize(const char* options) {
+ return false;
+ }
+ public:
+ virtual const char* name() const {
+ return "stderr";
+ }
+};
+
+#endif // SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logLevel.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logLevel.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+const char* LogLevel::_name[] = {
+ "off",
+#define LOG_LEVEL(name, printname) #printname,
+ LOG_LEVEL_LIST
+#undef LOG_LEVEL
+};
+
+LogLevelType LogLevel::from_string(const char* str) {
+ for (uint i = 0; i < Count; i++) {
+ if (strcasecmp(str, _name[i]) == 0) {
+ return static_cast<LogLevelType>(i);
+ }
+ }
+ return Invalid;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logLevel.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGLEVEL_HPP
+#define SHARE_VM_LOGGING_LOGLEVEL_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/macros.hpp"
+
+// The list of log levels:
+//
+// develop - A non-product level that is finer than trace.
+// Should be used for really expensive and/or
+// extensive logging, or logging that shouldn't
+// or can't be included in a product build.
+//
+// trace - Finest level of logging in product builds.
+// Use for extensive/noisy logging that can
+// give slow-down when enabled.
+//
+// debug - A finer level of logging. Use for semi-noisy
+// logging that is does not fit the info level.
+//
+// info - General level of logging. Use for significant
+// events and/or informative summaries.
+//
+// warning - Important messages that are not strictly errors.
+//
+// error - Critical messages caused by errors.
+//
+#define LOG_LEVEL_LIST \
+ NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \
+ LOG_LEVEL(Trace, trace) \
+ LOG_LEVEL(Debug, debug) \
+ LOG_LEVEL(Info, info) \
+ LOG_LEVEL(Warning, warning) \
+ LOG_LEVEL(Error, error)
+
+class LogLevel : public AllStatic {
+ public:
+ enum type {
+ Off,
+#define LOG_LEVEL(name, printname) name,
+ LOG_LEVEL_LIST
+#undef LOG_LEVEL
+ Count,
+ Invalid,
+ First = Off + 1,
+ Last = Error,
+ Default = Warning,
+ Unspecified = Info
+ };
+
+ static const char *name(LogLevel::type level) {
+ return _name[level];
+ }
+
+ static LogLevel::type from_string(const char* str);
+
+ private:
+ static const char* _name[];
+};
+
+typedef LogLevel::type LogLevelType;
+
+#endif // SHARE_VM_LOGGING_LOGLEVEL_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutput.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logFileStreamOutput.hpp"
+#include "logging/logOutput.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.inline.hpp"
+
+LogOutput* const LogOutput::Stdout = &LogStdoutOutput::_instance;
+LogOutput* const LogOutput::Stderr = &LogStderrOutput::_instance;
+
+LogOutput::~LogOutput() {
+ os::free(_config_string);
+}
+
+void LogOutput::set_config_string(const char* string) {
+ os::free(_config_string);
+ _config_string = os::strdup_check_oom(string, mtLogging);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutput.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGOUTPUT_HPP
+#define SHARE_VM_LOGGING_LOGOUTPUT_HPP
+
+#include "logging/logDecorators.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogDecorations;
+
+// The base class/interface for log outputs.
+// Keeps track of the latest configuration string,
+// and its selected decorators.
+class LogOutput : public CHeapObj<mtLogging> {
+ protected:
+ LogDecorators _decorators;
+ char* _config_string;
+
+ public:
+ static LogOutput* const Stdout;
+ static LogOutput* const Stderr;
+
+ void set_decorators(const LogDecorators &decorators) {
+ _decorators = decorators;
+ }
+
+ const LogDecorators& decorators() const {
+ return _decorators;
+ }
+
+ const char* config_string() const {
+ return _config_string;
+ }
+
+ LogOutput() : _config_string(NULL) {
+ }
+
+ virtual ~LogOutput();
+ void set_config_string(const char* string);
+
+ virtual const char* name() const = 0;
+ virtual bool initialize(const char* options) = 0;
+ virtual int write(const LogDecorations &decorations, const char* msg) = 0;
+};
+
+#endif // SHARE_VM_LOGGING_LOGOUTPUT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutputList.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logLevel.hpp"
+#include "logging/logOutputList.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/atomic.inline.hpp"
+#include "runtime/orderAccess.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+jint LogOutputList::increase_readers() {
+ jint result = Atomic::add(1, &_active_readers);
+ assert(_active_readers > 0, "Ensure we have consistent state");
+ return result;
+}
+
+jint LogOutputList::decrease_readers() {
+ jint result = Atomic::add(-1, &_active_readers);
+ assert(result >= 0, "Ensure we have consistent state");
+ return result;
+}
+
+void LogOutputList::wait_until_no_readers() const {
+ OrderAccess::storeload();
+ while (_active_readers != 0) {
+ // Busy wait
+ }
+}
+
+void LogOutputList::set_output_level(LogOutput* output, LogLevelType level) {
+ LogOutputNode* node = find(output);
+ if (level == LogLevel::Off && node != NULL) {
+ remove_output(node);
+ } else if (level != LogLevel::Off && node == NULL) {
+ add_output(output, level);
+ } else if (node != NULL) {
+ update_output_level(node, level);
+ }
+}
+
+LogOutputList::LogOutputNode* LogOutputList::find(LogOutput* output) {
+ for (LogOutputNode* node = _level_start[LogLevel::Last]; node != NULL; node = node->_next) {
+ if (output == node->_value) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+void LogOutputList::remove_output(LogOutputList::LogOutputNode* node) {
+ assert(node != NULL, "Node must be non-null");
+
+ // Remove node from _level_start first
+ bool found = false;
+ for (uint level = LogLevel::First; level < LogLevel::Count; level++) {
+ if (_level_start[level] == node) {
+ found = true;
+ _level_start[level] = node->_next;
+ }
+ }
+
+ // Now remove it from the linked list
+ for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) {
+ if (cur->_next == node) {
+ found = true;
+ cur->_next = node->_next;
+ break;
+ }
+ }
+ assert(found, "Node to be removed should always be found");
+
+ wait_until_no_readers();
+ delete node;
+}
+
+void LogOutputList::add_output(LogOutput* output, LogLevelType level) {
+ LogOutputNode* node = new LogOutputNode();
+ node->_value = output;
+ node->_level = level;
+
+ // Set the next pointer to the first node of a lower level
+ for (node->_next = _level_start[level];
+ node->_next != NULL && node->_next->_level == level;
+ node->_next = node->_next->_next) {
+ }
+
+ // Update the _level_start index
+ for (int l = LogLevel::Last; l >= level; l--) {
+ if (_level_start[l] == NULL || _level_start[l]->_level < level) {
+ _level_start[l] = node;
+ }
+ }
+
+ // Add the node the list
+ for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) {
+ if (cur != node && cur->_next == node->_next) {
+ cur->_next = node;
+ break;
+ }
+ }
+}
+
+void LogOutputList::update_output_level(LogOutputList::LogOutputNode* node, LogLevelType level) {
+ add_output(node->_value, level);
+ wait_until_no_readers();
+ remove_output(node);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutputList.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
+#define SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
+
+#include "logging/logLevel.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/atomic.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogOutput;
+
+// Data structure to keep track of log outputs for a given tagset.
+// Essentially a sorted linked list going from error level outputs
+// to outputs of finer levels. Keeps an index from each level to
+// the first node in the list for the corresponding level.
+// This allows a log message on, for example, info level to jump
+// straight into the list where the first info level output can
+// be found. The log message will then be printed on that output,
+// as well as all outputs in nodes that follow in the list (which
+// can be additional info level outputs and/or debug and trace outputs).
+//
+// Each instance keeps track of the number of current readers of the list.
+// To remove a node from the list the node must first be unlinked,
+// and the memory for that node can be freed whenever the removing
+// thread observes an active reader count of 0 (after unlinking it).
+class LogOutputList VALUE_OBJ_CLASS_SPEC {
+ private:
+ struct LogOutputNode : public CHeapObj<mtLogging> {
+ LogOutput* _value;
+ LogOutputNode* _next;
+ LogLevelType _level;
+ };
+
+ LogOutputNode* _level_start[LogLevel::Count];
+ volatile jint _active_readers;
+
+ LogOutputNode* find(LogOutput* output);
+ void remove_output(LogOutputNode* node);
+ void add_output(LogOutput* output, LogLevelType level);
+ void update_output_level(LogOutputNode* node, LogLevelType level);
+
+ public:
+ LogOutputList() : _active_readers(0) {
+ for (size_t i = 0; i < LogLevel::Count; i++) {
+ _level_start[i] = NULL;
+ }
+ }
+
+ // Test if the outputlist has an output for the given level.
+ bool is_level(LogLevelType level) {
+ return _level_start[level] != NULL;
+ }
+
+ // Set (add/update/remove) the output to the specified level.
+ void set_output_level(LogOutput* output, LogLevelType level);
+
+ // Bookkeeping functions to keep track of number of active readers/iterators for the list.
+ jint increase_readers();
+ jint decrease_readers();
+ void wait_until_no_readers() const;
+
+ class Iterator VALUE_OBJ_CLASS_SPEC {
+ friend class LogOutputList;
+ private:
+ LogOutputNode* _current;
+ LogOutputList* _list;
+ Iterator(LogOutputList* list, LogOutputNode* start) : _current(start), _list(list) {
+ }
+
+ public:
+ ~Iterator() {
+ _list->decrease_readers();
+ }
+
+ LogOutput* operator*() {
+ return _current->_value;
+ }
+
+ void operator++(int) {
+ _current = _current->_next;
+ }
+
+ bool operator!=(const LogOutputNode *ref) const {
+ return _current != ref;
+ }
+ };
+
+ Iterator iterator(LogLevelType level = LogLevel::Last) {
+ increase_readers();
+ return Iterator(this, _level_start[level]);
+ }
+
+ LogOutputNode* end() const {
+ return NULL;
+ }
+};
+
+#endif // SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logPrefix.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGPREFIX_HPP
+#define SHARE_VM_LOGGING_LOGPREFIX_HPP
+
+#include "gc/shared/gcId.hpp"
+#include "logging/logTag.hpp"
+
+// Prefixes prepend each log message for a specified tagset with the given prefix.
+// A prefix consists of a format string and a value or callback. Prefixes are added
+// after the decorations but before the log message.
+//
+// List of prefixes for specific tags and/or tagsets.
+// Syntax: LOG_PREFIX(<printf format>, <value/callback for value>, LOG_TAGS(<chosen log tags>))
+#define LOG_PREFIX_LIST // Currently unused/empty
+
+// The empty prefix, used when there's no prefix defined.
+template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag = LogTag::__NO_TAG>
+struct LogPrefix : public AllStatic {
+ STATIC_ASSERT(GuardTag == LogTag::__NO_TAG);
+ static size_t prefix(char* buf, size_t len) {
+ return 0;
+ }
+};
+
+#define LOG_PREFIX(fmt, fn, ...) \
+template <> struct LogPrefix<__VA_ARGS__> { \
+ static size_t prefix(char* buf, size_t len) { \
+ int ret = jio_snprintf(buf, len, fmt, fn); \
+ assert(ret >= 0, \
+ err_msg("Failed to prefix log message using prefix ('%s', '%s'), log buffer too small?", fmt, #fn)); \
+ return ret; \
+ } \
+};
+LOG_PREFIX_LIST
+#undef LOG_PREFIX
+
+#endif // SHARE_VM_LOGGING_LOGPREFIX_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTag.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logTag.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+const char* LogTag::_name[] = {
+ "", // __NO_TAG
+#define LOG_TAG(name) #name,
+ LOG_TAG_LIST
+#undef LOG_TAG
+};
+
+LogTagType LogTag::from_string(const char* str) {
+ for (uint i = 0; i < LogTag::Count; i++) {
+ if (strcasecmp(str, _name[i]) == 0) {
+ return static_cast<LogTagType>(i);
+ }
+ }
+ return __NO_TAG;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTag.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGTAG_HPP
+#define SHARE_VM_LOGGING_LOGTAG_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// List of available logging tags. New tags should be added here.
+// (The tags 'all', 'disable' and 'help' are special tags that can
+// not be used in log calls, and should not be listed below.)
+#define LOG_TAG_LIST \
+ LOG_TAG(logging)
+
+#define PREFIX_LOG_TAG(T) (LogTag::T)
+
+// Expand a set of log tags to their prefixed names.
+// For error detection purposes, the macro passes one more tag than what is supported.
+// If too many tags are given, a static assert in the log class will fail.
+#define LOG_TAGS_EXPANDED(T0, T1, T2, T3, T4, T5, ...) PREFIX_LOG_TAG(T0), PREFIX_LOG_TAG(T1), PREFIX_LOG_TAG(T2), \
+ PREFIX_LOG_TAG(T3), PREFIX_LOG_TAG(T4), PREFIX_LOG_TAG(T5)
+// The EXPAND_VARARGS macro is required for MSVC, or it will resolve the LOG_TAGS_EXPANDED macro incorrectly.
+#define EXPAND_VARARGS(x) x
+#define LOG_TAGS(...) EXPAND_VARARGS(LOG_TAGS_EXPANDED(__VA_ARGS__, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG))
+
+// Log tags are used to classify log messages.
+// Each log message can be assigned between 1 to LogTag::MaxTags number of tags.
+// Specifying multiple tags for a log message means that only outputs configured
+// for those exact tags, or a subset of the tags with a wildcard, will see the logging.
+// Multiple tags should be comma separated, e.g. log_error(tag1, tag2)("msg").
+class LogTag : public AllStatic {
+ public:
+ // The maximum number of tags that a single log message can have.
+ // E.g. there might be hundreds of different tags available,
+ // but a specific log message can only be tagged with up to MaxTags of those.
+ static const size_t MaxTags = 5;
+
+ enum type {
+ __NO_TAG,
+#define LOG_TAG(name) name,
+ LOG_TAG_LIST
+#undef LOG_TAG
+ Count
+ };
+
+ static const char* name(LogTag::type tag) {
+ return _name[tag];
+ }
+
+ static LogTag::type from_string(const char *str);
+
+ private:
+ static const char* _name[];
+};
+
+typedef LogTag::type LogTagType;
+
+#endif // SHARE_VM_LOGGING_LOGTAG_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagLevelExpression.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logTagLevelExpression.hpp"
+#include "logging/logTagSet.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/os.inline.hpp"
+
+const char* LogTagLevelExpression::DefaultExpressionString = "all";
+
+LogTagLevelExpression::~LogTagLevelExpression() {
+ os::free(_string);
+}
+
+void LogTagLevelExpression::clear() {
+ _ntags = 0;
+ _ncombinations = 0;
+ for (size_t combination = 0; combination < MaxCombinations; combination++) {
+ _level[combination] = LogLevel::Invalid;
+ _allow_other_tags[combination] = false;
+ for (size_t tag = 0; tag < LogTag::MaxTags; tag++) {
+ _tags[combination][tag] = LogTag::__NO_TAG;
+ }
+ }
+ os::free(_string);
+ _string = NULL;
+}
+
+bool LogTagLevelExpression::parse(const char* str, outputStream* errstream) {
+ bool success = true;
+ clear();
+ if (str == NULL || strcmp(str, "") == 0) {
+ str = DefaultExpressionString;
+ }
+ char* copy = os::strdup_check_oom(str, mtLogging);
+ // Split string on commas
+ for (char *comma_pos = copy, *cur = copy; success && comma_pos != NULL; cur = comma_pos + 1) {
+ if (_ncombinations == MaxCombinations) {
+ if (errstream != NULL) {
+ errstream->print_cr("Can not have more than " SIZE_FORMAT " tag combinations in a what-expression.",
+ MaxCombinations);
+ }
+ success = false;
+ break;
+ }
+
+ comma_pos = strchr(cur, ',');
+ if (comma_pos != NULL) {
+ *comma_pos = '\0';
+ }
+
+ // Parse the level, if specified
+ LogLevelType level = LogLevel::Unspecified;
+ char* equals = strchr(cur, '=');
+ if (equals != NULL) {
+ level = LogLevel::from_string(equals + 1);
+ if (level == LogLevel::Invalid) {
+ if (errstream != NULL) {
+ errstream->print_cr("Invalid level '%s' in what-expression.", equals + 1);
+ }
+ success = false;
+ break;
+ }
+ *equals = '\0'; // now ignore "=level" part of substr
+ }
+ set_level(level);
+
+ // Parse special tags such as 'all'
+ if (strcmp(cur, "all") == 0) {
+ set_allow_other_tags();
+ new_combination();
+ continue;
+ }
+
+ // Check for '*' suffix
+ char* asterisk_pos = strchr(cur, '*');
+ if (asterisk_pos != NULL && asterisk_pos[1] == '\0') {
+ set_allow_other_tags();
+ *asterisk_pos = '\0';
+ }
+
+ // Parse the tag expression (t1+t2+...+tn)
+ char* plus_pos;
+ char* cur_tag = cur;
+ do {
+ plus_pos = strchr(cur_tag, '+');
+ if (plus_pos != NULL) {
+ *plus_pos = '\0';
+ }
+ LogTagType tag = LogTag::from_string(cur_tag);
+ if (tag == LogTag::__NO_TAG) {
+ if (errstream != NULL) {
+ errstream->print_cr("Invalid tag '%s' in what-expression.", cur_tag);
+ }
+ success = false;
+ break;
+ }
+ if (_ntags == LogTag::MaxTags) {
+ if (errstream != NULL) {
+ errstream->print_cr("Tag combination exceeds the maximum of " SIZE_FORMAT " tags.",
+ LogTag::MaxTags);
+ }
+ success = false;
+ break;
+ }
+ add_tag(tag);
+ cur_tag = plus_pos + 1;
+ } while (plus_pos != NULL);
+
+ new_combination();
+ }
+
+ // Save the (unmodified) string for printing purposes.
+ _string = copy;
+ strcpy(_string, str);
+
+ return success;
+}
+
+LogLevelType LogTagLevelExpression::level_for(const LogTagSet& ts) const {
+ LogLevelType level = LogLevel::Off;
+ for (size_t combination = 0; combination < _ncombinations; combination++) {
+ bool contains_all = true;
+ size_t tag_idx;
+ for (tag_idx = 0; tag_idx < LogTag::MaxTags && _tags[combination][tag_idx] != LogTag::__NO_TAG; tag_idx++) {
+ if (!ts.contains(_tags[combination][tag_idx])) {
+ contains_all = false;
+ break;
+ }
+ }
+ // All tags in the expression must be part of the tagset,
+ // and either the expression allows other tags (has a wildcard),
+ // or the number of tags in the expression and tagset must match.
+ if (contains_all && (_allow_other_tags[combination] || tag_idx == ts.ntags())) {
+ level = _level[combination];
+ }
+ }
+ return level;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagLevelExpression.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
+#define SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
+
+#include "logging/logLevel.hpp"
+#include "logging/logTag.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogTagSet;
+
+// Class used to temporary encode a 'what'-expression during log configuration.
+// Consists of a combination of tags and levels, e.g. "tag1+tag2=level1,tag3*=level2".
+class LogTagLevelExpression : public StackObj {
+ private:
+ static const size_t MaxCombinations = 32;
+ static const char* DefaultExpressionString;
+
+ size_t _ntags, _ncombinations;
+ LogTagType _tags[MaxCombinations][LogTag::MaxTags];
+ LogLevelType _level[MaxCombinations];
+ bool _allow_other_tags[MaxCombinations];
+ char* _string;
+
+ void new_combination() {
+ _ncombinations++;
+ _ntags = 0;
+ }
+
+ void add_tag(LogTagType tag) {
+ assert(_ntags < LogTag::MaxTags, "Can't have more tags than MaxTags!");
+ _tags[_ncombinations][_ntags++] = tag;
+ }
+
+ void set_level(LogLevelType level) {
+ _level[_ncombinations] = level;
+ }
+
+ void set_allow_other_tags() {
+ _allow_other_tags[_ncombinations] = true;
+ }
+
+ void clear();
+
+ public:
+ LogTagLevelExpression() : _ntags(0), _ncombinations(0), _string(NULL) {
+ }
+
+ const char* to_string() const {
+ return _string;
+ }
+
+ ~LogTagLevelExpression();
+ bool parse(const char* str, outputStream* errstream = NULL);
+ LogLevelType level_for(const LogTagSet& ts) const;
+};
+
+#endif // SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagSet.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#include "precompiled.hpp"
+#include "logging/logDecorations.hpp"
+#include "logging/logLevel.hpp"
+#include "logging/logOutput.hpp"
+#include "logging/logTag.hpp"
+#include "logging/logTagSet.hpp"
+
+LogTagSet* LogTagSet::_list = NULL;
+size_t LogTagSet::_ntagsets = 0;
+
+// This constructor is called only during static initialization.
+// See the declaration in logTagSet.hpp for more information.
+LogTagSet::LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4)
+ : _next(_list) {
+ _tag[0] = t0;
+ _tag[1] = t1;
+ _tag[2] = t2;
+ _tag[3] = t3;
+ _tag[4] = t4;
+ for (_ntags = 0; _ntags < LogTag::MaxTags && _tag[_ntags] != LogTag::__NO_TAG; _ntags++) {
+ }
+ _list = this;
+ _ntagsets++;
+
+ // Set the default output to warning and error level for all new tagsets.
+ _output_list.set_output_level(LogOutput::Stderr, LogLevel::Default);
+}
+
+bool LogTagSet::is_level(LogLevelType level) {
+ return _output_list.is_level(level);
+}
+
+void LogTagSet::update_decorators(const LogDecorators& decorator) {
+ LogDecorators new_decorators = decorator;
+ for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) {
+ new_decorators.combine_with((*it)->decorators());
+ }
+ _decorators = new_decorators;
+}
+
+bool LogTagSet::has_output(const LogOutput* output) {
+ for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) {
+ if (*it == output) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void LogTagSet::log(LogLevelType level, const char* msg) {
+ LogDecorations decorations(level, *this, _decorators);
+ for (LogOutputList::Iterator it = _output_list.iterator(level); it != _output_list.end(); it++) {
+ (*it)->write(decorations, msg);
+ }
+}
+
+int LogTagSet::label(char* buf, size_t len) {
+ int tot_written = 0;
+ for (size_t i = 0; i < _ntags; i++) {
+ int written = jio_snprintf(buf + tot_written, len - tot_written, "%s%s",
+ (i == 0 ? "" : ","),
+ LogTag::name(_tag[i]));
+ if (written < 0) {
+ return -1;
+ }
+ tot_written += written;
+ }
+ return tot_written;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagSet.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGTAGSET_HPP
+#define SHARE_VM_LOGGING_LOGTAGSET_HPP
+
+#include "logging/logDecorators.hpp"
+#include "logging/logLevel.hpp"
+#include "logging/logOutputList.hpp"
+#include "logging/logTag.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// The tagset represents a combination of tags that occur in a log call somewhere.
+// Tagsets are created automatically by the LogTagSetMappings and should never be
+// instantiated directly somewhere else.
+class LogTagSet VALUE_OBJ_CLASS_SPEC {
+ private:
+ static LogTagSet* _list;
+ static size_t _ntagsets;
+
+ LogTagSet* const _next;
+ size_t _ntags;
+ LogTagType _tag[LogTag::MaxTags];
+
+ LogOutputList _output_list;
+ LogDecorators _decorators;
+
+ // Keep constructor private to prevent incorrect instantiations of this class.
+ // Only LogTagSetMappings can create/contain instances of this class.
+ // The constructor links all tagsets together in a global list of tagsets.
+ // This list is used during configuration to be able to update all tagsets
+ // and their configurations to reflect the new global log configuration.
+ LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4);
+
+ template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4>
+ friend class LogTagSetMapping;
+
+ public:
+ static LogTagSet* first() {
+ return _list;
+ }
+
+ LogTagSet* next() {
+ return _next;
+ }
+
+ size_t ntags() const {
+ return _ntags;
+ }
+
+ bool contains(LogTagType tag) const {
+ for (size_t i = 0; _tag[i] != LogTag::__NO_TAG; i++) {
+ if (tag == _tag[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void set_output_level(LogOutput* output, LogLevelType level) {
+ _output_list.set_output_level(output, level);
+ }
+
+ // Refresh the decorators for this tagset to contain the decorators for all
+ // of its current outputs combined with the given decorators.
+ void update_decorators(const LogDecorators& decorator);
+
+ int label(char *buf, size_t len);
+ bool has_output(const LogOutput* output);
+ bool is_level(LogLevelType level);
+ void log(LogLevelType level, const char* msg);
+};
+
+template <LogTagType T0, LogTagType T1 = LogTag::__NO_TAG, LogTagType T2 = LogTag::__NO_TAG,
+ LogTagType T3 = LogTag::__NO_TAG, LogTagType T4 = LogTag::__NO_TAG>
+class LogTagSetMapping : public AllStatic {
+private:
+ static LogTagSet _tagset;
+
+public:
+ static LogTagSet& tagset() {
+ return _tagset;
+ }
+};
+
+// Instantiate the static field _tagset for all tagsets that are used for logging somewhere.
+// (This must be done here rather than the .cpp file because it's a template.)
+// Each combination of tags used as template arguments to the Log class somewhere (via macro or not)
+// will instantiate the LogTagSetMapping template, which in turn creates the static field for that
+// tagset. This _tagset contains the configuration for those tags.
+template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4>
+LogTagSet LogTagSetMapping<T0, T1, T2, T3, T4>::_tagset(T0, T1, T2, T3, T4);
+
+#endif // SHARE_VM_LOGGING_LOGTAGSET_HPP
--- a/hotspot/src/share/vm/memory/allocation.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/memory/allocation.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -154,8 +154,9 @@
mtChunk = 0x0C, // chunk that holds content of arenas
mtTest = 0x0D, // Test type for verifying NMT
mtTracing = 0x0E, // memory used for Tracing
- mtNone = 0x0F, // undefined
- mt_number_of_types = 0x10 // number of memory types (mtDontTrack
+ mtLogging = 0x0F, // memory for logging
+ mtNone = 0x10, // undefined
+ mt_number_of_types = 0x11 // number of memory types (mtDontTrack
// is not included as validate type)
};
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -128,6 +128,7 @@
# include "interpreter/templateInterpreter.hpp"
# include "interpreter/templateTable.hpp"
# include "jvmtifiles/jvmti.h"
+# include "logging/log.hpp"
# include "memory/allocation.hpp"
# include "memory/allocation.inline.hpp"
# include "memory/heap.hpp"
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -32,6 +32,7 @@
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "gc/shared/taskqueue.hpp"
+#include "logging/logConfiguration.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/universe.inline.hpp"
#include "oops/oop.inline.hpp"
@@ -3190,6 +3191,26 @@
if (FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true) != Flag::SUCCESS) {
return JNI_EINVAL;
}
+ } else if (match_option(option, "-Xlog", &tail)) {
+ bool ret = false;
+ if (strcmp(tail, ":help") == 0) {
+ LogConfiguration::print_command_line_help(defaultStream::output_stream());
+ vm_exit(0);
+ } else if (strcmp(tail, ":disable") == 0) {
+ LogConfiguration::disable_logging();
+ ret = true;
+ } else if (*tail == '\0') {
+ ret = LogConfiguration::parse_command_line_arguments();
+ assert(ret, "-Xlog without arguments should never fail to parse");
+ } else if (*tail == ':') {
+ ret = LogConfiguration::parse_command_line_arguments(tail + 1);
+ }
+ if (ret == false) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Invalid -Xlog option '-Xlog%s'\n",
+ tail);
+ return JNI_EINVAL;
+ }
// JNI hooks
} else if (match_option(option, "-Xcheck", &tail)) {
if (!strcmp(tail, ":jni")) {
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -127,6 +127,7 @@
Mutex* Management_lock = NULL;
Monitor* Service_lock = NULL;
Monitor* PeriodicTask_lock = NULL;
+Mutex* LogConfiguration_lock = NULL;
#ifdef INCLUDE_TRACE
Mutex* JfrStacktrace_lock = NULL;
@@ -282,6 +283,7 @@
if (WhiteBoxAPI) {
def(Compilation_lock , Monitor, leaf, false, Monitor::_safepoint_check_never);
}
+ def(LogConfiguration_lock , Mutex, nonleaf, false, Monitor::_safepoint_check_always);
#ifdef INCLUDE_TRACE
def(JfrMsg_lock , Monitor, leaf, true, Monitor::_safepoint_check_always);
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -126,6 +126,7 @@
extern Mutex* Management_lock; // a lock used to serialize JVM management
extern Monitor* Service_lock; // a lock used for service thread operation
extern Monitor* PeriodicTask_lock; // protects the periodic task structure
+extern Mutex* LogConfiguration_lock; // protects configuration of logging
#ifdef INCLUDE_TRACE
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
--- a/hotspot/src/share/vm/runtime/thread.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -37,6 +37,7 @@
#include "interpreter/linkResolver.hpp"
#include "interpreter/oopMapCache.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
+#include "logging/logConfiguration.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.inline.hpp"
@@ -3306,6 +3307,10 @@
// Initialize the os module before using TLS
os::init();
+ // Record VM creation timing statistics
+ TraceVmCreationTime create_vm_timer;
+ create_vm_timer.start();
+
// Initialize system properties.
Arguments::init_system_properties();
@@ -3315,6 +3320,9 @@
// Update/Initialize System properties after JDK version number is known
Arguments::init_version_specific_system_properties();
+ // Make sure to initialize log configuration *before* parsing arguments
+ LogConfiguration::initialize(create_vm_timer.begin_time());
+
// Parse arguments
jint parse_result = Arguments::parse(args);
if (parse_result != JNI_OK) return parse_result;
@@ -3341,10 +3349,6 @@
HOTSPOT_VM_INIT_BEGIN();
- // Record VM creation timing statistics
- TraceVmCreationTime create_vm_timer;
- create_vm_timer.start();
-
// Timing (must come after argument parsing)
TraceTime timer("Create VM", TraceStartupTime);
@@ -3492,6 +3496,7 @@
// debug stuff, that does not work until all basic classes have been initialized.
set_init_completed();
+ LogConfiguration::post_initialize();
Metaspace::post_initialize();
HOTSPOT_VM_INIT_END();
@@ -3966,6 +3971,8 @@
// exit_globals() will delete tty
exit_globals();
+ LogConfiguration::finalize();
+
return true;
}
--- a/hotspot/src/share/vm/services/management.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/services/management.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -118,6 +118,10 @@
void start()
{ _timer.update_to(0); _begin_time = os::javaTimeMillis(); }
+ jlong begin_time() const {
+ return _begin_time;
+ }
+
/**
* Only call this if initialization completes successfully; it will
* crash if PerfMemory_exit() has already been called (usually by
--- a/hotspot/src/share/vm/services/nmtCommon.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/services/nmtCommon.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -40,6 +40,7 @@
"Arena Chunk",
"Test",
"Tracing",
+ "Logging",
"Unknown"
};
--- a/hotspot/src/share/vm/services/virtualMemoryTracker.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/services/virtualMemoryTracker.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -84,7 +84,10 @@
return _committed_regions.insert_after(committed_rgn, node) != NULL;
}
}
- assert(rgn->contain_region(addr, size), "Must cover this region");
+ // If we have reached this point, then we are trying to commit a region that overlaps with some existing committed regions.
+ remove_uncommitted_region(addr, size);
+ add_committed_region(committed_rgn);
+
return true;
} else {
// New committed region
--- a/hotspot/src/share/vm/utilities/ostream.cpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Mon Sep 28 15:05:02 2015 +0200
@@ -1440,3 +1440,14 @@
}
#endif
+
+void logStream::write(const char* s, size_t len) {
+ if (len > 0 && s[len - 1] == '\n') {
+ _current_line.write(s, len - 1);
+ _log_func(_current_line.as_string());
+ _current_line.reset();
+ } else {
+ _current_line.write(s, len);
+ update_position(s, len);
+ }
+}
--- a/hotspot/src/share/vm/utilities/ostream.hpp Thu Sep 24 11:38:26 2015 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.hpp Mon Sep 28 15:05:02 2015 +0200
@@ -235,6 +235,18 @@
void flush() {};
};
+class logStream : public outputStream {
+private:
+ stringStream _current_line;
+ void (*_log_func)(const char* fmt, ...);
+public:
+ void write(const char* s, size_t len);
+ logStream(void (*log_func)(const char* fmt, ...)) : _log_func(log_func) {}
+ ~logStream() {
+ guarantee(_current_line.size() == 0, "Buffer not flushed. Missing call to print_cr()?");
+ }
+};
+
class gcLogFileStream : public fileStream {
protected:
const char* _file_name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/mixedgc/TestLogging.java Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, 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 TestLogging
+ * @summary Check that a mixed GC is reflected in the gc logs
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @library /testlibrary /../../test/lib
+ * @modules java.management
+ * @build sun.hotspot.WhiteBox gc.g1.mixedgc.TestLogging
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver gc.g1.mixedgc.TestLogging
+ */
+
+package gc.g1.mixedgc;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Asserts;
+import sun.hotspot.WhiteBox;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+
+/**
+ * Test spawns MixedGCProvoker in a separate VM and expects to find a message
+ * telling that a mixed gc has happened
+ */
+public class TestLogging {
+ private static final String[] COMMON_OPTIONS = new String[]{
+ "-Xbootclasspath/a:.", "-XX:+UseG1GC",
+ "-XX:+UnlockExperimentalVMOptions",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI",
+ "-XX:SurvivorRatio=1", // Survivor-to-eden ratio is 1:1
+ "-Xms10M", "-Xmx10M",
+ "-XX:MaxTenuringThreshold=1", // promote objects after first gc
+ "-XX:InitiatingHeapOccupancyPercent=0", // marking cycle happens
+ // each time
+ "-XX:G1MixedGCCountTarget=4",
+ "-XX:MaxGCPauseMillis=30000", // to have enough time
+ "-XX:G1HeapRegionSize=1m", "-XX:G1HeapWastePercent=0",
+ "-XX:G1MixedGCLiveThresholdPercent=100"};
+
+ public static final int ALLOCATION_SIZE = 20000;
+ public static final int ALLOCATION_COUNT = 15;
+
+ public static void main(String args[]) throws Exception {
+ // Test turns logging on by giving -XX:+PrintGC flag
+ test("-XX:+PrintGC");
+ // Test turns logging on by giving -XX:+PrintGCDetails
+ test("-XX:+PrintGCDetails");
+ }
+
+ private static void test(String vmFlag) throws Exception {
+ System.out.println(String.format("%s: running with %s flag", TestLogging.class.getSimpleName(), vmFlag));
+ OutputAnalyzer output = spawnMixedGCProvoker(vmFlag);
+ System.out.println(output.getStdout());
+ output.shouldHaveExitValue(0);
+ output.shouldContain("GC pause (G1 Evacuation Pause) (mixed)");
+ }
+
+ /**
+ * Method spawns MixedGCProvoker with addition flags set
+ *
+ * @parameter extraFlags -flags to be added to the common options set
+ */
+ private static OutputAnalyzer spawnMixedGCProvoker(String... extraFlags)
+ throws Exception {
+ List<String> testOpts = new ArrayList<>();
+ Collections.addAll(testOpts, COMMON_OPTIONS);
+ Collections.addAll(testOpts, extraFlags);
+ testOpts.add(MixedGCProvoker.class.getName());
+ System.out.println(testOpts);
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(false,
+ testOpts.toArray(new String[testOpts.size()]));
+ return new OutputAnalyzer(pb.start());
+ }
+}
+
+/**
+ * Utility class to guarantee a mixed GC. The class allocates several arrays and
+ * promotes them to the oldgen. After that it tries to provoke mixed GC by
+ * allocating new objects.
+ *
+ * The necessary condition for guaranteed mixed GC is running MixedGCProvoker is
+ * running in VM with the following flags: -XX:MaxTenuringThreshold=1, -Xms10M,
+ * -Xmx10M, -XX:G1MixedGCLiveThresholdPercent=100, -XX:G1HeapWastePercent=0,
+ * -XX:G1HeapRegionSize=1m
+ */
+class MixedGCProvoker {
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+ private static final List<byte[]> liveOldObjects = new ArrayList<>();
+ private static final List<byte[]> newObjects = new ArrayList<>();
+
+ private static void allocateOldObjects() throws Exception {
+ List<byte[]> deadOldObjects = new ArrayList<>();
+ // Allocates buffer and promotes it to the old gen. Mix live and dead old
+ // objects
+ for (int i = 0; i < TestLogging.ALLOCATION_COUNT; ++i) {
+ liveOldObjects.add(new byte[TestLogging.ALLOCATION_SIZE * 10]);
+ deadOldObjects.add(new byte[TestLogging.ALLOCATION_SIZE * 10]);
+ }
+
+ // need only 2 promotions to promote objects to the old gen
+ WB.youngGC();
+ WB.youngGC();
+ // check it is promoted & keep alive
+ Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects),
+ "List of the objects is suppose to be in OldGen");
+ Asserts.assertTrue(WB.isObjectInOldGen(deadOldObjects),
+ "List of the objects is suppose to be in OldGen");
+ }
+
+
+ /**
+ * Waits until Concurent Mark Cycle finishes
+ * @param wb Whitebox instance
+ * @param sleepTime sleep time
+ */
+ public static void waitTillCMCFinished(WhiteBox wb, int sleepTime) {
+ while (wb.g1InConcurrentMark()) {
+ if (sleepTime > -1) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish");
+ }
+ }
+ }
+ }
+
+
+
+ public static void main(String args[]) throws Exception {
+ // allocate old objects
+ allocateOldObjects();
+ waitTillCMCFinished(WB, 0);
+ WB.g1StartConcMarkCycle();
+ waitTillCMCFinished(WB, 0);
+
+ WB.youngGC();
+ System.out.println("Allocating new objects to provoke mixed GC");
+ // allocate more objects to provoke GC
+ for (int i = 0; i < (TestLogging.ALLOCATION_COUNT * 20); i++) {
+ newObjects.add(new byte[TestLogging.ALLOCATION_SIZE]);
+ }
+ // check that liveOldObjects still alive
+ Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects),
+ "List of the objects is suppose to be in OldGen");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/logging/TestPrintReferences.java Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, 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 TestPrintReferences
+ * @bug 8136991
+ * @summary Validate the reference processing logging
+ * @key gc
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ */
+
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class TestPrintReferences {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb_enabled =
+ ProcessTools.createJavaProcessBuilder("-XX:+PrintGCDetails", "-XX:+PrintReferenceGC", "-Xmx10M", GCTest.class.getName());
+ OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());
+
+ String countRegex = "[0-9]+ refs";
+ String timeRegex = "[0-9]+[.,][0-9]+ secs";
+
+ output.shouldMatch(
+ "#[0-9]+: \\[SoftReference, " + countRegex + ", " + timeRegex + "\\]" +
+ "#[0-9]+: \\[WeakReference, " + countRegex + ", " + timeRegex + "\\]" +
+ "#[0-9]+: \\[FinalReference, " + countRegex + ", " + timeRegex + "\\]" +
+ "#[0-9]+: \\[PhantomReference, " + countRegex + ", " + timeRegex + "\\]" +
+ "#[0-9]+: \\[JNI Weak Reference, (" + countRegex + ", )?" + timeRegex + "\\]");
+
+ output.shouldHaveExitValue(0);
+ }
+
+ static class GCTest {
+ public static void main(String [] args) {
+ System.gc();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/TestVMOptionsFile.java Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2015, 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 8061999
+ * @summary Test "-XX:VMOptionsFile" VM option
+ * @library /testlibrary
+ * @modules jdk.management
+ * @run main TestVMOptionsFile
+ */
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.DynamicVMOption;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.nio.file.attribute.AclEntry;
+import java.nio.file.attribute.AclEntryPermission;
+import java.nio.file.attribute.AclEntryType;
+import java.nio.file.attribute.AclFileAttributeView;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.LinkedHashSet;
+
+public class TestVMOptionsFile {
+
+ /* Empty VM Option file */
+ private static final String VM_OPTION_FILE_EMPTY = "optionfile_empty";
+ /* VM Option file with tabs and spaces */
+ private static final String VM_OPTION_FILE_TABS_AND_SPACES = "optionfile_only_tabsandspaces";
+ /* Various valid VM Option files */
+ private static final String VM_OPTION_FILE_1 = "optionfile_1";
+ private static final String VM_OPTION_FILE_2 = "optionFILE_2";
+ private static final String VM_OPTION_FILE_3 = "optionfile_3";
+ private static final String VM_OPTION_FILE_QUOTE = "optionfile_quote";
+ private static final String VM_OPTION_FILE_QUOTE_MAX_SIZE = "optionfile_quote_max_size";
+ /* 2 VM Option files with unmatched quotes */
+ private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_1 = "optionfile_unmatched_quote_1";
+ private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_2 = "optionfile_unmatched_quote_2";
+ /* Name of the file with flags for VM_OPTION_FILE_2 Option file */
+ private static final String FLAGS_FILE = "flags_file";
+ /* VM Option file with a lot of options with quote on separate lines */
+ private static final String VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE = "optionfile_lot_of_options_quote";
+ /* Number of properties defined in VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE */
+ private static final int NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE = 65;
+ /* VM Option file with bad option in it */
+ private static final String VM_OPTION_FILE_WITH_BAD_OPTION = "optionfile_bad_option";
+ /* VM Option file with "-XX:VMOptionsFile=" option in it */
+ private static final String VM_OPTION_FILE_WITH_VM_OPTION_FILE = "optionfile_with_optionfile";
+ /* VM Option file with "-XX:VMOptionsFile=" option in it, where file is the same option file */
+ private static final String VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE = "optionfile_with_same_optionfile";
+ /* VM Option file without read permissions(not accessible) */
+ private static final String VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS = "optionfile_wo_read_perm";
+ /* VM Option file with long property(file size is 1024 bytes) */
+ private static final String VM_OPTION_FILE_WITH_LONG_PROPERTY = "optionfile_long_property";
+ /* VM Option file with very long property(file size is more than 1024 bytes) */
+ private static final String VM_OPTION_FILE_WITH_VERY_LONG_PROPERTY = "optionfile_very_long_property";
+ /* VM Option file which does not exist */
+ private static final String NOT_EXISTING_FILE = "not_exist_junk2123";
+
+ /* JAVA_TOOL_OPTIONS environment variable */
+ private static final String JAVA_TOOL_OPTIONS = "JAVA_TOOL_OPTIONS";
+ /* _JAVA_OPTIONS environment variable */
+ private static final String JAVA_OPTIONS = "_JAVA_OPTIONS";
+
+ /* Exit code for JVM, zero - for success, non-zero for failure */
+ private static final int JVM_SUCCESS = 0;
+ private static final int JVM_FAIL_WITH_EXIT_CODE_1 = 1;
+
+ /* Current working directory */
+ private static final String CURRENT_DIR = System.getProperty("user.dir");
+
+ /* Source directory */
+ private static final String SOURCE_DIR = System.getProperty("test.src", ".");
+
+ /* VM Options which are passed to the JVM */
+ private static final List<String> VMParams = new ArrayList<>();
+ /* Argument passed to the PrintPropertyAndOptions.main */
+ private static final Set<String> appParams = new LinkedHashSet<>();
+
+ private static OutputAnalyzer output;
+
+ /*
+ * Get absoulte path to file from folder with sources
+ */
+ private static String getAbsolutePathFromSource(String fileName) {
+ return SOURCE_DIR + File.separator + fileName;
+ }
+
+ /*
+ * Make file non-readable by modifying its permissions.
+ * If file supports "posix" attributes, then modify it.
+ * Otherwise check for "acl" attributes.
+ */
+ private static void makeFileNonReadable(String file) throws IOException {
+ Path filePath = Paths.get(file);
+ Set<String> supportedAttr = filePath.getFileSystem().supportedFileAttributeViews();
+
+ if (supportedAttr.contains("posix")) {
+ Files.setPosixFilePermissions(filePath, PosixFilePermissions.fromString("-w--w----"));
+ } else if (supportedAttr.contains("acl")) {
+ UserPrincipal fileOwner = Files.getOwner(filePath);
+
+ AclFileAttributeView view = Files.getFileAttributeView(filePath, AclFileAttributeView.class);
+
+ AclEntry entry = AclEntry.newBuilder()
+ .setType(AclEntryType.DENY)
+ .setPrincipal(fileOwner)
+ .setPermissions(AclEntryPermission.READ_DATA)
+ .build();
+
+ List<AclEntry> acl = view.getAcl();
+ acl.add(0, entry);
+ view.setAcl(acl);
+ }
+ }
+
+ private static void copyFromSource(String fileName) throws IOException {
+ Files.copy(Paths.get(getAbsolutePathFromSource(fileName)),
+ Paths.get(fileName), StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ private static void createOptionFiles() throws IOException {
+ FileWriter fw = new FileWriter(VM_OPTION_FILE_WITH_VM_OPTION_FILE);
+
+ /* Create VM option file with following parameters "-XX:VMOptionFile=<absolute_path_to_the_VM_option_file> */
+ fw.write("-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1));
+ fw.close();
+
+ /* Create VM option file with following parameters "-XX:MinHeapFreeRatio=12 -XX:VMOptionFile=<absolute_path_to_the_same_VM_option_file> */
+ fw = new FileWriter(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE);
+ fw.write("-XX:MinHeapFreeRatio=12 -XX:VMOptionsFile=" + (new File(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE)).getCanonicalPath());
+ fw.close();
+
+ /* Copy valid VM option file and change its permission to make it not accessible */
+ Files.copy(Paths.get(getAbsolutePathFromSource(VM_OPTION_FILE_1)),
+ Paths.get(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS),
+ StandardCopyOption.REPLACE_EXISTING);
+
+ makeFileNonReadable(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS);
+
+ /* Copy valid VM option file to perform test with relative path */
+ copyFromSource(VM_OPTION_FILE_2);
+
+ /* Copy flags file to the current working folder */
+ copyFromSource(FLAGS_FILE);
+
+ /* Create a new empty file */
+ new File(VM_OPTION_FILE_EMPTY).createNewFile();
+ }
+
+ /*
+ * Add parameters to the VM Parameters list
+ */
+ private static void addVMParam(String... params) {
+ VMParams.addAll(Arrays.asList(params));
+ }
+
+ /*
+ * Add property name to the application arguments list
+ */
+ private static void addPropertiesToCheck(String... params) {
+ for (String param : params) {
+ appParams.add("property=" + param);
+ }
+ }
+
+ /*
+ * Add VM option name to the application arguments list
+ */
+ private static void addVMOptionsToCheck(String... params) {
+ for (String param : params) {
+ appParams.add("vmoption=" + param);
+ }
+ }
+
+ /*
+ * Add property to the VM Params list and to the application arguments list
+ */
+ private static void addProperty(String propertyName, String propertyValue) {
+ addVMParam("-D" + propertyName + "=" + propertyValue);
+ addPropertiesToCheck(propertyName);
+ }
+
+ /*
+ * Add "-XX:VMOptionsfile" parameter to the VM Params list
+ */
+ private static void addVMOptionsFile(String fileName) {
+ addVMParam("-XX:VMOptionsFile=" + fileName);
+ }
+
+ private static void outputShouldContain(String expectedString) {
+ output.shouldContain(expectedString);
+ }
+
+ private static void outputShouldNotContain(String expectedString) {
+ output.shouldNotContain(expectedString);
+ }
+
+ private static ProcessBuilder createProcessBuilder() throws Exception {
+ ProcessBuilder pb;
+ List<String> runJava = new ArrayList<>();
+
+ runJava.addAll(VMParams);
+ runJava.add(PrintPropertyAndOptions.class.getName());
+ runJava.addAll(appParams);
+
+ pb = ProcessTools.createJavaProcessBuilder(runJava.toArray(new String[0]));
+
+ VMParams.clear();
+ appParams.clear();
+
+ return pb;
+ }
+
+ private static void runJavaCheckExitValue(ProcessBuilder pb, int expectedExitValue) throws Exception {
+ output = new OutputAnalyzer(pb.start());
+ output.shouldHaveExitValue(expectedExitValue);
+ }
+
+ private static void runJavaCheckExitValue(int expectedExitValue) throws Exception {
+ runJavaCheckExitValue(createProcessBuilder(), expectedExitValue);
+ }
+
+ /*
+ * Update environment variable in passed ProcessBuilder object to the passed value
+ */
+ private static void updateEnvironment(ProcessBuilder pb, String name, String value) {
+ pb.environment().put(name, value);
+ }
+
+ /*
+ * Check property value by examining output
+ */
+ private static void checkProperty(String property, String value) {
+ outputShouldContain("Property " + property + "=" + value);
+ }
+
+ /*
+ * Check VM Option value by examining output
+ */
+ private static void checkVMOption(String vmOption, String value) {
+ outputShouldContain("VM Option " + vmOption + "=" + value);
+ }
+
+ private static void testVMOptions() throws Exception {
+ StringBuilder longProperty = new StringBuilder();
+
+ /* Check that empty VM Option file is accepted without errors */
+ addVMOptionsFile(VM_OPTION_FILE_EMPTY);
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+
+ /* Check that VM Option file with tabs and spaces is accepted without errors */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_TABS_AND_SPACES));
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+
+ /* Check that parameters are gotten from first VM Option file. Pass absolute path to the VM Option file */
+ addVMParam("-showversion");
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1));
+ addPropertiesToCheck("optfile_1");
+ addVMOptionsToCheck("SurvivorRatio", "MinHeapFreeRatio");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+ outputShouldContain("interpreted mode");
+ checkProperty("optfile_1", "option_file_1");
+ checkVMOption("SurvivorRatio", "16");
+ checkVMOption("MinHeapFreeRatio", "22");
+
+ /*
+ * Check that parameters are gotten from second VM Option file which also contains flags file.
+ * Flags file and option file contains NewRatio, but since options from VM Option file
+ * are processed later NewRatio should be set to value from VM Option file
+ * Pass relative path to the VM Option file in form "vmoptionfile"
+ */
+ addVMOptionsFile(VM_OPTION_FILE_2);
+ addPropertiesToCheck("javax.net.ssl.keyStorePassword");
+ addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio", "MinHeapFreeRatio", "MaxFDLimit", "AlwaysPreTouch");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+ checkProperty("javax.net.ssl.keyStorePassword", "someVALUE123+");
+ checkVMOption("UseGCOverheadLimit", "true");
+ checkVMOption("NewRatio", "4");
+ checkVMOption("MinHeapFreeRatio", "3");
+ checkVMOption("MaxFDLimit", "true");
+ checkVMOption("AlwaysPreTouch", "false");
+
+ /* Check that parameters are gotten from third VM Option file which contains a mix of the options */
+ addVMParam("-showversion");
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_3));
+ addPropertiesToCheck("other.secret.data", "property");
+ addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+ outputShouldContain("interpreted mode");
+ checkProperty("other.secret.data", "qwerty");
+ checkProperty("property", "second");
+ checkVMOption("UseGCOverheadLimit", "false");
+ checkVMOption("NewRatio", "16");
+
+ /* Check that quotes are processed normally in VM Option file */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_QUOTE));
+ addPropertiesToCheck("my.quote.single", "my.quote.double", "javax.net.ssl.trustStorePassword");
+ addVMOptionsToCheck("ErrorFile");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+
+ checkProperty("my.quote.single", "Property in single quote. Here a double qoute\" Add some slashes \\/");
+ checkProperty("my.quote.double", "Double qoute. Include single '.");
+ checkProperty("javax.net.ssl.trustStorePassword", "data @+NEW");
+ checkVMOption("ErrorFile", "./my error file");
+
+ /* Check that quotes are processed normally in VM Option file. Pass max size file */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_QUOTE_MAX_SIZE));
+
+ addPropertiesToCheck("big");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+
+ checkProperty("big", String.format("%01016d", 9));
+
+ /*
+ * Verify that VM Option file accepts a file with 65 properties and with two options on separate
+ * lines and properties that use quotes a lot.
+ */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE));
+ for (int i = 1; i <= NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE; i++) {
+ addPropertiesToCheck(String.format("prop%02d", i));
+ }
+ addVMOptionsToCheck("MinHeapFreeRatio", "MaxHeapFreeRatio");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+
+ for (int i = 1; i <= NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE; i++) {
+ checkProperty(String.format("prop%02d", i), String.format("%02d", i));
+ }
+ checkVMOption("MinHeapFreeRatio", "7");
+ checkVMOption("MaxHeapFreeRatio", "96");
+
+ /*
+ * Verify that VM Option file accepts a file with maximum allowed size(1024 bytes)
+ */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITH_LONG_PROPERTY));
+ addPropertiesToCheck("very.very.long.property");
+
+ runJavaCheckExitValue(JVM_SUCCESS);
+ for (int i = 1; i < 249; i++) {
+ longProperty.append("long");
+ }
+ longProperty.append("l");
+ checkProperty("very.very.long.property", longProperty.toString());
+ }
+
+ private static ProcessBuilder prepareTestCase(int testCase) throws Exception {
+ ProcessBuilder pb;
+
+ Asserts.assertTrue(0 < testCase && testCase < 6, "testCase should be from 1 to 5");
+
+ addVMParam("-showversion");
+ addPropertiesToCheck("jto", "jo", "optfile_1", "shared.property");
+ addVMOptionsToCheck("MinHeapFreeRatio", "SurvivorRatio", "NewRatio");
+
+ if (testCase < 5) {
+ addVMParam("-XX:Flags=flags_file");
+ addProperty("shared.property", "command_line_before");
+ addProperty("clb", "unique_command_line_before");
+ addVMParam("-XX:MinHeapFreeRatio=7");
+ }
+
+ if (testCase < 4) {
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1));
+ }
+
+ if (testCase < 3) {
+ addVMParam("-XX:MinHeapFreeRatio=9");
+ addProperty("shared.property", "command_line_after");
+ addProperty("cla", "unique_command_line_after");
+ }
+
+ /* Create ProcessBuilder after all setup is done to update environment variables */
+ pb = createProcessBuilder();
+
+ if (testCase < 2) {
+ updateEnvironment(pb, JAVA_OPTIONS, "-Dshared.property=somevalue -Djo=unique_java_options "
+ + "-XX:MinHeapFreeRatio=18 -Dshared.property=java_options -XX:MinHeapFreeRatio=11");
+ }
+
+ if (testCase < 6) {
+ updateEnvironment(pb, JAVA_TOOL_OPTIONS, "-Dshared.property=qwerty -Djto=unique_java_tool_options "
+ + "-XX:MinHeapFreeRatio=15 -Dshared.property=java_tool_options -XX:MinHeapFreeRatio=6");
+ }
+
+ return pb;
+ }
+
+ private static void testVMOptionsLastArgumentsWins() throws Exception {
+ ProcessBuilder pb;
+
+ /*
+ * "shared.property" property and "MinHeapFreeRatio" XX VM Option are defined
+ * in flags file, JAVA_TOOL_OPTIONS and _JAVA_OPTIONS environment variables,
+ * on command line before VM Option file, on command line after VM Option file
+ * and also in VM Option file. Verify that last argument wins. Also check
+ * unique properties and VM Options.
+ * Here is the order of options processing and last argument wins:
+ * 1) Flags file
+ * 2) JAVA_TOOL_OPTIONS environment variables
+ * 3) Pseudo command line from launcher
+ * 4) _JAVA_OPTIONS
+ * In every category arguments processed from left to right and from up to down
+ * and the last processed arguments wins, i.e. if argument is defined several
+ * times the value of argument will be equal to the last processed argument.
+ *
+ * "shared.property" property and "MinHeapFreeRatio" should be equal to the
+ * value from _JAVA_OPTIONS environment variable
+ */
+ pb = prepareTestCase(1);
+
+ runJavaCheckExitValue(pb, JVM_SUCCESS);
+
+ outputShouldContain("interpreted mode");
+ checkProperty("shared.property", "java_options");
+ checkVMOption("MinHeapFreeRatio", "11");
+ /* Each category defines its own properties */
+ checkProperty("jto", "unique_java_tool_options");
+ checkProperty("jo", "unique_java_options");
+ checkProperty("clb", "unique_command_line_before");
+ checkProperty("optfile_1", "option_file_1");
+ checkProperty("cla", "unique_command_line_after");
+ /* SurvivorRatio defined only in VM Option file */
+ checkVMOption("SurvivorRatio", "16");
+ /* NewRatio defined only in flags file */
+ checkVMOption("NewRatio", "5");
+
+ /*
+ * The same as previous but without _JAVA_OPTIONS environment variable.
+ * "shared.property" property and "MinHeapFreeRatio" should be equal to the
+ * value from pseudo command line after VM Option file
+ */
+ pb = prepareTestCase(2);
+
+ runJavaCheckExitValue(pb, JVM_SUCCESS);
+
+ outputShouldContain("interpreted mode");
+ checkProperty("shared.property", "command_line_after");
+ checkVMOption("MinHeapFreeRatio", "9");
+
+ /*
+ * The same as previous but without arguments in pseudo command line after
+ * VM Option file.
+ * "shared.property" property and "MinHeapFreeRatio" should be equal to the
+ * value from VM Option file.
+ */
+ pb = prepareTestCase(3);
+
+ runJavaCheckExitValue(pb, JVM_SUCCESS);
+
+ outputShouldContain("interpreted mode");
+ checkProperty("shared.property", "vmoptfile");
+ checkVMOption("MinHeapFreeRatio", "22");
+
+ /*
+ * The same as previous but without arguments in VM Option file.
+ * "shared.property" property and "MinHeapFreeRatio" should be equal to the
+ * value from pseudo command line.
+ */
+ pb = prepareTestCase(4);
+
+ runJavaCheckExitValue(pb, JVM_SUCCESS);
+
+ checkProperty("shared.property", "command_line_before");
+ checkVMOption("MinHeapFreeRatio", "7");
+
+ /*
+ * The same as previous but without arguments from pseudo command line.
+ * "shared.property" property and "MinHeapFreeRatio" should be equal to the
+ * value from JAVA_TOOL_OPTIONS environment variable.
+ */
+ pb = prepareTestCase(5);
+
+ runJavaCheckExitValue(pb, JVM_SUCCESS);
+
+ checkProperty("shared.property", "java_tool_options");
+ checkVMOption("MinHeapFreeRatio", "6");
+ }
+
+ private static void testVMOptionsInvalid() throws Exception {
+ ProcessBuilder pb;
+
+ /* Pass directory instead of file */
+ addVMOptionsFile(CURRENT_DIR);
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+
+ /* Pass not existing file */
+ addVMOptionsFile(getAbsolutePathFromSource(NOT_EXISTING_FILE));
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Could not open options file");
+
+ /* Pass VM option file with bad option */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITH_BAD_OPTION));
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Unrecognized VM option");
+
+ /* Pass VM option file with same VM option file option in it */
+ addVMOptionsFile(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE);
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("VM options file is only supported on the command line");
+
+ /* Pass VM option file with VM option file option in it */
+ addVMOptionsFile(VM_OPTION_FILE_WITH_VM_OPTION_FILE);
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("VM options file is only supported on the command line");
+
+ /* Pass VM option file with very long property(more than 1024 bytes) */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITH_VERY_LONG_PROPERTY));
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Options file");
+ outputShouldContain("is larger than 1024 bytes");
+
+ /* Pass VM option file which is not accessible (without read permissions) */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS));
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Could not open options file");
+
+ /* Pass two VM option files */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1));
+ addVMOptionsFile(VM_OPTION_FILE_2);
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Only one VM Options file is supported on the command line");
+
+ /* Pass empty option file i.e. pass "-XX:VMOptionsFile=" */
+ addVMOptionsFile("");
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Could not open options file");
+
+ /* Pass VM option file with unmatched single quote */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_1));
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Unmatched quote in");
+
+ /* Pass VM option file with unmatched double quote in X option */
+ addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_2));
+
+ runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
+ outputShouldContain("Unmatched quote in");
+ }
+
+ public static void main(String[] args) throws Exception {
+ /*
+ * Preparation before actual testing - create two VM Option files
+ * which contains VM Option file in it and copy other files to the
+ * current working folder
+ */
+ createOptionFiles();
+
+ testVMOptions(); /* Test VM Option file general functionality */
+ testVMOptionsLastArgumentsWins(); /* Verify that last argument wins */
+ testVMOptionsInvalid(); /* Test invalid VM Option file functionality */
+
+ }
+
+ public static class PrintPropertyAndOptions {
+
+ public static void main(String[] arguments) {
+ String property;
+ String vmOption;
+ for (String arg : arguments) {
+ if (arg.startsWith("property=")) {
+ property = arg.substring(9);
+ System.out.println("Property " + property + "=" + System.getProperty(property, "NOT DEFINED"));
+ } else if (arg.startsWith("vmoption=")) {
+ vmOption = arg.substring(9);
+ System.out.println("VM Option " + vmOption + "=" + (new DynamicVMOption(vmOption)).getValue());
+ }
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/flags_file Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,5 @@
++MaxFDLimit
+-AlwaysPreTouch
+MinHeapFreeRatio=3
+MaxHeapFreeRatio=89
+NewRatio=5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionFILE_2 Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,4 @@
+-XX:+UseGCOverheadLimit
+-XX:Flags=flags_file
+-Djavax.net.ssl.keyStorePassword=someVALUE123+
+-XX:NewRatio=4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_1 Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-Dshared.property=othervalue -XX:MinHeapFreeRatio=13 -Doptfile_1=option_file_1 -Xint -XX:SurvivorRatio=16 -Xminf0.22 -Dshared.property=vmoptfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_3 Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,8 @@
+-Xcomp -Dproperty=first
+
+ -Xint
+-XX:+UseGCOverheadLimit
+
+ -XX:NewRatio=4 -XX:-UseGCOverheadLimit -Dproperty=second
+
+-Dother.secret.data=qwerty -XX:NewRatio=16
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_bad_option Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-Dmy.property=user1 -XX:bad_option -Xint
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_long_property Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-Dvery.very.long.property=longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_lot_of_options_quote Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,66 @@
+-Dprop01='01'
+-Dprop02='02'
+-Dprop03='03'
+-Dprop04='04'
+-Dprop05='05'
+-D"pr"op06='06'
+-Dprop07='07'
+-Dprop08='08'
+-Dprop09="09"
+-Dprop"10=10"
+-Dprop11='11'
+'-Dprop12=12'
+-Dprop13='13'
+-Dprop14='14'
+-Dprop15='15'
+-Dprop16='16'
+-Dprop17='17'
+-Dprop18='18'
+-Dprop19='19'
+-Dprop20='20'
+-Dprop21='21'
+-Dprop22='22'
+-Dprop23='23'
+-Dpr'o'p24='24'
+-Dprop25='25'
+-Dprop26='26'
+-Dprop27='27'
+-Dprop28='28'
+-XX:MinHeapFreeRatio=7
+-D"prop29=29"
+-Dprop30='30'
+-Dprop31='31'
+-Dprop32="32"
+-Dprop33='33'
+-Dprop34='34'
+-Dprop35='35'
+'-Dpr'op36='36'
+-Dprop37='37'
+-Dprop38='38'
+-Dprop39='39'
+-Dprop40='40'
+-Dprop41='41'
+-Dprop42='42'
+-Dprop43='43'
+-Dprop44='44'
+-Dprop45='45'
+-D"prop46="'46'
+-Dprop47='47'
+-Dprop48='48'
+-Dprop49='49' -XX:MaxHeapFreeRatio=96
+"-"Dprop50='50'
+-Dprop51='51'
+-Dprop52='52'
+-Dprop53='53'
+-Dprop54='54'
+-Dprop55='55'
+-Dprop56='56'
+-Dprop57='57'
+-"D"prop58='58'
+-Dprop59='59'
+'-Dprop60=''60'
+-Dprop61='61'
+-Dprop62='62'
+-Dprop63='63'
+-Dprop64=64
+-Dprop65=65
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_only_tabsandspaces Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,4 @@
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+'-Dmy.quote.single'='Property in single quote. Here a double qoute" Add some slashes \/' -D"my.quote.double"="Double qoute. Include single '." -'Xloggc':log"gc.log" -X"X:ErrorFile"=./my' error file' -Djavax.net.ssl.trustStorePassword='data @+NEW'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote_max_size Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-Dbig='00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009'
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_1 Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-Dmy.quote.single='Unmatched single quote with embedded double " quote
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_2 Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-"Xloggc:Unmatched quote in X option
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_very_long_property Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,1 @@
+-Dvery.very.long.property=longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/NMT/CommitOverlappingRegions.java Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, 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 Test commits of overlapping regions of memory.
+ * @key nmt jcmd
+ * @library /testlibrary /../../test/lib
+ * @modules java.base/sun.misc
+ * java.management
+ * @build CommitOverlappingRegions
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail CommitOverlappingRegions
+ */
+
+import jdk.test.lib.*;
+import sun.hotspot.WhiteBox;
+
+public class CommitOverlappingRegions {
+ public static WhiteBox wb = WhiteBox.getWhiteBox();
+ public static void main(String args[]) throws Exception {
+ OutputAnalyzer output;
+ long size = 32 * 1024;
+ long addr;
+
+ String pid = Integer.toString(ProcessTools.getProcessId());
+ ProcessBuilder pb = new ProcessBuilder();
+
+ addr = wb.NMTReserveMemory(8*size); // [ ]
+ pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
+ // Test output before commits
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("(reserved=256KB, committed=0KB)");
+
+ // Commit regions 1 and 2, then test output.
+ wb.NMTCommitMemory(addr + 0*size, 3*size); // [ ]
+ wb.NMTCommitMemory(addr + 4*size, 3*size); // [ ]
+
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("(reserved=256KB, committed=192KB)");
+
+ // Commit the final region which overlaps partially with both regions.
+ wb.NMTCommitMemory(addr + 2*size, 3*size); // [ ]
+
+ output = new OutputAnalyzer(pb.start());
+ output.getOutput();
+ output.shouldContain("(reserved=256KB, committed=224KB)");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/logging/TestBasicLogOutput.java Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 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 TestBasicLogOutput
+ * @summary Ensure logging can be enabled and successfully prints to stdout.
+ * @library /testlibrary
+ */
+
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class TestBasicLogOutput {
+
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:all=trace", "-version");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("[logging]"); // expected tag(s)
+ output.shouldContain("Log configuration fully initialized."); // expected message
+ output.shouldHaveExitValue(0);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java Mon Sep 28 15:05:02 2015 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015, 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.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.apps.LingeredAppWithDeadlock;
+
+import jdk.test.lib.Utils;
+import jdk.test.lib.Platform;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+
+/*
+ * @test
+ * @summary Test deadlock detection
+ * @library /../../test/lib/share/classes
+ * @library /testlibrary
+ * @modules java.management
+ * @build jdk.test.lib.*
+ * @build jdk.test.lib.apps.*
+ * @build DeadlockDetectionTest
+ * @run main DeadlockDetectionTest
+ */
+
+public class DeadlockDetectionTest {
+
+ private static LingeredAppWithDeadlock theApp = null;
+ private static ProcessBuilder processBuilder = new ProcessBuilder();
+
+ private static OutputAnalyzer jstack(String... toolArgs) throws Exception {
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
+ launcher.addToolArg("jstack");
+ if (toolArgs != null) {
+ for (String toolArg : toolArgs) {
+ launcher.addToolArg(toolArg);
+ }
+ }
+
+ processBuilder.command(launcher.getCommand());
+ System.out.println(processBuilder.command().stream().collect(Collectors.joining(" ")));
+ OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
+ System.out.println(output.getOutput());
+
+ return output;
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("Starting DeadlockDetectionTest");
+
+ if (!Platform.shouldSAAttach()) {
+ // Silently skip the test if we don't have enough permissions to attach
+ // Not all conditions checked by function is relevant to SA but it's worth
+ // to check
+ System.err.println("Error! Insufficient permissions to attach.");
+ return;
+ }
+
+
+ if (!LingeredApp.isLastModifiedWorking()) {
+ // Exact behaviour of the test depends on operating system and the test nature,
+ // so just print the warning and continue
+ System.err.println("Warning! Last modified time doesn't work.");
+ }
+
+ try {
+ List<String> vmArgs = new ArrayList<String>();
+ vmArgs.add("-XX:+UsePerfData");
+ vmArgs.addAll(Utils.getVmOptions());
+
+ theApp = new LingeredAppWithDeadlock();
+ LingeredApp.startApp(vmArgs, theApp);
+ OutputAnalyzer output = jstack("--pid", Long.toString(theApp.getPid()));
+ System.out.println(output.getOutput());
+
+ if (output.getExitValue() == 3) {
+ System.out.println("Test can't run for some reason. Skipping");
+ }
+ else {
+ output.shouldHaveExitValue(0);
+ output.shouldContain("Found a total of 1 deadlock.");
+ }
+
+ } finally {
+ LingeredApp.stopApp(theApp);
+ }
+ }
+}