Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8338104

ScheduledThreadPoolExecutor.ScheduledFutureTask#getDelay overflow

XMLWordPrintable

      A DESCRIPTION OF THE PROBLEM :
      Calling `java.net.DatagramSocket#receive` in virtual thread would lead to virtualthread unparker scheduled after about Long.MAX_VALUE, which leading to negative time returned by `java.util.concurrent.ScheduledThreadPoolExecutor#triggerTime(long)`

      It may become the head of workQueue (depends on whether it overflows again when compareTo). If that happens, the unparker thread could park forever because getDelay is overflowed again to a very big number.

      Even worse, when first task is canceled (park condition met), the unparker thread is still parking because java.lang.VirtualThread#cancel pass false to maybeInterruptIfRunning.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Start a larger number of virtual thread calls datagramSocket.receive.
      2. Start a large number of virtual thread, park and do other things.
      3. "Other things" get blocked.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No overflow happened.
      ACTUAL -
      All virutal thread is blocked.

      ---------- BEGIN SOURCE ----------
      I can't reproduce the blocking with simple code, but negative trigger time is easily reproduced using debugger:

          public static void main(String[] args) throws InterruptedException {
              Thread.ofVirtual().start(() -> {
                  try {
                      // make nanoTime bigger
                      DatagramSocket datagramSocket = new DatagramSocket(null);
                      datagramSocket.bind(new InetSocketAddress("0.0.0.0", 0));
                      datagramSocket.receive(new DatagramPacket(new byte[4096], 4096)); // debug at java.lang.VirtualThread#scheduleUnpark and we will find out that trigger time of unpark task is negative which may cause java.util.concurrent.ScheduledThreadPoolExecutor.ScheduledFutureTask#getDelay overflow again to a very large number.
                  } catch (IOException e) {
                      throw new RuntimeException(e);
                  }
              });
              Thread.sleep(10000000);
          }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      setSoTimeout for DatagramSocket.

            vklang Viktor Klang
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: