提交 01b1f1dd 编写于 作者: P Pavel Avgustinov 提交者: Oleg Nenashev

Fix potential deadlock between queue maintenance and asynchronous execution (#3354)

[JENKINS-46248] - Fix potential deadlock between queue maintenance and asynchronous execution
上级 24ea6846
......@@ -431,11 +431,12 @@ public class Executor extends Thread implements ModelObject {
} catch (AsynchronousExecution x) {
lock.writeLock().lock();
try {
x.setExecutor(this);
x.setExecutorWithoutCompleting(this);
this.asynchronousExecution = x;
} finally {
lock.writeLock().unlock();
}
x.maybeComplete();
} catch (Throwable e) {
problems = e;
} finally {
......
......@@ -39,6 +39,7 @@ import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;
import jenkins.model.Jenkins;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
......@@ -61,7 +62,7 @@ public abstract class AsynchronousExecution extends RuntimeException {
/**
* Initially null, and usually stays null.
* If {@link #completed} is called before {@link #setExecutor}, then either {@link #NULL} for success, or the error.
* If {@link #completed} is called before {@link #setExecutorWithoutCompleting}, then either {@link #NULL} for success, or the error.
*/
@GuardedBy("this")
private @CheckForNull Throwable result;
......@@ -98,7 +99,7 @@ public abstract class AsynchronousExecution extends RuntimeException {
/**
* Obtains the associated executor.
* @return Associated Executor. May be {@code null} if {@link #setExecutor(hudson.model.Executor)}
* @return Associated Executor. May be {@code null} if {@link #setExecutorWithoutCompleting(hudson.model.Executor)}
* has not been called yet.
*/
@CheckForNull
......@@ -106,13 +107,26 @@ public abstract class AsynchronousExecution extends RuntimeException {
return executor;
}
/**
* Set the executor without notifying it about task completion.
* The caller <b>must</b> also call {@link #maybeComplete()}
* after releasing any problematic locks.
*/
@Restricted(NoExternalUse.class)
public synchronized final void setExecutor(@Nonnull Executor executor) {
assert this.executor==null;
public synchronized final void setExecutorWithoutCompleting(@Nonnull Executor executor) {
assert this.executor == null;
this.executor = executor;
if (result!=null) {
executor.completedAsynchronous( result!=NULL ? result : null );
}
/**
* If there is a pending completion notification, deliver it to the executor.
* Must be called after {@link #setExecutorWithoutCompleting(Executor)}.
*/
@Restricted(NoExternalUse.class)
public synchronized final void maybeComplete() {
assert this.executor != null;
if (result != null) {
executor.completedAsynchronous(result != NULL ? result : null);
result = null;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册