Explorar o código

Some shutdown hook refactorings for #980

Sebastian Stenzel %!s(int64=5) %!d(string=hai) anos
pai
achega
ac536ba125

+ 2 - 2
main/commons/src/main/java/org/cryptomator/common/CommonsModule.java

@@ -67,7 +67,7 @@ public abstract class CommonsModule {
 
 	@Provides
 	@Singleton
-	static ScheduledExecutorService provideScheduledExecutorService(@Named("shutdownTaskScheduler") Consumer<Runnable> shutdownTaskScheduler) {
+	static ScheduledExecutorService provideScheduledExecutorService(ShutdownHook shutdownHook) {
 		final AtomicInteger threadNumber = new AtomicInteger(1);
 		ScheduledExecutorService executorService = Executors.newScheduledThreadPool(NUM_SCHEDULER_THREADS, r -> {
 			Thread t = new Thread(r);
@@ -75,7 +75,7 @@ public abstract class CommonsModule {
 			t.setDaemon(true);
 			return t;
 		});
-		shutdownTaskScheduler.accept(executorService::shutdown);
+		shutdownHook.runOnShutdown(executorService::shutdown);
 		return executorService;
 	}
 

+ 20 - 18
main/launcher/src/main/java/org/cryptomator/launcher/CleanShutdownPerformer.java

@@ -3,46 +3,48 @@
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the accompanying LICENSE file.
  *******************************************************************************/
-package org.cryptomator.launcher;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
+package org.cryptomator.common;
 
+import com.google.common.util.concurrent.Runnables;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 
 @Singleton
-class CleanShutdownPerformer extends Thread {
+public class ShutdownHook extends Thread {
 
-	private static final Logger LOG = LoggerFactory.getLogger(CleanShutdownPerformer.class);
-	private final ConcurrentMap<Runnable, Boolean> tasks = new ConcurrentHashMap<>();
+	private static final Logger LOG = LoggerFactory.getLogger(ShutdownHook.class);
+	private static final Runnable POISON = Runnables.doNothing();
+	
+	private final Queue<Runnable> tasks = new ConcurrentLinkedQueue<>();
 
 	@Inject
-	CleanShutdownPerformer() {
+	ShutdownHook() {
 		super(null, null, "ShutdownTasks", 0);
+		Runtime.getRuntime().addShutdownHook(this);
+		LOG.debug("Registered shutdown hook.");
 	}
 
 	@Override
 	public void run() {
 		LOG.debug("Running graceful shutdown tasks...");
-		tasks.keySet().forEach(r -> {
+		tasks.add(POISON);
+		Runnable task;
+		while ((task = tasks.remove()) != POISON) {
 			try {
-				r.run();
+				task.run();
 			} catch (RuntimeException e) {
 				LOG.error("Exception while shutting down.", e);
 			}
-		});
-		tasks.clear();
+		}
 	}
 
-	void scheduleShutdownTask(Runnable task) {
-		tasks.put(task, Boolean.TRUE);
-	}
-
-	void registerShutdownHook() {
-		Runtime.getRuntime().addShutdownHook(this);
+	public void runOnShutdown(Runnable task) {
+		tasks.add(task);
 	}
+	
 }

+ 1 - 4
main/launcher/src/main/java/org/cryptomator/launcher/Cryptomator.java

@@ -32,17 +32,15 @@ public class Cryptomator {
 	private final IpcFactory ipcFactory;
 	private final Optional<String> applicationVersion;
 	private final CountDownLatch shutdownLatch;
-	private final CleanShutdownPerformer shutdownPerformer;
 	private final UiLauncher uiLauncher;
 
 	@Inject
-	Cryptomator(LoggerConfiguration logConfig, DebugMode debugMode, IpcFactory ipcFactory, @Named("applicationVersion") Optional<String> applicationVersion, @Named("shutdownLatch") CountDownLatch shutdownLatch, CleanShutdownPerformer shutdownPerformer, UiLauncher uiLauncher) {
+	Cryptomator(LoggerConfiguration logConfig, DebugMode debugMode, IpcFactory ipcFactory, @Named("applicationVersion") Optional<String> applicationVersion, @Named("shutdownLatch") CountDownLatch shutdownLatch, UiLauncher uiLauncher) {
 		this.logConfig = logConfig;
 		this.debugMode = debugMode;
 		this.ipcFactory = ipcFactory;
 		this.applicationVersion = applicationVersion;
 		this.shutdownLatch = shutdownLatch;
-		this.shutdownPerformer = shutdownPerformer;
 		this.uiLauncher = uiLauncher;
 	}
 
@@ -90,7 +88,6 @@ public class Cryptomator {
 	 */
 	private int runGuiApplication() {
 		try {
-			shutdownPerformer.registerShutdownHook();
 			uiLauncher.launch();
 			shutdownLatch.await();
 			LOG.info("UI shut down");

+ 1 - 9
main/launcher/src/main/java/org/cryptomator/launcher/CryptomatorModule.java

@@ -7,18 +7,10 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
-import java.util.function.Consumer;
 
 @Module
 class CryptomatorModule {
-
-	@Provides
-	@Singleton
-	@Named("shutdownTaskScheduler")
-	Consumer<Runnable> provideShutdownTaskScheduler(CleanShutdownPerformer shutdownPerformer) {
-		return shutdownPerformer::scheduleShutdownTask;
-	}
-
+	
 	@Provides
 	@Singleton
 	@Named("shutdownLatch")

+ 18 - 3
main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java

@@ -3,9 +3,11 @@ package org.cryptomator.ui.traymenu;
 import javafx.application.Platform;
 import javafx.beans.Observable;
 import javafx.collections.ObservableList;
+import org.cryptomator.common.ShutdownHook;
 import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.common.vaults.VaultState;
+import org.cryptomator.common.vaults.Volume;
 import org.cryptomator.ui.fxapp.FxApplication;
 import org.cryptomator.ui.launcher.FxApplicationStarter;
 import org.cryptomator.ui.preferences.SelectedPreferencesTab;
@@ -38,17 +40,17 @@ class TrayMenuController {
 	private final ResourceBundle resourceBundle;
 	private final FxApplicationStarter fxApplicationStarter;
 	private final CountDownLatch shutdownLatch;
-	private final Settings settings;
+	private final ShutdownHook shutdownHook;
 	private final ObservableList<Vault> vaults;
 	private final PopupMenu menu;
 	private final AtomicBoolean allowSuddenTermination;
 
 	@Inject
-	TrayMenuController(ResourceBundle resourceBundle, FxApplicationStarter fxApplicationStarter, @Named("shutdownLatch") CountDownLatch shutdownLatch, Settings settings, ObservableList<Vault> vaults) {
+	TrayMenuController(ResourceBundle resourceBundle, FxApplicationStarter fxApplicationStarter, @Named("shutdownLatch") CountDownLatch shutdownLatch, ShutdownHook shutdownHook, ObservableList<Vault> vaults) {
 		this.resourceBundle = resourceBundle;
 		this.fxApplicationStarter = fxApplicationStarter;
 		this.shutdownLatch = shutdownLatch;
-		this.settings = settings;
+		this.shutdownHook = shutdownHook;
 		this.vaults = vaults;
 		this.menu = new PopupMenu();
 		this.allowSuddenTermination = new AtomicBoolean(true);
@@ -72,6 +74,7 @@ class TrayMenuController {
 		if (Desktop.getDesktop().isSupported(Desktop.Action.APP_QUIT_HANDLER)) {
 			Desktop.getDesktop().setQuitHandler(this::handleQuitRequest);
 		}
+		shutdownHook.runOnShutdown(this::forceUnmountRemainingVaults);
 
 		// allow sudden termination
 		if (Desktop.getDesktop().isSupported(Desktop.Action.APP_SUDDEN_TERMINATION)) {
@@ -175,4 +178,16 @@ class TrayMenuController {
 			}
 		});
 	}
+
+	private void forceUnmountRemainingVaults() {
+		for (Vault vault : vaults) {
+			if (vault.isUnlocked()) {
+				try {
+					vault.lock(true);
+				} catch (Volume.VolumeException e) {
+					LOG.error("Failed to unmount vault " + vault.getPath(), e);
+				}
+			}
+		}
+	}
 }