/******************************************************************************* * * Copyright (c) 2010, InfraDNA, Inc. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * * * *******************************************************************************/ package hudson.model.queue; import hudson.AbortException; /** * A concurrency primitive that waits for N number of threads to synchronize. If * any of the threads are interrupted while waiting for the completion of the * condition, then all the involved threads get interrupted. * * @author Kohsuke Kawaguchi */ class Latch { private final int n; private int i = 0; /** * If the synchronization on the latch is aborted/interrupted, point to the * stack trace where that happened. If null, no interruption happened. */ private Exception interrupted; public Latch(int n) { this.n = n; } public synchronized void abort(Throwable cause) { interrupted = new AbortException(); if (cause != null) { interrupted.initCause(cause); } notifyAll(); } public synchronized void synchronize() throws InterruptedException { check(n); try { onCriteriaMet(); } catch (Error e) { abort(e); throw e; } catch (RuntimeException e) { abort(e); throw e; } check(n * 2); } private void check(int threshold) throws InterruptedException { i++; if (i == threshold) { notifyAll(); } else { while (i < threshold && interrupted == null) { try { wait(); } catch (InterruptedException e) { interrupted = e; notifyAll(); throw e; } } } // all of us either leave normally or get interrupted if (interrupted != null) { throw (InterruptedException) new InterruptedException().initCause(interrupted); } } protected void onCriteriaMet() throws InterruptedException { } }