aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Ross2012-11-05 16:18:08 (EST)
committerJohn Ross2012-11-05 16:36:54 (EST)
commitec21eb4e37d764934e84fac5ee09179f3d66b12b (patch)
tree8418b476b1f2818098d5ff6131aedf3cd34c1167
parentc343180660d3ee829d18ed3997e50c5f71ce85e4 (diff)
downloadrt.equinox.bundles-ec21eb4e37d764934e84fac5ee09179f3d66b12b.zip
rt.equinox.bundles-ec21eb4e37d764934e84fac5ee09179f3d66b12b.tar.gz
rt.equinox.bundles-ec21eb4e37d764934e84fac5ee09179f3d66b12b.tar.bz2
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.
-rwxr-xr-xbundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMessages.properties3
-rwxr-xr-xbundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/ConsoleMsg.java9
-rwxr-xr-xbundles/org.eclipse.equinox.console/src/org/eclipse/equinox/console/commands/EquinoxCommandProvider.java79
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 ad516ea..cae002d 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 eee8340..4d09386 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 0e2f2a0..8f4945d 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);