/*
* Copyright 2015-2016 Cel Skeggs
*
* This file is part of the CCRE, the Common Chicken Runtime Engine.
*
* The CCRE is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The CCRE 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the CCRE. If not, see <http://www.gnu.org/licenses/>.
*/
package ccre.time;
import ccre.verifier.FlowPhase;
import ccre.verifier.ImperativePhase;
import ccre.verifier.SetupPhase;
/**
* An abstraction of time that allows multiple implementations to be used. For
* example, time can be faked during execution of JUnit tests.
*
* This abstraction is for control-based time, not human time: it is useless for
* tracking dates, for example.
*
* @author skeggsc
*/
public abstract class Time {
/**
* The number of milliseconds in a second. This is for use in code such that
* fewer magic numbers are necessary.
*/
public static final long MILLISECONDS_PER_SECOND = 1000;
/**
* The number of microseconds in a second. This is for use in code such that
* fewer magic numbers are necessary.
*/
public static final long MICROSECONDS_PER_SECOND = 1000000;
/**
* The number of nanoseconds in a second. This is for use in code such that
* fewer magic numbers are necessary.
*/
public static final long NANOSECONDS_PER_SECOND = 1000000000;
/**
* The number of microseconds in a millisecond. This is for use in code such
* that fewer magic numbers are necessary.
*/
public static final long MICROSECONDS_PER_MILLISECOND = 1000;
/**
* The number of nanoseconds in a millisecond. This is for use in code such
* that fewer magic numbers are necessary.
*/
public static final long NANOSECONDS_PER_MILLISECOND = 1000000;
/**
* The number of nanoseconds in a microsecond. This is for use in code such
* that fewer magic numbers are necessary.
*/
public static final long NANOSECONDS_PER_MICROSECOND = 1000;
/**
* The current provider for time. This allows replacement as necessary, for
* example while testing.
*/
private static Time time = new NormalTime(0);
/**
* Changes the current provider that specifies the time in the CCRE. This is
* not threadsafe! The old time provider's {@link #close()} method will be
* called once the new provider is installed.
*
* @param time the new time provider.
*/
// TODO: not thread safe - does this need to be?
@SetupPhase
public static void setTimeProvider(Time time) {
if (time == null) {
throw new NullPointerException();
}
Time old = Time.time;
Time.time = time;
// we do it afterwards so that anything new will get sent to the new
// time provider
old.close();
}
/**
* Gets the current time provider. This is a {@link NormalTime} instance by
* default.
*
* @return the Time instance.
*/
public static Time getTimeProvider() {
return time;
}
/**
* Queries the current time based on an unspecified zero point. This is not
* suitable for determining the time of day, but is suitable for tracking
* the time since an event.
*
* This delegates to {@link #nowMillis()} on the current provider.
*
* @return the current time, in milliseconds.
*/
@FlowPhase
public static long currentTimeMillis() {
return time.nowMillis();
}
/**
* Queries the current time based on an unspecified zero point. This is not
* suitable for determining the time of day, but is suitable for tracking
* the time since an event.
*
* This delegates to {@link #nowNanos()} on the current provider.
*
* @return the current time, in nanoseconds.
*/
@FlowPhase
public static long currentTimeNanos() {
return time.nowNanos();
}
/**
* Sleeps for at least the specified amount of time before returning, unless
* the thread is interrupted.
*
* The call to <code>sleep</code> may last longer than specified in a number
* of cases.
*
* This delegates to the current provider's {@link #sleepFor(long)} method.
*
* @param millis how long to sleep for.
* @throws InterruptedException if the thread is interrupted while sleeping.
*/
@ImperativePhase
public static void sleep(long millis) throws InterruptedException {
time.sleepFor(millis);
}
/**
* Waits for an object's monitor to be notified, as if
* {@link Object#wait(long)} were called.
*
* The call to <code>wait</code> may last longer than specified in a number
* of cases.
*
* This delegates to the current provider's {@link #waitOn(Object, long)}
* method.
*
* @param object the object to wait on.
* @param timeout how long to sleep for, in milliseconds.
* @throws InterruptedException if the thread is interrupted while waiting.
*/
@ImperativePhase
public static void wait(Object object, long timeout) throws InterruptedException {
time.waitOn(object, timeout);
}
/**
* Queries the current time based on an unspecified zero point. This is not
* suitable for determining the time of day, but is suitable for tracking
* the time since an event.
*
* @return the current time, in milliseconds.
*/
@FlowPhase
protected abstract long nowMillis();
/**
* Queries the current time based on an unspecified zero point. This is not
* suitable for determining the time of day, but is suitable for tracking
* the time since an event.
*
* @return the current time, in nanoseconds.
*/
@FlowPhase
protected abstract long nowNanos();
/**
* Sleeps for at least the specified amount of time before returning, unless
* the thread is interrupted.
*
* The call to <code>sleep</code> may last longer than specified in a number
* of cases.
*
* This delegates to the current provider's {@link #sleepFor(long)} method.
*
* @param millis how long to sleep for.
* @throws InterruptedException if the thread is interrupted while sleeping.
*/
@ImperativePhase
protected abstract void sleepFor(long millis) throws InterruptedException;
/**
* Waits for an object's monitor to be notified, as if
* {@link Object#wait(long)} were called.
*
* The call to <code>wait</code> may last longer than specified in a number
* of cases. It may also have spurious wake-ups, where it wakes up without
* any cause. This may occur frequently.
*
* This delegates to the current provider's {@link #waitOn(Object, long)}
* method.
*
* @param object the object to wait on.
* @param timeout how long to sleep for, in milliseconds.
* @throws InterruptedException if the thread is interrupted while waiting.
*/
@ImperativePhase
protected abstract void waitOn(Object object, long timeout) throws InterruptedException;
/**
* This provider has been replaced; transition to the new one. For example,
* one might wake up any current sleepers.
*/
@SetupPhase
protected abstract void close();
}