diff options
author | John Ross | 2012-11-05 21:18:08 +0000 |
---|---|---|
committer | John Ross | 2012-11-05 21:36:54 +0000 |
commit | ec21eb4e37d764934e84fac5ee09179f3d66b12b (patch) | |
tree | 8418b476b1f2818098d5ff6131aedf3cd34c1167 /bundles/org.eclipse.equinox.console | |
parent | c343180660d3ee829d18ed3997e50c5f71ce85e4 (diff) | |
download | rt.equinox.bundles-ec21eb4e37d764934e84fac5ee09179f3d66b12b.tar.gz rt.equinox.bundles-ec21eb4e37d764934e84fac5ee09179f3d66b12b.tar.xz rt.equinox.bundles-ec21eb4e37d764934e84fac5ee09179f3d66b12b.zip |
Bug 348993: Allow to stop a thread from console (e.g. main thread that is caught in an endless loop)v20121105-213654I20121106-0800
The existing threads command was updated to support additional syntax. The full syntax is now
(t | threads) [stop <thread> [<throwable>]]
where <thread> is the thread name, and <throwable> is the fully qualified class name of something extending
java.lang.Throwable and visible to the console bundle's class loader. If <throwable> is unspecified, the default is
java.lang.IllegalStateException. The <throwable> will be created with a translatable message indicating the thread was
stopped by the OSGi Console, if a constructor accepting a String as the sole parameter exists. Otherwise, the default
constructor is used. The <throwable> is initialized with the target thread's stack trace and a cause of
java.lang.RuntimeException which will also contain the translatable message. The cause will contain the stack trace of
the current thread.
Diffstat (limited to 'bundles/org.eclipse.equinox.console')
3 files changed, 88 insertions, 3 deletions
diff --git a/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMessages.properties b/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMessages.properties index ad516ea0f..cae002d74 100755 --- a/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMessages.properties +++ b/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMessages.properties @@ -100,3 +100,6 @@ CONSOLE_DISABLED_BUNDLE_REASON=Reason(s):\t{0} (policy={1}) CONSOLE_STOP_MESSAGE=Really want to stop Equinox? (y/n; default=y) CONSOLE_STOP_CONFIRMATION_YES=y CONSOLE_STOP_ERROR_READ_CONFIRMATION=Error while reading confirmation +THREADS_THREAD_DOES_NOT_EXIST=Thread does not exist: {0} +THREADS_THREAD_STOPPED_BY_CONSOLE=Thread "{0}" stopped by the OSGi Console. +THREADS_UNRECOGNIZED_ACTION=Unrecognized action. Supported actions are {stop}. diff --git a/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMsg.java b/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMsg.java index eee834040..4d09386c4 100755 --- a/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMsg.java +++ b/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMsg.java @@ -107,6 +107,10 @@ public class ConsoleMsg extends NLS { public static String STARTLEVEL_INITIAL_BUNDLE_STARTLEVEL; public static String STARTLEVEL_POSITIVE_INTEGER; + public static String THREADS_THREAD_DOES_NOT_EXIST; + public static String THREADS_THREAD_STOPPED_BY_CONSOLE; + public static String THREADS_UNRECOGNIZED_ACTION; + public static final String CONSOLE_HELP_EXIT_COMMAND_DESCRIPTION = "exit immediately (System.exit)"; public static final String CONSOLE_HELP_LAUNCH_COMMAND_DESCRIPTION = "start the OSGi Framework"; public static final String CONSOLE_HELP_SHUTDOWN_COMMAND_DESCRIPTION = "shutdown the OSGi Framework"; @@ -151,6 +155,11 @@ public class ConsoleMsg extends NLS { public static final String CONSOLE_HELP_SETPROP_COMMAND_ARGUMENTS_DESCRIPTION = "list of properties with values to be set; the format is <key>=<value> and the pairs are separated with space if more than one"; public static final String CONSOLE_HELP_SS_COMMAND_DESCRIPTION = "display installed bundles (short status)"; public static final String CONSOLE_THREADS_COMMAND_DESCRIPTION = "display threads and thread groups"; + public static final String CONSOLE_THREADS_COMMAND_ACTION_DESCRIPTION = "perform the specified action on the named thread; supported actions are {stop}"; + public static final String CONSOLE_THREADS_COMMAND_ACTION_THROWABLE_DESCRIPTION = "perform the specified action on the named thread using the provided throwable; supported actions are {stop}"; + public static final String CONSOLE_THREADS_COMMAND_ARG_ACTION_DESCRIPTION = "the action to perform"; + public static final String CONSOLE_THREADS_COMMAND_ARG_THREAD_DESCRIPTION = "the thread on which to perform the action"; + public static final String CONSOLE_THREADS_COMMAND_ARG_THROWABLE_DESCRIPTION = "the class of the throwable to be used in conjunction with the action (default = java.lang.IllegalStateException)"; public static final String CONSOLE_HELP_SL_COMMAND_DESCRIPTION = "display the start level for the specified bundle, or for the framework if no bundle specified"; public static final String CONSOLE_HELP_SL_COMMAND_ARGUMENT_DESCRIPTION = "bundle to get the start level"; public static final String CONSOLE_HELP_SETFWSL_COMMAND_DESCRIPTION = "set the framework start level"; diff --git a/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/EquinoxCommandProvider.java b/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/EquinoxCommandProvider.java index 0e2f2a00f..8f4945db9 100755 --- a/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/EquinoxCommandProvider.java +++ b/bundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/EquinoxCommandProvider.java @@ -16,6 +16,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; @@ -1450,7 +1451,27 @@ public class EquinoxCommandProvider implements SynchronousBundleListener { */ @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_DESCRIPTION) public void t() throws Exception { - threads(); + t(null, null); + } + + @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ACTION_DESCRIPTION) + public void t(@Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_ACTION_DESCRIPTION) String action, @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_THREAD_DESCRIPTION) String thread) throws Exception { + t(action, thread, null); + } + + @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ACTION_THROWABLE_DESCRIPTION) + public void t(@Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_ACTION_DESCRIPTION) String action, @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_THREAD_DESCRIPTION) String thread, @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_THROWABLE_DESCRIPTION) Class<? extends Throwable> throwable) throws Exception { + threads(action, thread, throwable); + } + + @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_DESCRIPTION) + public void threads() throws Exception { + threads(null, null); + } + + @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ACTION_DESCRIPTION) + public void threads(@Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_ACTION_DESCRIPTION) String action, @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_THREAD_DESCRIPTION) String thread) throws Exception { + threads(action, thread, null); } /** @@ -1458,8 +1479,8 @@ public class EquinoxCommandProvider implements SynchronousBundleListener { * in the embedded system. * */ - @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_DESCRIPTION) - public void threads() throws Exception { + @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ACTION_THROWABLE_DESCRIPTION) + public void threads(@Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_ACTION_DESCRIPTION) String action, @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_THREAD_DESCRIPTION) String thread, @Descriptor(ConsoleMsg.CONSOLE_THREADS_COMMAND_ARG_THROWABLE_DESCRIPTION) Class<? extends Throwable> throwable) throws Exception { ThreadGroup[] threadGroups = getThreadGroups(); Util.sortByString(threadGroups); @@ -1467,6 +1488,58 @@ public class EquinoxCommandProvider implements SynchronousBundleListener { ThreadGroup tg = getTopThreadGroup(); Thread[] threads = new Thread[tg.activeCount()]; int count = tg.enumerate(threads, true); + + // Was an action specified? + if (action != null) { + // An action was specified. Process it here and return without + // listing all of the threads. + if ("stop".equals(action)) { + // A thread needs to be stopped. + // Locate the thread with the specified name. + Thread t = null; + for (int i = 0; i < threads.length; i++) { + if (threads[i].getName().equals(thread)) { + // Found the thread. Stop the loop. + t = threads[i]; + break; + } + } + if (t == null) { + // Did not find a thread with the specified name. + System.out.println(NLS.bind(ConsoleMsg.THREADS_THREAD_DOES_NOT_EXIST, thread)); + return; + } + String message = NLS.bind(ConsoleMsg.THREADS_THREAD_STOPPED_BY_CONSOLE, t.getName()); + // Instantiate the specified exception, if any. + Throwable toThrow; + // Was an exception specified? + if (throwable == null) + // If not, use the default. + toThrow = new IllegalStateException(message); + else { + // Instantiate the throwable with the message, if possible. + // Otherwise use the default constructor. + try { + toThrow = throwable.getConstructor(String.class).newInstance(message); + } + catch (Exception e) { + toThrow = throwable.newInstance(); + } + } + // Initialize the cause. Its stack trace will be that of the current thread. + toThrow.initCause(new RuntimeException(message)); + // Set the stack trace to that of the target thread. + toThrow.setStackTrace(t.getStackTrace()); + // Stop the thread using the specified throwable. + t.stop(toThrow); + return; + } + // An unrecognized action was specified. + System.out.println(ConsoleMsg.THREADS_UNRECOGNIZED_ACTION); + return; + } + + // No need to sort if an action was specified. Util.sortByString(threads); StringBuffer sb = new StringBuffer(120); |