diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp index 68bd830cf1b403b5c001592aa947d684e720e3b3..29e3c01b83276e2e587d1a0d95ce2856ca539f36 100644 --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -1488,11 +1488,11 @@ void _handle_uncaught_cxx_exception() { // First crack at OS-specific initialization, from inside the new thread. -void os::initialize_thread() { +void os::initialize_thread(Thread* thr) { int r = thr_main() ; guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ; if (r) { - JavaThread* jt = (JavaThread *)Thread::current(); + JavaThread* jt = (JavaThread *)thr; assert(jt != NULL,"Sanity check"); size_t stack_size; address base = jt->stack_base(); diff --git a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index c6d31ab4f9ace281d90cb7e2ebc64d431d6ac3db..b7a808e353ef19e0df533ff8f2226e131f9cf315 100644 --- a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -297,7 +297,7 @@ char* os::non_memory_address_word() { return (char*) -1; } -void os::initialize_thread() { +void os::initialize_thread(Thread* thr) { // Nothing to do. } diff --git a/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp b/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp index 4bb5a8abb2406b2bb346c6895d652655ecde910e..64af2c1f86963131a83a9e4d72583c9bff804f7d 100644 --- a/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp +++ b/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp @@ -103,7 +103,7 @@ char* os::non_memory_address_word() { #endif // SPARC } -void os::initialize_thread() { +void os::initialize_thread(Thread* thr) { // Nothing to do. } diff --git a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp index 11c90e522fc83331666777bc519e2a899b012273..06ab7a7bfb4d71a8d6eae1006f360c4709e917d2 100644 --- a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp +++ b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp @@ -225,7 +225,7 @@ char* os::non_memory_address_word() { return (char*) 0; } -void os::initialize_thread() {} +void os::initialize_thread(Thread* thr) {} void os::print_context(outputStream *st, void *context) { if (context == NULL) return; diff --git a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index 93bb1f45919baacf91ad0e45fdad44e9d281ff74..1f927850c6661a24704e13f4057c53a027caf530 100644 --- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -114,7 +114,7 @@ char* os::non_memory_address_word() { return (char*) -1; } -void os::initialize_thread() { +void os::initialize_thread(Thread* thr) { // Nothing to do. } diff --git a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp index 203090ce07996a5ae3bb12360a15fffd344f9302..edc988ac99633178ba3f334c8885eca8ad59525b 100644 --- a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp +++ b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp @@ -98,7 +98,7 @@ char* os::non_memory_address_word() { #endif // SPARC } -void os::initialize_thread() { +void os::initialize_thread(Thread * thr){ // Nothing to do. } diff --git a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index 52fe243ee0e7250bfb2b317825e63444461e3c77..88d38f468e0dda8c5e8a326f40fbf6d152ac6e4e 100644 --- a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -219,7 +219,7 @@ bool os::register_code_area(char *low, char *high) { return true; } -void os::initialize_thread() { +void os::initialize_thread(Thread* thr) { // Nothing to do. } diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp index 93c3df0e402ff86b230996effc72436dd79a3f6a..c8e6e518565f3f9eba9907f6be6e8698ee2e3048 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp @@ -230,6 +230,7 @@ void ConcurrentMarkSweepThread::print_on(outputStream* st) const { void ConcurrentMarkSweepThread::print_all_on(outputStream* st) { if (_cmst != NULL) { _cmst->print_on(st); + st->cr(); } if (_collector != NULL) { AbstractWorkGang* gang = _collector->conc_workers(); diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index cd8de5f7c7f64353f196e9df69f45450a87bed0c..f0b4aea1193a728ea3e35326bb983cde22f06941 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -3420,7 +3420,6 @@ void G1CollectedHeap::print_gc_threads_on(outputStream* st) const { st->cr(); _cm->print_worker_threads_on(st); _cg1r->print_worker_threads_on(st); - st->cr(); } void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { diff --git a/src/share/vm/runtime/os.cpp b/src/share/vm/runtime/os.cpp index 6689cd4dc3c49b832d84e4310ba80922c7bdc877..55de8940a5bb465b867c9ca6c31d9ac050ef23cd 100644 --- a/src/share/vm/runtime/os.cpp +++ b/src/share/vm/runtime/os.cpp @@ -201,14 +201,21 @@ OSReturn os::set_priority(Thread* thread, ThreadPriority p) { } } - +// The mapping from OS priority back to Java priority may be inexact because +// Java priorities can map M:1 with native priorities. If you want the definite +// Java priority then use JavaThread::java_priority() OSReturn os::get_priority(const Thread* const thread, ThreadPriority& priority) { int p; int os_prio; OSReturn ret = get_native_priority(thread, &os_prio); if (ret != OS_OK) return ret; - for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] > os_prio; p--) ; + if (java_to_os_priority[MaxPriority] > java_to_os_priority[MinPriority]) { + for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] > os_prio; p--) ; + } else { + // niceness values are in reverse order + for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] < os_prio; p--) ; + } priority = (ThreadPriority)p; return OS_OK; } diff --git a/src/share/vm/runtime/os.hpp b/src/share/vm/runtime/os.hpp index 508edba8a3e93f40e81f473c0e33415adbf2b92e..bb5d6ea9e28345cf4587553b5053f823be16b077 100644 --- a/src/share/vm/runtime/os.hpp +++ b/src/share/vm/runtime/os.hpp @@ -387,7 +387,7 @@ class os: AllStatic { static void pd_start_thread(Thread* thread); static void start_thread(Thread* thread); - static void initialize_thread(); + static void initialize_thread(Thread* thr); static void free_thread(OSThread* osthread); // thread id on Linux/64bit is 64bit, on Windows and Solaris, it's 32bit diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp index 500010aa30510c9aa8252ce7ea8350145fcdffb6..d2f819260d7920ce39d5b17291ec57cb2074b0f6 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -308,19 +308,25 @@ void Thread::initialize_thread_local_storage() { // initialize structure dependent on thread local storage ThreadLocalStorage::set_thread(this); - - // set up any platform-specific state. - os::initialize_thread(); } void Thread::record_stack_base_and_size() { set_stack_base(os::current_stack_base()); set_stack_size(os::current_stack_size()); + // CR 7190089: on Solaris, primordial thread's stack is adjusted + // in initialize_thread(). Without the adjustment, stack size is + // incorrect if stack is set to unlimited (ulimit -s unlimited). + // So far, only Solaris has real implementation of initialize_thread(). + // + // set up any platform-specific state. + os::initialize_thread(this); - // record thread's native stack, stack grows downward - address low_stack_addr = stack_base() - stack_size(); - MemTracker::record_thread_stack(low_stack_addr, stack_size(), this, - CURRENT_PC); + // record thread's native stack, stack grows downward + if (MemTracker::is_on()) { + address stack_low_addr = stack_base() - stack_size(); + MemTracker::record_thread_stack(stack_low_addr, stack_size(), this, + CURRENT_PC); + } } @@ -836,7 +842,11 @@ void Thread::metadata_do(void f(Metadata*)) { void Thread::print_on(outputStream* st) const { // get_priority assumes osthread initialized if (osthread() != NULL) { - st->print("prio=%d tid=" INTPTR_FORMAT " ", get_priority(this), this); + int os_prio; + if (os::get_native_priority(this, &os_prio) == OS_OK) { + st->print("os_prio=%d ", os_prio); + } + st->print("tid=" INTPTR_FORMAT " ", this); osthread()->print_on(st); } debug_only(if (WizardMode) print_owned_locks_on(st);) @@ -2743,7 +2753,11 @@ void JavaThread::print_thread_state() const { void JavaThread::print_on(outputStream *st) const { st->print("\"%s\" ", get_thread_name()); oop thread_oop = threadObj(); - if (thread_oop != NULL && java_lang_Thread::is_daemon(thread_oop)) st->print("daemon "); + if (thread_oop != NULL) { + st->print("#" INT64_FORMAT " ", java_lang_Thread::thread_id(thread_oop)); + if (java_lang_Thread::is_daemon(thread_oop)) st->print("daemon "); + st->print("prio=%d ", java_lang_Thread::priority(thread_oop)); + } Thread::print_on(st); // print guess for valid stack memory region (assume 4K pages); helps lock debugging st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12)); @@ -4270,8 +4284,10 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format st->cr(); Universe::heap()->print_gc_threads_on(st); WatcherThread* wt = WatcherThread::watcher_thread(); - if (wt != NULL) wt->print_on(st); - st->cr(); + if (wt != NULL) { + wt->print_on(st); + st->cr(); + } CompileBroker::print_compiler_threads_on(st); st->flush(); } diff --git a/src/share/vm/services/memTracker.cpp b/src/share/vm/services/memTracker.cpp index befee59858f21a8982f0f72ab9099152b66eb6bc..91c324dfcc6e04076ae1eeb76f15f4316f4617f6 100644 --- a/src/share/vm/services/memTracker.cpp +++ b/src/share/vm/services/memTracker.cpp @@ -341,6 +341,7 @@ void MemTracker::release_thread_recorder(MemRecorder* rec) { */ void MemTracker::create_memory_record(address addr, MEMFLAGS flags, size_t size, address pc, Thread* thread) { + assert(addr != NULL, "Sanity check"); if (!shutdown_in_progress()) { // single thread, we just write records direct to global recorder,' // with any lock diff --git a/src/share/vm/services/memTracker.hpp b/src/share/vm/services/memTracker.hpp index c565e9e072cd45bfceba2a0b4d1cd48101d39dfa..eea28c169d06d2132b63f416dd8bb72e2ff5e5a9 100644 --- a/src/share/vm/services/memTracker.hpp +++ b/src/share/vm/services/memTracker.hpp @@ -185,6 +185,7 @@ class MemTracker : AllStatic { static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { if (NMT_CAN_TRACK(flags)) { + assert(size > 0, "Sanity check"); create_memory_record(addr, (flags|MemPointerRecord::malloc_tag()), size, pc, thread); } } @@ -198,6 +199,7 @@ class MemTracker : AllStatic { static inline void record_realloc(address old_addr, address new_addr, size_t size, MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { if (is_on()) { + assert(size > 0, "Sanity check"); record_free(old_addr, flags, thread); record_malloc(new_addr, size, flags, pc, thread); } @@ -208,6 +210,7 @@ class MemTracker : AllStatic { // we add a positive offset to arena address, so we can have arena size record // sorted after arena record if (is_on() && !UseMallocOnly) { + assert(addr != NULL, "Sanity check"); create_memory_record((addr + sizeof(void*)), MemPointerRecord::arena_size_tag(), size, 0, NULL); } @@ -217,7 +220,7 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_reserve(address addr, size_t size, address pc = 0, Thread* thread = NULL) { if (is_on()) { - assert(size > 0, "reserve szero size"); + assert(size > 0, "Sanity check"); create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag(), size, pc, thread); } @@ -248,6 +251,7 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_commit(address addr, size_t size, address pc = 0, Thread* thread = NULL) { if (is_on()) { + assert(size > 0, "Sanity check"); create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag(), size, DEBUG_CALLER_PC, thread); } @@ -257,6 +261,7 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_uncommit(address addr, size_t size, Thread* thread = NULL) { if (is_on()) { + assert(size > 0, "Sanity check"); create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag(), size, DEBUG_CALLER_PC, thread); } @@ -266,6 +271,7 @@ class MemTracker : AllStatic { static inline void record_virtual_memory_release(address addr, size_t size, Thread* thread = NULL) { if (is_on()) { + assert(size > 0, "Sanity check"); create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag(), size, DEBUG_CALLER_PC, thread); } diff --git a/test/runtime/7194254/Test7194254.java b/test/runtime/7194254/Test7194254.java new file mode 100644 index 0000000000000000000000000000000000000000..b3370ee74a90016f166338c9eb4cf40b5301cbaf --- /dev/null +++ b/test/runtime/7194254/Test7194254.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7194254 + * @summary Creates several threads with different java priorities and checks + * whether jstack reports correct priorities for them. + * + * @run main T7194254 + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Test7194254 { + + public static void main(String[] args) throws Exception { + final int NUMBER_OF_JAVA_PRIORITIES = + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY + 1; + final CyclicBarrier barrier = + new CyclicBarrier(NUMBER_OF_JAVA_PRIORITIES + 1); + + for (int p = Thread.MIN_PRIORITY; p <= Thread.MAX_PRIORITY; ++p) { + final int priority = p; + new Thread("Priority=" + p) { + { + setPriority(priority); + } + public void run() { + try { + barrier.await(); // 1st + barrier.await(); // 2nd + } catch (Exception exc) { + // ignore + } + } + }.start(); + } + barrier.await(); // 1st + + int matches = 0; + List failed = new ArrayList<>(); + try { + String pid = getPid(); + String jstack = System.getProperty("java.home") + "/../bin/jstack"; + Process process = new ProcessBuilder(jstack, pid) + .redirectErrorStream(true).start(); + Pattern pattern = Pattern.compile( + "\\\"Priority=(\\d+)\\\".* prio=(\\d+).*"); + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream()))) { + String line; + while((line = reader.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.matches()) { + matches += 1; + String expected = matcher.group(1); + String actual = matcher.group(2); + if (!expected.equals(actual)) { + failed.add(line); + } + } + } + } + barrier.await(); // 2nd + } finally { + barrier.reset(); + } + + if (matches != NUMBER_OF_JAVA_PRIORITIES) { + throw new AssertionError("matches: expected " + + NUMBER_OF_JAVA_PRIORITIES + ", but was " + matches); + } + if (!failed.isEmpty()) { + throw new AssertionError(failed.size() + ":" + failed); + } + System.out.println("Test passes."); + } + + static String getPid() { + RuntimeMXBean runtimebean = ManagementFactory.getRuntimeMXBean(); + String vmname = runtimebean.getName(); + int i = vmname.indexOf('@'); + if (i != -1) { + vmname = vmname.substring(0, i); + } + return vmname; + } + +} +