1 /* 2 * Created on 18-Sep-2004 3 * Created by Paul Gardner 4 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 */ 19 20 package org.gudy.azureus2.core3.util; 21 22 /** 23 * @author parg 24 * 25 */ 26 public class 27 AESemaphore 28 extends AEMonSem 29 { 30 private int dont_wait = 0; 31 32 private int total_reserve = 0; 33 private int total_release = 0; 34 35 private boolean released_forever = false; 36 37 protected Thread latest_waiter; 38 39 public AESemaphore( String _name )40 AESemaphore( 41 String _name ) 42 { 43 this( _name, 0 ); 44 } 45 46 public AESemaphore( String _name, int count )47 AESemaphore( 48 String _name, 49 int count ) 50 { 51 super( _name, false ); 52 53 dont_wait = count; 54 total_release = count; 55 } 56 57 public void reserve()58 reserve() 59 { 60 if ( !reserve(0)){ 61 62 Debug.out( "AESemaphore: reserve completed without acquire [" + getString() + "]" ); 63 } 64 } 65 66 public boolean reserve( long millis )67 reserve( 68 long millis ) 69 { 70 return( reserveSupport( millis, 1 ) == 1 ); 71 } 72 73 public boolean reserveIfAvailable()74 reserveIfAvailable() 75 { 76 synchronized(this){ 77 78 if ( released_forever || dont_wait > 0 ){ 79 80 reserve(); 81 82 return( true ); 83 84 }else{ 85 86 return( false ); 87 } 88 } 89 } 90 91 public int reserveSet( int max_to_reserve, long millis )92 reserveSet( 93 int max_to_reserve, 94 long millis ) 95 { 96 return( reserveSupport( millis, max_to_reserve)); 97 } 98 99 public int reserveSet( int max_to_reserve )100 reserveSet( 101 int max_to_reserve ) 102 { 103 return( reserveSupport( 0, max_to_reserve)); 104 } 105 106 protected int reserveSupport( long millis, int max_to_reserve )107 reserveSupport( 108 long millis, 109 int max_to_reserve ) 110 { 111 if ( DEBUG ){ 112 113 super.debugEntry(); 114 } 115 116 synchronized(this){ 117 118 entry_count++; 119 120 //System.out.println( name + "::reserve"); 121 122 if ( released_forever ){ 123 124 return(1); 125 } 126 127 if ( dont_wait == 0 ){ 128 129 try{ 130 waiting++; 131 132 latest_waiter = Thread.currentThread(); 133 134 if ( waiting > 1 ){ 135 136 // System.out.println( "AESemaphore: " + name + " contended" ); 137 } 138 139 if ( millis == 0 ){ 140 141 // we can get spurious wakeups (see Object javadoc) so we need to guard against 142 // their possibility 143 144 int spurious_count = 0; 145 146 while( true ){ 147 148 wait(); 149 150 if ( total_reserve == total_release ){ 151 152 spurious_count++; 153 154 if ( spurious_count > 1024 ){ 155 156 Debug.out( "AESemaphore: spurious wakeup limit exceeded" ); 157 158 throw( new Throwable( "die die die" )); 159 160 }else{ 161 162 // Debug.out("AESemaphore: spurious wakeup, ignoring" ); 163 } 164 }else{ 165 166 break; 167 } 168 } 169 }else{ 170 171 // we don't hugely care about spurious wakeups here, it'll just appear 172 // as a failed reservation a bit early 173 174 wait(millis); 175 } 176 177 if ( total_reserve == total_release ){ 178 179 // here we have timed out on the wait without acquiring 180 181 waiting--; 182 183 return( 0 ); 184 } 185 186 total_reserve++; 187 188 return( 1 ); 189 190 }catch( Throwable e ){ 191 192 waiting--; 193 194 Debug.out( "**** semaphore operation interrupted ****" ); 195 196 throw( new RuntimeException("Semaphore: operation interrupted", e )); 197 198 }finally{ 199 200 latest_waiter = null; 201 } 202 }else{ 203 int num_to_get = max_to_reserve>dont_wait?dont_wait:max_to_reserve; 204 205 dont_wait -= num_to_get; 206 207 total_reserve += num_to_get; 208 209 return( num_to_get ); 210 } 211 } 212 } 213 214 public void release()215 release() 216 { 217 try{ 218 synchronized(this){ 219 220 //System.out.println( name + "::release"); 221 222 total_release++; 223 224 if ( waiting != 0 ){ 225 226 waiting--; 227 228 notify(); 229 230 }else{ 231 dont_wait++; 232 } 233 } 234 }finally{ 235 236 if ( DEBUG ){ 237 238 debugExit(); 239 } 240 } 241 } 242 243 public void releaseAllWaiters()244 releaseAllWaiters() 245 { 246 synchronized(this){ 247 248 int x = waiting; 249 250 for ( int i=0;i<x;i++ ){ 251 release(); 252 } 253 } 254 } 255 256 public void releaseForever()257 releaseForever() 258 { 259 synchronized(this){ 260 261 releaseAllWaiters(); 262 263 released_forever = true; 264 } 265 } 266 267 public boolean isReleasedForever()268 isReleasedForever() 269 { 270 synchronized(this){ 271 272 return( released_forever ); 273 } 274 } 275 276 public int getValue()277 getValue() 278 { 279 synchronized(this){ 280 281 return( dont_wait - waiting ); 282 } 283 } 284 285 public String getString()286 getString() 287 { 288 synchronized(this){ 289 290 return( "value=" + dont_wait + ",waiting=" + waiting + ",res=" + total_reserve + ",rel=" + total_release ); 291 } 292 } 293 } 294