blob: 8089de321cce6be74fdb396aab208d4a86b005ee [file] [log] [blame]
/*
* Copyright (c) 2002-2016, the original author or authors.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* https://opensource.org/licenses/BSD-3-Clause
*/
package jdk.internal.org.jline.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Manages the JLine shutdown-hook thread and tasks to execute on shutdown.
*
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.7
*/
public final class ShutdownHooks
{
private static final List<Task> tasks = new ArrayList<>();
private static Thread hook;
public static synchronized <T extends Task> T add(final T task) {
Objects.requireNonNull(task);
// Install the hook thread if needed
if (hook == null) {
hook = addHook(new Thread("JLine Shutdown Hook")
{
@Override
public void run() {
runTasks();
}
});
}
// Track the task
Log.debug("Adding shutdown-hook task: ", task);
tasks.add(task);
return task;
}
private static synchronized void runTasks() {
Log.debug("Running all shutdown-hook tasks");
// Iterate through copy of tasks list
for (Task task : tasks.toArray(new Task[tasks.size()])) {
Log.debug("Running task: ", task);
try {
task.run();
}
catch (Throwable e) {
Log.warn("Task failed", e);
}
}
tasks.clear();
}
private static Thread addHook(final Thread thread) {
Log.debug("Registering shutdown-hook: ", thread);
Runtime.getRuntime().addShutdownHook(thread);
return thread;
}
public static synchronized void remove(final Task task) {
Objects.requireNonNull(task);
// ignore if hook never installed
if (hook == null) {
return;
}
// Drop the task
tasks.remove(task);
// If there are no more tasks, then remove the hook thread
if (tasks.isEmpty()) {
removeHook(hook);
hook = null;
}
}
private static void removeHook(final Thread thread) {
Log.debug("Removing shutdown-hook: ", thread);
try {
Runtime.getRuntime().removeShutdownHook(thread);
}
catch (IllegalStateException e) {
// The VM is shutting down, not a big deal; ignore
}
}
/**
* Essentially a {@link Runnable} which allows running to throw an exception.
*/
public interface Task
{
void run() throws Exception;
}
}