1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/WaitingThread.java $ 3 * $Revision: 649217 $ 4 * $Date: 2008-04-17 11:32:32 -0700 (Thu, 17 Apr 2008) $ 5 * 6 * ==================================================================== 7 * 8 * Licensed to the Apache Software Foundation (ASF) under one or more 9 * contributor license agreements. See the NOTICE file distributed with 10 * this work for additional information regarding copyright ownership. 11 * The ASF licenses this file to You under the Apache License, Version 2.0 12 * (the "License"); you may not use this file except in compliance with 13 * the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * ==================================================================== 23 * 24 * This software consists of voluntary contributions made by many 25 * individuals on behalf of the Apache Software Foundation. For more 26 * information on the Apache Software Foundation, please see 27 * <http://www.apache.org/>. 28 * 29 */ 30 31 package org.apache.http.impl.conn.tsccm; 32 33 34 import java.util.Date; 35 import java.util.concurrent.locks.Condition; 36 37 38 /** 39 * Represents a thread waiting for a connection. 40 * This class implements throwaway objects. It is instantiated whenever 41 * a thread needs to wait. Instances are not re-used, except if the 42 * waiting thread experiences a spurious wakeup and continues to wait. 43 * <br/> 44 * All methods assume external synchronization on the condition 45 * passed to the constructor. 46 * Instances of this class do <i>not</i> synchronize access! 47 * 48 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a> 49 */ 50 public class WaitingThread { 51 52 /** The condition on which the thread is waiting. */ 53 private final Condition cond; 54 55 /** The route specific pool on which the thread is waiting. */ 56 //@@@ replace with generic pool interface 57 private final RouteSpecificPool pool; 58 59 /** The thread that is waiting for an entry. */ 60 private Thread waiter; 61 62 /** True if this was interrupted. */ 63 private boolean aborted; 64 65 66 /** 67 * Creates a new entry for a waiting thread. 68 * 69 * @param cond the condition for which to wait 70 * @param pool the pool on which the thread will be waiting, 71 * or <code>null</code> 72 */ 73 public WaitingThread(Condition cond, RouteSpecificPool pool) { 74 75 if (cond == null) { 76 throw new IllegalArgumentException("Condition must not be null."); 77 } 78 79 this.cond = cond; 80 this.pool = pool; 81 } 82 83 84 /** 85 * Obtains the condition. 86 * 87 * @return the condition on which to wait, never <code>null</code> 88 */ 89 public final Condition getCondition() { 90 // not synchronized 91 return this.cond; 92 } 93 94 95 /** 96 * Obtains the pool, if there is one. 97 * 98 * @return the pool on which a thread is or was waiting, 99 * or <code>null</code> 100 */ 101 public final RouteSpecificPool getPool() { 102 // not synchronized 103 return this.pool; 104 } 105 106 107 /** 108 * Obtains the thread, if there is one. 109 * 110 * @return the thread which is waiting, or <code>null</code> 111 */ 112 public final Thread getThread() { 113 // not synchronized 114 return this.waiter; 115 } 116 117 118 /** 119 * Blocks the calling thread. 120 * This method returns when the thread is notified or interrupted, 121 * if a timeout occurrs, or if there is a spurious wakeup. 122 * <br/> 123 * This method assumes external synchronization. 124 * 125 * @param deadline when to time out, or <code>null</code> for no timeout 126 * 127 * @return <code>true</code> if the condition was satisfied, 128 * <code>false</code> in case of a timeout. 129 * Typically, a call to {@link #wakeup} is used to indicate 130 * that the condition was satisfied. Since the condition is 131 * accessible outside, this cannot be guaranteed though. 132 * 133 * @throws InterruptedException if the waiting thread was interrupted 134 * 135 * @see #wakeup 136 */ 137 public boolean await(Date deadline) 138 throws InterruptedException { 139 140 // This is only a sanity check. We cannot synchronize here, 141 // the lock would not be released on calling cond.await() below. 142 if (this.waiter != null) { 143 throw new IllegalStateException 144 ("A thread is already waiting on this object." + 145 "\ncaller: " + Thread.currentThread() + 146 "\nwaiter: " + this.waiter); 147 } 148 149 if (aborted) 150 throw new InterruptedException("Operation interrupted"); 151 152 this.waiter = Thread.currentThread(); 153 154 boolean success = false; 155 try { 156 if (deadline != null) { 157 success = this.cond.awaitUntil(deadline); 158 } else { 159 this.cond.await(); 160 success = true; 161 } 162 if (aborted) 163 throw new InterruptedException("Operation interrupted"); 164 } finally { 165 this.waiter = null; 166 } 167 return success; 168 169 } // await 170 171 172 /** 173 * Wakes up the waiting thread. 174 * <br/> 175 * This method assumes external synchronization. 176 */ 177 public void wakeup() { 178 179 // If external synchronization and pooling works properly, 180 // this cannot happen. Just a sanity check. 181 if (this.waiter == null) { 182 throw new IllegalStateException 183 ("Nobody waiting on this object."); 184 } 185 186 // One condition might be shared by several WaitingThread instances. 187 // It probably isn't, but just in case: wake all, not just one. 188 this.cond.signalAll(); 189 } 190 191 public void interrupt() { 192 aborted = true; 193 this.cond.signalAll(); 194 } 195 196 197 } // class WaitingThread 198