diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java index 72c1c7774..f10eb3968 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -44,9 +44,6 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; import static org.cryptomator.common.Constants.MASTERKEY_FILENAME; @@ -74,8 +71,6 @@ public class Vault { private final StringBinding accessPoint; private final BooleanBinding accessPointPresent; private final BooleanProperty showingStats; - private final Lock lock = new ReentrantLock(); //FIXME: naming - private final Condition isLocked = lock.newCondition(); //FIXME: improve naming private volatile Volume volume; @@ -152,13 +147,6 @@ public class Vault { if (throwable != null) { LOG.warn("Unexpected unmount and lock of vault " + getDisplayName(), throwable); } - lock.lock(); - try { - isLocked.signal(); - } finally { - lock.unlock(); - } - }); } catch (Exception e) { destroyCryptoFileSystem(); @@ -176,20 +164,15 @@ public class Vault { volume.unmount(); } destroyCryptoFileSystem(); - lock.lock(); try { - while (state.get() != VaultState.Value.LOCKED) { - if (!isLocked.await(3000, TimeUnit.MILLISECONDS)) { - throw new VolumeException("Locking failed"); //FIXME: other exception - } + boolean locked = state.awaitState(VaultState.Value.LOCKED, 3000, TimeUnit.MILLISECONDS); + if (!locked) { + throw new VolumeException("Locking failed"); //FIXME: other exception } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new VolumeException("Lock failed."); //FIXME: other/new exception - } finally { - lock.unlock(); } - } public void reveal(Volume.Revealer vaultRevealer) throws VolumeException { diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultState.java b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultState.java index b9c3cc9b5..c3c616307 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultState.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultState.java @@ -8,7 +8,11 @@ import javax.inject.Inject; import javafx.application.Platform; import javafx.beans.value.ObservableObjectValue; import javafx.beans.value.ObservableValueBase; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; @PerVault public class VaultState extends ObservableValueBase implements ObservableObjectValue { @@ -48,6 +52,8 @@ public class VaultState extends ObservableValueBase implements } private final AtomicReference value; + private final Lock lock = new ReentrantLock(); + private final Condition valueChanged = lock.newCondition(); @Inject public VaultState(VaultState.Value initialValue) { @@ -89,7 +95,43 @@ public class VaultState extends ObservableValueBase implements } } + /** + * Waits for the specified time, until the desired state is reached. + * + * @param desiredState what state to wait for + * @param time the maximum time to wait + * @param unit the time unit of the {@code time} argument + * @return {@code false} if the waiting time detectably elapsed before reaching {@code desiredState} + * @throws InterruptedException if the current thread is interrupted + */ + public boolean awaitState(Value desiredState, long time, TimeUnit unit) throws InterruptedException { + lock.lock(); + try { + long remaining = unit.convert(time, TimeUnit.NANOSECONDS); + while (value.get() != desiredState) { + if (remaining <= 0L) { + return false; + } + remaining = valueChanged.awaitNanos(remaining); + } + return true; + } finally { + lock.unlock(); + } + } + + private void signal() { + lock.lock(); + try { + valueChanged.signalAll(); + } finally { + lock.unlock(); + } + } + + @Override protected void fireValueChangedEvent() { + signal(); if (Platform.isFxApplicationThread()) { super.fireValueChangedEvent(); } else {