fix some datakeeper bugs and rewrite Lock, add SimpleLock

This commit is contained in:
Daniella 2024-06-12 21:28:56 +02:00
parent 2b8244b7e0
commit 53e270e88f
Signed by: TudbuT
GPG key ID: B3CF345217F202D3
4 changed files with 144 additions and 161 deletions

View file

@ -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();

View file

@ -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 {
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();
}
}
public class Lock extends SimpleLock {
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));
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
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;
}
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();
}
}

View 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;
}
}

View 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();
}
}