/*
* Copyright (c) 2012-2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.services.util;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A reference class for implementing sleep/wakeup semantics based on Java condition variables.
* Currently it's being used by Upgrade/Property/SecretsManager of syssvc but may as well be used elsewhere.
*/
public class Waiter {
// just to differentiate the default and wakeup value
private long t = -1;
private Lock lock = new ReentrantLock();
Condition wakeup = lock.newCondition();
private static final Logger logger = LoggerFactory.getLogger(Waiter.class);
/**
* Sleep for a specific amount of time, or until the wakeup method is called, whichever comes first
*
* @param milliSeconds the amount of time to sleep, in milliseconds.
*/
public void sleep(long milliSeconds) {
lock.lock();
try {
// if someone tried to wake it up before it goes to sleep
// just reset t and restart the loop
if (t != 0) {
t = System.currentTimeMillis() + milliSeconds;
while (true) {
final long dt = t - System.currentTimeMillis();
if (dt <= 0) {
break;
} else {
wakeup.await(dt, TimeUnit.MILLISECONDS);
}
}
}
// reset t since it may have been set to 0 while sleeping
t = System.currentTimeMillis();
} catch (InterruptedException e) {
logger.error(e.getMessage(),e);
} finally {
lock.unlock();
}
}
/**
* Wakeup a sleeping thread
* If the thread is not sleeping, it will skip the sleep immediately followed.
*/
public void wakeup() {
lock.lock();
try {
t = 0;
wakeup.signal();
} finally {
lock.unlock();
}
}
}