fix some datakeeper bugs and rewrite Lock, add SimpleLock
This commit is contained in:
parent
2b8244b7e0
commit
53e270e88f
|
@ -2,6 +2,7 @@ package de.tudbut.security;
|
|||
|
||||
import de.tudbut.obj.DoubleTypedObject;
|
||||
import de.tudbut.tools.Lock;
|
||||
import de.tudbut.tools.SimpleLock;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
@ -19,7 +20,7 @@ public class DataKeeper<T> {
|
|||
private Supplier<T> dataInsertion;
|
||||
private final Strictness strictness;
|
||||
private final Lock lock = new Lock(true);
|
||||
private final Queue<DoubleTypedObject<Consumer<Accessor<T>>, Lock>> nextFunctionToRun = new LinkedList<>();
|
||||
private final Queue<DoubleTypedObject<Consumer<Accessor<T>>, SimpleLock>> nextFunctionToRun = new LinkedList<>();
|
||||
private final Thread keeper = new Thread(this::keep, "DataKeeper"); { keeper.start(); }
|
||||
|
||||
static { initSecurity(); }
|
||||
|
@ -53,10 +54,10 @@ public class DataKeeper<T> {
|
|||
else
|
||||
return;
|
||||
}
|
||||
Lock waitLock = new Lock(true);
|
||||
SimpleLock waitLock = new SimpleLock(true);
|
||||
nextFunctionToRun.add(new DoubleTypedObject<>(accessor, waitLock));
|
||||
lock.unlock();
|
||||
waitLock.waitHere(500);
|
||||
waitLock.waitHere();
|
||||
}
|
||||
|
||||
public void forget() {
|
||||
|
@ -64,7 +65,7 @@ public class DataKeeper<T> {
|
|||
}
|
||||
|
||||
public DataKeeper<T> forgetIn(int ms) {
|
||||
if(forget.timeLeft() > ms)
|
||||
if(forget.timeLeft() < ms)
|
||||
return this;
|
||||
forget.lock(ms);
|
||||
return this;
|
||||
|
@ -81,14 +82,16 @@ public class DataKeeper<T> {
|
|||
lock.waitHere();
|
||||
lock.lock(500);
|
||||
|
||||
DoubleTypedObject<Consumer<Accessor<T>>, Lock> itm = nextFunctionToRun.poll();
|
||||
DoubleTypedObject<Consumer<Accessor<T>>, SimpleLock> itm = nextFunctionToRun.poll();
|
||||
if(itm == null)
|
||||
continue;
|
||||
Consumer<Accessor<T>> toRun = itm.o;
|
||||
Lock lock = itm.t;
|
||||
SimpleLock lock = itm.t;
|
||||
// second layer of protection, crashes this time.
|
||||
if(!permissionManager.checkLambda(strictness, toRun))
|
||||
if(!permissionManager.checkLambda(strictness, toRun)) {
|
||||
lock.lock(); // never return
|
||||
permissionManager.crash(strictness);
|
||||
}
|
||||
|
||||
toRun.accept(new Accessor<>(permissionManager, strictness, data));
|
||||
lock.unlock();
|
||||
|
|
|
@ -1,55 +1,17 @@
|
|||
package de.tudbut.tools;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Helper for synchronization and timing
|
||||
*/
|
||||
public class Lock {
|
||||
public class Lock extends SimpleLock {
|
||||
|
||||
private final Locker locker = new Locker();
|
||||
private boolean locked = false;
|
||||
private int t = 0;
|
||||
private long ts = 0;
|
||||
private final AtomicInteger waiting = new AtomicInteger();
|
||||
private volatile boolean[] waiterLocker = null;
|
||||
|
||||
/**
|
||||
* Object to handle thread locking
|
||||
*/
|
||||
private static class Locker {
|
||||
|
||||
/**
|
||||
* Make the thread wait until {@link Locker#unlock()} is called
|
||||
* @throws InterruptedException Inherited from {@link Object#wait}
|
||||
*/
|
||||
public synchronized void lockHere() throws InterruptedException {
|
||||
wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the thread wait until {@link Locker#unlock()} is called or the timeout runs out
|
||||
* @throws InterruptedException Inherited from {@link Object#wait}
|
||||
* @param timeout Maximal wait time
|
||||
*/
|
||||
public synchronized void lockHere(long timeout) throws InterruptedException {
|
||||
wait(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop locking
|
||||
*/
|
||||
public synchronized void unlock() {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
private long startTime = 0, lockTime = 0;
|
||||
|
||||
/**
|
||||
* Creates a Lock without default state
|
||||
*/
|
||||
public Lock() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,95 +19,76 @@ public class Lock {
|
|||
* @param locked Default state
|
||||
*/
|
||||
public Lock(boolean locked) {
|
||||
this.locked = locked;
|
||||
super(locked);
|
||||
}
|
||||
|
||||
public synchronized long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public synchronized long timeLocked() {
|
||||
return startTime != 0 ? System.currentTimeMillis() - startTime : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The time left (or MAX_VALUE)
|
||||
*/
|
||||
public synchronized long timeLeft() {
|
||||
if(lockTime == 0)
|
||||
return Long.MAX_VALUE;
|
||||
return waitTime();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The time left
|
||||
*/
|
||||
public long timeLeft() {
|
||||
updateLocked();
|
||||
return locked ? (ts + t) - new Date().getTime() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate timeout
|
||||
* @param timeout Timeout to override time
|
||||
* @return Time left
|
||||
*/
|
||||
protected int checkTime(int timeout) {
|
||||
return locked ? checkNegative(Math.min((int) (t - (new Date().getTime() - ts ) ), timeout <= 0 ? Integer.MAX_VALUE : timeout), timeout) : timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns alt if i is negative, otherwise i
|
||||
* @param i The integer to check
|
||||
* @param alt The alternative for if its negative
|
||||
* @return The checked or overridden value
|
||||
*/
|
||||
protected int checkNegative(int i, int alt) {
|
||||
if(i <= 0)
|
||||
return alt;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is still locked?
|
||||
*/
|
||||
protected void updateLocked() {
|
||||
if(new Date().getTime() - ts >= t && ts != 0)
|
||||
locked = false;
|
||||
public synchronized long waitTime() {
|
||||
return Math.max(lockTime - timeLocked(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until unlocked, either by a timer or manually
|
||||
*/
|
||||
public void waitHere() {
|
||||
updateLocked();
|
||||
if(locked) {
|
||||
try {
|
||||
locker.lockHere(checkTime(0));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
updateLocked();
|
||||
public synchronized void waitHere() {
|
||||
super.waitHere(waitTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until unlocked, either by a timer, manually, or when it waited for timeout
|
||||
* @param timeout Timeout
|
||||
*/
|
||||
public void waitHere(int timeout) {
|
||||
updateLocked();
|
||||
if(locked) {
|
||||
try {
|
||||
locker.lockHere(checkTime(timeout));
|
||||
public synchronized void waitHere(int timeout) {
|
||||
if(timeout == 0 || !super.isLocked())
|
||||
return;
|
||||
|
||||
if(lockTime == 0) {
|
||||
super.waitHere(timeout);
|
||||
} else {
|
||||
long timeLeft = lockTime - (System.currentTimeMillis() - startTime);
|
||||
if (timeLeft == 0) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
super.waitHere(Math.min(timeLeft, timeout));
|
||||
}
|
||||
}
|
||||
updateLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock manually
|
||||
*/
|
||||
public synchronized void unlock() {
|
||||
locker.unlock();
|
||||
locked = false;
|
||||
super.unlock();
|
||||
startTime = 0;
|
||||
lockTime = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock until manually unlocked
|
||||
*/
|
||||
public synchronized void lock() {
|
||||
t = 0;
|
||||
ts = 0;
|
||||
locked = true;
|
||||
startTime = System.currentTimeMillis();
|
||||
lockTime = 0;
|
||||
super.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,64 +96,24 @@ public class Lock {
|
|||
* @param time The time to lock for
|
||||
*/
|
||||
public synchronized void lock(int time) {
|
||||
if(time < 0)
|
||||
time = 0;
|
||||
locked = true;
|
||||
t = time;
|
||||
ts = new Date().getTime();
|
||||
if(time == 0)
|
||||
return;
|
||||
|
||||
startTime = System.currentTimeMillis();
|
||||
lockTime = time;
|
||||
super.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return If the lock is locked
|
||||
*/
|
||||
public synchronized boolean isLocked() {
|
||||
updateLocked();
|
||||
return locked;
|
||||
update();
|
||||
return super.isLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize multiple threads on this lock
|
||||
* @param amount The amount of threads to synchronize
|
||||
*/
|
||||
public void synchronize(int amount) {
|
||||
this.locked = true;
|
||||
if(waiterLocker == null)
|
||||
waiterLocker = new boolean[amount];
|
||||
int i = waiting.get();
|
||||
waiting.getAndIncrement();
|
||||
locker.unlock();
|
||||
while (amount > waiting.get()) {
|
||||
try {
|
||||
locker.lockHere();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
locker.unlock();
|
||||
boolean b;
|
||||
waiterLocker[i] = true;
|
||||
b = true;
|
||||
try {
|
||||
while (b) {
|
||||
b = false;
|
||||
for (int j = 0 ; j < waiterLocker.length ; j++) {
|
||||
if (!waiterLocker[j]) {
|
||||
b = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) { }
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
waiting.getAndDecrement();
|
||||
waiterLocker = null;
|
||||
this.locked = false;
|
||||
private synchronized void update() {
|
||||
if(timeLeft() == 0)
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
|
38
src/main/java/de/tudbut/tools/SimpleLock.java
Normal file
38
src/main/java/de/tudbut/tools/SimpleLock.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package de.tudbut.tools;
|
||||
|
||||
public class SimpleLock {
|
||||
private boolean locked = false;
|
||||
|
||||
public SimpleLock() { }
|
||||
|
||||
public SimpleLock(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
public synchronized void lock() {
|
||||
locked = true;
|
||||
}
|
||||
|
||||
public void waitHere() {
|
||||
waitHere(0);
|
||||
}
|
||||
|
||||
public synchronized void waitHere(long timeout) {
|
||||
if(locked) {
|
||||
try {
|
||||
wait(timeout);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void unlock() {
|
||||
locked = false;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public synchronized boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
}
|
39
src/test/java/LockTest.java
Normal file
39
src/test/java/LockTest.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
import de.tudbut.tools.Lock;
|
||||
|
||||
public class LockTest {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
System.out.println("Timer test");
|
||||
Lock lock = new Lock();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
long start = System.currentTimeMillis();
|
||||
lock.lock(500);
|
||||
Thread.sleep(250);
|
||||
System.out.println("Time locked/left after 250ms: " + lock.timeLocked() + "/" + lock.timeLeft());
|
||||
lock.waitHere();
|
||||
System.out.println("Took " + (System.currentTimeMillis() - start) + ". (Should be 500)");
|
||||
}
|
||||
System.out.println("Timer test with shortcut");
|
||||
for (int i = 0; i < 5; i++) {
|
||||
long start = System.currentTimeMillis();
|
||||
lock.lock(5000);
|
||||
Thread.sleep(250);
|
||||
System.out.println("Time locked/left after 250ms: " + lock.timeLocked() + "/" + lock.timeLeft());
|
||||
lock.waitHere(500);
|
||||
System.out.println("Took " + (System.currentTimeMillis() - start) + ". (Should be 750)");
|
||||
}
|
||||
System.out.println("Sync test");
|
||||
lock.lock();
|
||||
System.out.println("Thread 2 should be up first but start after 1. Lock has timeout: " + lock.timeLeft());
|
||||
new Thread(() -> {
|
||||
System.out.println("Thread 2 up");
|
||||
lock.waitHere();
|
||||
System.out.println("Thread 2 started");
|
||||
}).start();
|
||||
Thread.sleep(10);
|
||||
new Thread(() -> {
|
||||
System.out.println("Thread 1 up");
|
||||
System.out.println("Thread 1 started");
|
||||
lock.unlock();
|
||||
}).start();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue