gt:         long cnt = COUNT.decrementAndGet();
context: /*
   * Copyright (c) 2000, 2019, 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
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * 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.
   */
  
  package java.nio;
  
  import jdk.internal.access.JavaLangRefAccess;
  import jdk.internal.access.JavaNioAccess;
  import jdk.internal.access.SharedSecrets;
  import jdk.internal.misc.Unsafe;
  import jdk.internal.misc.VM;
  
  import java.util.concurrent.atomic.AtomicLong;
  
  /**
   * Access to bits, native and otherwise.
   */
  
  class Bits {                            // package-private
  
      private Bits() { }
  
  
      // -- Swapping --
  
      static short swap(short x) {
          return Short.reverseBytes(x);
      }
  
      static char swap(char x) {
          return Character.reverseBytes(x);
      }
  
      static int swap(int x) {
          return Integer.reverseBytes(x);
      }
  
      static long swap(long x) {
          return Long.reverseBytes(x);
      }
  
  
      // -- Unsafe access --
  
      private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  
      // -- Processor and memory-system properties --
  
      private static int PAGE_SIZE = -1;
  
      static int pageSize() {
          if (PAGE_SIZE == -1)
              PAGE_SIZE = UNSAFE.pageSize();
          return PAGE_SIZE;
      }
  
      static int pageCount(long size) {
          return (int)(size + (long)pageSize() - 1L) / pageSize();
      }
  
      private static boolean UNALIGNED = UNSAFE.unalignedAccess();
  
      static boolean unaligned() {
          return UNALIGNED;
      }
  
  
      // -- Direct memory management --
  
      // A user-settable upper limit on the maximum amount of allocatable
      // direct buffer memory.  This value may be changed during VM
      // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
      private static volatile long MAX_MEMORY = VM.maxDirectMemory();
      private static final AtomicLong RESERVED_MEMORY = new AtomicLong();
      private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();
      private static final AtomicLong COUNT = new AtomicLong();
      private static volatile boolean MEMORY_LIMIT_SET;
  
      // max. number of sleeps during try-reserving with exponentially
      // increasing delay before throwing OutOfMemoryError:
      // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
      // which means that OOME will be thrown after 0.5 s of trying
      private static final int MAX_SLEEPS = 9;
  
      // These methods should be called whenever direct memory is allocated or
      // freed.  They allow the user to control the amount of direct memory
      // which a process may access.  All sizes are specified in bytes.
      static void reserveMemory(long size, int cap) {
  
          if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {
              MAX_MEMORY = VM.maxDirectMemory();
              MEMORY_LIMIT_SET = true;
          }
  
          // optimist!
          if (tryReserveMemory(size, cap)) {
              return;
          }
  
          final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
          boolean interrupted = false;
          try {
  
              // Retry allocation until success or there are no more
              // references (including Cleaners that might free direct
              // buffer memory) to process and allocation still fails.
              boolean refprocActive;
              do {
                  try {
                      refprocActive = jlra.waitForReferenceProcessing();
                  } catch (InterruptedException e) {
                      // Defer interrupts and keep trying.
                      interrupted = true;
                      refprocActive = true;
                  }
                  if (tryReserveMemory(size, cap)) {
                      return;
                  }
              } while (refprocActive);
  
              // trigger VM's Reference processing
              System.gc();
  
              // A retry loop with exponential back-off delays.
              // Sometimes it would suffice to give up once reference
              // processing is complete.  But if there are many threads
              // competing for memory, this gives more opportunities for
              // any given thread to make progress.  In particular, this
              // seems to be enough for a stress test like
              // DirectBufferAllocTest to (usually) succeed, while
              // without it that test likely fails.  Since failure here
              // ends in OOME, there's no need to hurry.
              long sleepTime = 1;
              int sleeps = 0;
              while (true) {
                  if (tryReserveMemory(size, cap)) {
                      return;
                  }
                  if (sleeps >= MAX_SLEEPS) {
                      break;
                  }
                  try {
                      if (!jlra.waitForReferenceProcessing()) {
                          Thread.sleep(sleepTime);
                          sleepTime <<= 1;
                          sleeps++;
                      }
                  } catch (InterruptedException e) {
                      interrupted = true;
                  }
              }
  
              // no luck
              throw new OutOfMemoryError
                  ("Cannot reserve "
                   + size + " bytes of direct buffer memory (allocated: "
                   + RESERVED_MEMORY.get() + ", limit: " + MAX_MEMORY +")");
  
          } finally {
              if (interrupted) {
                  // don't swallow interrupts
                  Thread.currentThread().interrupt();
              }
          }
      }
  
      private static boolean tryReserveMemory(long size, int cap) {
  
          // -XX:MaxDirectMemorySize limits the total capacity rather than the
          // actual memory usage, which will differ when buffers are page
          // aligned.
          long totalCap;
          while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {
              if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {
                  RESERVED_MEMORY.addAndGet(size);
                  COUNT.incrementAndGet();
                  return true;
              }
          }
  
          return false;
      }
  
  
      static void unreserveMemory(long size, int cap) {
  