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

The parallelism which is close to MAX_CAP,poolIndex may exceed 17 bits

XMLWordPrintable

    • x86_64
    • windows

      ADDITIONAL SYSTEM INFORMATION :
      OS:Win10
      jdk: jdk-15.0.2
      jre: jdk-15.0.2

      A DESCRIPTION OF THE PROBLEM :
      Creates a {@code ForkJoinPool} with the given parameters. If we make parallelism equal to 0x7ffe,it's less than MAX_CAP(Obviously,0x7ffe<0x7fff). When calculating the length of the array in the constructor,the main code that (int n = (parallelism > 1) ? parallelism - 1 : 1; //At this time,n=parallelism - 1,it‘s 0x7ffd(0111 1111 1111 1101).
                          n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
                          n = (n + 1) << 1;).
      The last,n+1=1000 0000 0000 0000, [(n + 1) << 1]=1 0000 0000 0000 0000,that is 17bits!!!,more than 16.We didn't realize that near the limit, doubling the capacity would take another bit。So i think the MAX_CAP shuold be 0x3fff,not to be (1<<15)-1.Only in this way can we meet the requirements of the notes“To enable this packing, we restrict maximum parallelism to (1<<15)-1 (which is far in excess of normal operating range) to allow ids, counts, and their negations (used for thresholding) to fit into 16bit subfields.”
      The constructor code is as follows:
      ********************************************************************************************************************

      static final int MAX_CAP = 0x7fff; // max #workers - 1

      public ForkJoinPool(int parallelism,
                              ForkJoinWorkerThreadFactory factory,
                              UncaughtExceptionHandler handler,
                              boolean asyncMode,
                              int corePoolSize,
                              int maximumPoolSize,
                              int minimumRunnable,
                              Predicate<? super ForkJoinPool> saturate,
                              long keepAliveTime,
                              TimeUnit unit) {
              // check, encode, pack parameters
              if (parallelism <= 0 || parallelism > MAX_CAP ||
                  maximumPoolSize < parallelism || keepAliveTime <= 0L)
                  throw new IllegalArgumentException();
              if (factory == null)
                  throw new NullPointerException();
              long ms = Math.max(unit.toMillis(keepAliveTime), TIMEOUT_SLOP);

              int corep = Math.min(Math.max(corePoolSize, parallelism), MAX_CAP);
              long c = ((((long)(-corep) << TC_SHIFT) & TC_MASK) |
                        (((long)(-parallelism) << RC_SHIFT) & RC_MASK));
              int m = parallelism | (asyncMode ? FIFO : 0);
              int maxSpares = Math.min(maximumPoolSize, MAX_CAP) - parallelism;
              int minAvail = Math.min(Math.max(minimumRunnable, 0), MAX_CAP);
              int b = ((minAvail - parallelism) & SMASK) | (maxSpares << SWIDTH);
              int n = (parallelism > 1) ? parallelism - 1 : 1; // at least 2 slots
              n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
              n = (n + 1) << 1; // power of two, including space for submission queues

              this.workerNamePrefix = "ForkJoinPool-" + nextPoolId() + "-worker-";
              this.workQueues = new WorkQueue[n];
              this.factory = factory;
              this.ueh = handler;
              this.saturate = saturate;
              this.keepAlive = ms;
              this.bounds = b;
              this.mode = m;
              this.ctl = c;
              checkPermission();
          }
      *************************************************************************************************************

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      step1:If we make parallelism equal to 0x7ffe,it's less than MAX_CAP(Obviously,0x7ffe<0x7fff).
      It's mean that we give parallelism=0111 1111 1111 1110, capacity calculation:
      int n = (parallelism > 1) ? parallelism - 1 : 1;
      step2:
      n=0111 1111 1111 1101;(n >>> 1)=0011 1111 1111 1110;
      (n |= n >>> 1)=0111 1111 1111 1111
      .........
      (n |= n >>> 16)=0111 1111 1111 1111
      step3: n+1=1000 0000 0000 0000
      step4:[(n+1)<<1]= 1 0000 0000 0000 0000


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      [(n+1)<<1]= 1000 0000 0000 0000 Maximum poolIndex is 2^15-1
      ACTUAL -
      [(n+1)<<1]= 1 0000 0000 0000 0000 that is 17bits,exceed the last 16bits of the "ctl".
      2^16-1

      ---------- BEGIN SOURCE ----------
      Because this involves the maximum parallelism, which can be up to 32767. I have no equipment condition. But this error occurs in three lines of capacity code. The example I gave fully proves max_ Cap has errors in setting value, which is only a pure mathematical problem demonstration to find errors.I hope you can confirm this problem!
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      make the MAX_CAP = 0x7ffe,That's binary 0011 1111 1111 1111

      FREQUENCY : always


            tongwan Andrew Wang
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: