kill: Support killing any queued task by interrupting it

We probably don't have enough cancellation points in our code to
really kill most tasks before they fully complete.  For example,
most of the JGit upload-pack and receive-pack code path uses
NullProgressMonitor, which unfortunately does not check if the
calling thread has been interrupted.

Change-Id: I57379ba77d7aefc720421d74771fb65ab6be61fa
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce
2009-11-20 20:15:41 -08:00
parent 0f28761ff1
commit 3f1a13afb3
15 changed files with 457 additions and 139 deletions

View File

@@ -14,9 +14,9 @@
package com.google.gerrit.sshd;
import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.server.RequestCleanup;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.CancelableRunnable;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.sshd.SshScopes.Context;
@@ -256,12 +256,6 @@ public abstract class BaseCommand implements Command {
* command's logic.
*/
protected synchronized void startThread(final CommandRunnable thunk) {
final List<Command> active =
SshScopes.getContext().session.getAttribute(SshUtil.ACTIVE);
synchronized (active) {
active.add(BaseCommand.this);
}
final TaskThunk tt = new TaskThunk(thunk);
if (isAdminCommand()) {
// Admin commands should not block the main work threads (there
@@ -374,7 +368,7 @@ public abstract class BaseCommand implements Command {
return commandPrefix + " " + commandLine;
}
private final class TaskThunk implements Runnable {
private final class TaskThunk implements CancelableRunnable {
private final CommandRunnable thunk;
private final Context context;
@@ -383,13 +377,23 @@ public abstract class BaseCommand implements Command {
this.context = SshScopes.getContext();
}
@Override
public void cancel() {
try {
SshScopes.current.set(context);
onExit(15);
} finally {
SshScopes.current.set(null);
}
}
@Override
public void run() {
final Thread thisThread = Thread.currentThread();
final String thisName = thisThread.getName();
int rc = 0;
try {
thisThread.setName(toString());
thisThread.setName("SSH " + toString());
SshScopes.current.set(context);
try {
thunk.run();
@@ -412,10 +416,6 @@ public abstract class BaseCommand implements Command {
rc = handleError(e);
} finally {
try {
List<Command> active = context.session.getAttribute(SshUtil.ACTIVE);
synchronized (active) {
active.remove(BaseCommand.this);
}
onExit(rc);
} finally {
SshScopes.current.set(null);
@@ -428,8 +428,7 @@ public abstract class BaseCommand implements Command {
public String toString() {
final ServerSession session = context.session;
final String who = session.getUsername();
final Account.Id id = session.getAttribute(SshUtil.CURRENT_ACCOUNT);
return "SSH " + getFullCommandLine() + " / " + who + " " + id;
return getFullCommandLine() + " (" + who + ")";
}
}