/*
 * Copyright 2016 higherfrequencytrading.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.openhft.chronicle.core.util;

import java.util.concurrent.locks.LockSupport;

/**
 * A timer for timeouts which is resilient to pauses in the JVM, tickTime can only increase if the JVM hasn't been paused.
 * <p>
 * For this to work, currentTimeMillis (or one of the methods that calls it) must be called more frequently than
 * every millisecond; the EventLoop implementations in chronicle-threads do this.
 * </p>
 */
public enum Time {
    ;

    static volatile long lastTime = System.currentTimeMillis();
    static volatile long tickTime = 0;

    public static long currentTimeMillis() {
        long now = System.currentTimeMillis();
        if (now == lastTime)
            return now;
        tickTime++;
        lastTime = now;
        return lastTime;
    }

    public static long tickTime() {
        currentTimeMillis();
        return tickTime;
    }

    public static void parkNanos(long nanos) {
        long millis = nanos / 1000000;
        if (millis > 0) {
            long start = System.currentTimeMillis();
            long startTT = tickTime;
            LockSupport.parkNanos(nanos);
            long end = System.currentTimeMillis();
            long endTT = Math.min(end - start, millis) + startTT;
            if (endTT > tickTime)
                tickTime = endTT;
        } else {
            currentTimeMillis();
            LockSupport.parkNanos(nanos);
            currentTimeMillis();
        }
    }

    /**
     * Sleeps in such a way that any long pause of the JVM, e.g. GC, will make it wait much longer to prevent timeouts being busted.
     *
     * @param sleepMS to pause for at least.
     * @throws IllegalArgumentException
     */
    public static void sleep(long sleepMS) {
        long sleepNS = sleepMS * 1_000_000;
        long pauseTimeNS = sleepNS / 16 + 1;
        int count = (int) (sleepNS / pauseTimeNS);
        for (int i = 0; i < count; i++)
            LockSupport.parkNanos(pauseTimeNS);
    }
}

@@ -646,16 +646,54 @@
 .util;%0A%0A
+import java.util.concurrent.TimeUnit;%0A
 import j
@@ -2371,107 +2371,35 @@
 ong 
-sleepMS) %7B%0A        long sleepNS = sleepMS * 1_000_000;%0A        long pauseTimeNS = sleepNS / 16 + 1;
+count, TimeUnit timeUnit) %7B
 %0A   
@@ -2407,21 +2407,22 @@
     int 
-count
+millis
  = (int)
@@ -2426,72 +2426,131 @@
 nt) 
-(sleepNS / pauseTimeNS);%0A        for (int i = 0; i %3C count; i++)
+timeUnit.convert(count, TimeUnit.MILLISECONDS);%0A        for (int i = 0; i %3C millis; i++) %7B%0A            currentTimeMillis();
 %0A   
@@ -2584,21 +2584,29 @@
 nos(
-pauseTimeNS);
+1_000_000);%0A        %7D
 %0A   

Add a pause tolerant sleep.