/* * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/WaitingThread.java $ * $Revision: 649217 $ * $Date: 2008-04-17 11:32:32 -0700 (Thu, 17 Apr 2008) $ * * ==================================================================== * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.http.impl.conn.tsccm; import java.util.Date; import java.util.concurrent.locks.Condition; /** * Represents a thread waiting for a connection. * This class implements throwaway objects. It is instantiated whenever * a thread needs to wait. Instances are not re-used, except if the * waiting thread experiences a spurious wakeup and continues to wait. * <br/> * All methods assume external synchronization on the condition * passed to the constructor. * Instances of this class do <i>not</i> synchronize access! * * @author <a href="mailto:rolandw at apache.org">Roland Weber</a> */ public class WaitingThread { /** The condition on which the thread is waiting. */ private final Condition cond; /** The route specific pool on which the thread is waiting. */ //@@@ replace with generic pool interface private final RouteSpecificPool pool; /** The thread that is waiting for an entry. */ private Thread waiter; /** True if this was interrupted. */ private boolean aborted; /** * Creates a new entry for a waiting thread. * * @param cond the condition for which to wait * @param pool the pool on which the thread will be waiting, * or <code>null</code> */ public WaitingThread(Condition cond, RouteSpecificPool pool) { if (cond == null) { throw new IllegalArgumentException("Condition must not be null."); } this.cond = cond; this.pool = pool; } /** * Obtains the condition. * * @return the condition on which to wait, never <code>null</code> */ public final Condition getCondition() { // not synchronized return this.cond; } /** * Obtains the pool, if there is one. * * @return the pool on which a thread is or was waiting, * or <code>null</code> */ public final RouteSpecificPool getPool() { // not synchronized return this.pool; } /** * Obtains the thread, if there is one. * * @return the thread which is waiting, or <code>null</code> */ public final Thread getThread() { // not synchronized return this.waiter; } /** * Blocks the calling thread. * This method returns when the thread is notified or interrupted, * if a timeout occurrs, or if there is a spurious wakeup. * <br/> * This method assumes external synchronization. * * @param deadline when to time out, or <code>null</code> for no timeout * * @return <code>true</code> if the condition was satisfied, * <code>false</code> in case of a timeout. * Typically, a call to {@link #wakeup} is used to indicate * that the condition was satisfied. Since the condition is * accessible outside, this cannot be guaranteed though. * * @throws InterruptedException if the waiting thread was interrupted * * @see #wakeup */ public boolean await(Date deadline) throws InterruptedException { // This is only a sanity check. We cannot synchronize here, // the lock would not be released on calling cond.await() below. if (this.waiter != null) { throw new IllegalStateException ("A thread is already waiting on this object." + "\ncaller: " + Thread.currentThread() + "\nwaiter: " + this.waiter); } if (aborted) throw new InterruptedException("Operation interrupted"); this.waiter = Thread.currentThread(); boolean success = false; try { if (deadline != null) { success = this.cond.awaitUntil(deadline); } else { this.cond.await(); success = true; } if (aborted) throw new InterruptedException("Operation interrupted"); } finally { this.waiter = null; } return success; } // await /** * Wakes up the waiting thread. * <br/> * This method assumes external synchronization. */ public void wakeup() { // If external synchronization and pooling works properly, // this cannot happen. Just a sanity check. if (this.waiter == null) { throw new IllegalStateException ("Nobody waiting on this object."); } // One condition might be shared by several WaitingThread instances. // It probably isn't, but just in case: wake all, not just one. this.cond.signalAll(); } public void interrupt() { aborted = true; this.cond.signalAll(); } } // class WaitingThread