< prev index next >

src/java.base/share/classes/java/lang/PinnedThreadPrinter.java

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
--- 1,7 ---
  /*
!  * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

*** 32,19 ***
  import java.util.Map;
  import java.util.Objects;
  import java.util.Set;
  import java.util.stream.Collectors;
  import static java.lang.StackWalker.Option.*;
  
  /**
   * Helper class to print the virtual thread stack trace when pinned.
   *
   * The class maintains a ClassValue with the hashes of stack traces that are pinned by
   * code in that Class. This is used to avoid printing the same stack trace many times.
   */
  class PinnedThreadPrinter {
!     static final StackWalker STACK_WALKER;
      static {
          var options = Set.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE);
          PrivilegedAction<StackWalker> pa = () ->
              LiveStackFrame.getStackWalker(options, VirtualThread.continuationScope());
          @SuppressWarnings("removal")
--- 32,23 ---
  import java.util.Map;
  import java.util.Objects;
  import java.util.Set;
  import java.util.stream.Collectors;
  import static java.lang.StackWalker.Option.*;
+ import jdk.internal.access.JavaIOPrintStreamAccess;
+ import jdk.internal.access.SharedSecrets;
+ import jdk.internal.misc.InternalLock;
  
  /**
   * Helper class to print the virtual thread stack trace when pinned.
   *
   * The class maintains a ClassValue with the hashes of stack traces that are pinned by
   * code in that Class. This is used to avoid printing the same stack trace many times.
   */
  class PinnedThreadPrinter {
!     private static final JavaIOPrintStreamAccess JIOPSA = SharedSecrets.getJavaIOPrintStreamAccess();
+     private static final StackWalker STACK_WALKER;
      static {
          var options = Set.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE);
          PrivilegedAction<StackWalker> pa = () ->
              LiveStackFrame.getStackWalker(options, VirtualThread.continuationScope());
          @SuppressWarnings("removal")

*** 84,11 ***
          }
          return hash;
      }
  
      /**
!      * Prints the continuation stack trace.
       *
       * @param printAll true to print all stack frames, false to only print the
       *        frames that are native or holding a monitor
       */
      static void printStackTrace(PrintStream out, boolean printAll) {
--- 88,11 ---
          }
          return hash;
      }
  
      /**
!      * Prints the current thread's stack trace.
       *
       * @param printAll true to print all stack frames, false to only print the
       *        frames that are native or holding a monitor
       */
      static void printStackTrace(PrintStream out, boolean printAll) {

*** 96,25 ***
              s.map(f -> (LiveStackFrame) f)
                      .filter(f -> f.getDeclaringClass() != PinnedThreadPrinter.class)
                      .collect(Collectors.toList())
          );
  
!         // find the closest frame that is causing the thread to be pinned
!         stack.stream()
!             .filter(f -> (f.isNativeMethod() || f.getMonitors().length > 0))
!             .map(LiveStackFrame::getDeclaringClass)
!             .findFirst()
!             .ifPresentOrElse(klass -> {
!                 int hash = hash(stack);
!                 Hashes hashes = HASHES.get(klass);
!                 synchronized (hashes) {
!                     // print the stack trace if not already seen
!                     if (hashes.add(hash)) {
!                         printStackTrace(stack, out, printAll);
!                     }
!                 }
!             }, () -> printStackTrace(stack, out, true));  // not found
      }
  
      private static void printStackTrace(List<LiveStackFrame> stack,
                                          PrintStream out,
                                          boolean printAll) {
--- 100,31 ---
              s.map(f -> (LiveStackFrame) f)
                      .filter(f -> f.getDeclaringClass() != PinnedThreadPrinter.class)
                      .collect(Collectors.toList())
          );
  
!         // tryLock to avoid blocking waiting for System.out
!         InternalLock lock = (InternalLock) JIOPSA.lock(out);
!         if (lock != null && lock.tryLock()) {
!             try {
!                 // find the closest frame that is causing the thread to be pinned
!                 stack.stream()
!                     .filter(f -> (f.isNativeMethod() || f.getMonitors().length > 0))
!                     .map(LiveStackFrame::getDeclaringClass)
!                     .findFirst()
!                     .ifPresentOrElse(klass -> {
!                         int hash = hash(stack);
!                         Hashes hashes = HASHES.get(klass);
!                         // print the stack trace if not already seen
!                         if (hashes.add(hash)) {
!                             printStackTrace(stack, out, printAll);
+                         }
+                     }, () -> printStackTrace(stack, out, true));  // not found
+             } finally {
+                 lock.unlock();
+             }
+         }
      }
  
      private static void printStackTrace(List<LiveStackFrame> stack,
                                          PrintStream out,
                                          boolean printAll) {
< prev index next >