package com.laytonsmith.PureUtilities; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import sun.misc.Signal; /** * Adds a generic way to handle signals, if the VM was started with the -Xrs option. */ public class SignalHandler { private static final Map<SignalType, SignalCallback> handlers = new HashMap<>(); private static final Set<SignalType> setup = new HashSet<>(); /** * Registers a new signal handler, and returns the last one * @param type The signal type to register for * @param handler The handler, which will be called when the signal occurs. * @return The last handler that was registered for this signal, or null if * no previous handler was registered. * @throws IllegalArgumentException If the signal cannot be registered, for instance, * if the signal is already registered by the VM or the OS, it won't be possible to * register for this signal. Also, if the signal type itself is uncatchable, this * is also thrown. */ public static SignalCallback addHandler(final SignalType type, SignalCallback handler){ if(!type.isCatchable()){ throw new IllegalArgumentException(type.getSignalName() + " cannot be caught, and therefore cannot be registered."); } SignalCallback last = null; if(handlers.containsKey(type)){ last = handlers.get(type); } handlers.put(type, handler); if(!setup.contains(type)){ sun.misc.Signal.handle(new sun.misc.Signal(type.getSignalName()), new sun.misc.SignalHandler() { @Override public void handle(Signal sig) { boolean handled = handlers.get(type).handle(type); if(!handled){ if(type.getDefaultAction() == SignalType.DefaultAction.IGNORE){ sun.misc.SignalHandler.SIG_IGN.handle(sig); } else { sun.misc.SignalHandler.SIG_DFL.handle(sig); } } } }); setup.add(type); } return last; } /** * Raises the specified signal in the process. * @param type */ public static void raise(SignalType type){ sun.misc.Signal.raise(new sun.misc.Signal(type.getSignalName())); } public static interface SignalCallback { /** * When the signal this was registered with occurs, this method is called. * @param type The type that activated this. * @return If the signal should be ignored, return true. If false is returned, * the default action will occur. */ boolean handle(SignalType type); } }