001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.scheduler; 014 015 import static org.jikesrvm.runtime.SysCall.sysCall; 016 import org.jikesrvm.VM; 017 018 import org.vmmagic.pragma.Uninterruptible; 019 import org.vmmagic.pragma.Unpreemptible; 020 import org.vmmagic.pragma.NonMoving; 021 import org.vmmagic.pragma.NoInline; 022 import org.vmmagic.pragma.NoOptCompile; 023 import org.vmmagic.pragma.BaselineSaveLSRegisters; 024 import org.vmmagic.unboxed.Word; 025 026 /** 027 * Implementation of a heavy lock and condition variable implemented using 028 * the primitives available from the operating system. Currently we use 029 * a pthread_mutex_t and pthread_cond_it. When instantiated, the mutex 030 * and cond are allocated. There is currently no way to destroy either 031 * (thus, pool and reuse accordingly). 032 * <p> 033 * It is perfectly safe to use this throughout the VM for locking. It is 034 * meant to provide roughly the same functionality as Java monitors, 035 * except: 036 * <ul> 037 * <li>This class provides a faster slow path than Java monitors.</li> 038 * <li>This class provides a slower fast path than Java monitors.</li> 039 * <li>This class does not have any interaction with Thread.interrupt() 040 * or Thread.stop(). Thus, if you block on a lock or a wait and the 041 * calling thread is stopped or interrupted, nothing will happen 042 * until the lock is acquired or the wait is notified.</li> 043 * <li>This class will work in the inner guts of the RVM runtime because 044 * it gives you the ability to lock and unlock, as well as wait and 045 * notify, without using any other VM runtime functionality.</li> 046 * <li>This class allows you to optionally block without letting the thread 047 * system know that you are blocked. The benefit is that you can 048 * perform synchronization without depending on RVM thread subsystem functionality. 049 * However, most of the time, you should use the methods that inform 050 * the thread system that you are blocking. Methods that have the 051 * "Nicely" suffix will inform the thread system if you are blocked, 052 * while methods that do not have the suffix will either not block 053 * (as is the case with unlock and broadcast) or will block without 054 * letting anyone know (like lock and wait). Not letting the threading 055 * system know that you are blocked may cause things like GC to stall 056 * until you unblock.</li> 057 * </ul> 058 */ 059 @Uninterruptible 060 @NonMoving 061 public class Monitor { 062 Word monitor; 063 int holderSlot=-1; // use the slot so that we're even more GC safe 064 int recCount; 065 public int acquireCount; 066 /** 067 * Allocate a heavy condition variable and lock. This involves 068 * allocating stuff in C that never gets deallocated. Thus, don't 069 * instantiate too many of these. 070 */ 071 public Monitor() { 072 monitor = sysCall.sysMonitorCreate(); 073 } 074 /** 075 * Wait until it is possible to acquire the lock and then acquire it. 076 * There is no bound on how long you might wait, if someone else is 077 * holding the lock and there is no bound on how long they will hold it. 078 * As well, even if there is a bound on how long a thread might hold a 079 * lock but there are multiple threads contending on its acquisition, 080 * there will not necessarily be a bound on how long any particular 081 * thread will wait until it gets its turn. 082 * <p> 083 * This blocking method method does not notify the threading subsystem 084 * that it is blocking. Thus, if someone (like, say, the GC) requests 085 * that the thread is blocked then their request will block until this 086 * method unblocks. If this sounds like it might be undesirable, call 087 * lockNicely instead. 088 */ 089 @NoInline 090 @NoOptCompile 091 public void lockNoHandshake() { 092 int mySlot = RVMThread.getCurrentThreadSlot(); 093 if (mySlot != holderSlot) { 094 sysCall.sysMonitorEnter(monitor); 095 if (VM.VerifyAssertions) VM._assert(holderSlot==-1); 096 if (VM.VerifyAssertions) VM._assert(recCount==0); 097 holderSlot = mySlot; 098 } 099 recCount++; 100 acquireCount++; 101 } 102 /** 103 * Relock the mutex after using unlockCompletely. 104 */ 105 @NoInline 106 @NoOptCompile 107 public void relockNoHandshake(int recCount) { 108 sysCall.sysMonitorEnter(monitor); 109 if (VM.VerifyAssertions) VM._assert(holderSlot==-1); 110 if (VM.VerifyAssertions) VM._assert(this.recCount==0); 111 holderSlot=RVMThread.getCurrentThreadSlot(); 112 this.recCount=recCount; 113 acquireCount++; 114 } 115 /** 116 * Wait until it is possible to acquire the lock and then acquire it. 117 * There is no bound on how long you might wait, if someone else is 118 * holding the lock and there is no bound on how long they will hold it. 119 * As well, even if there is a bound on how long a thread might hold a 120 * lock but there are multiple threads contending on its acquisition, 121 * there will not necessarily be a bound on how long any particular 122 * thread will wait until it gets its turn. 123 * <p> 124 * This blocking method method notifies the threading subsystem that it 125 * is blocking. Thus, it may be safer than calling lock. But, 126 * its reliance on threading subsystem accounting methods may mean that 127 * it cannot be used in certain contexts (say, the threading subsystem 128 * itself). 129 * <p> 130 * This method will ensure that if it blocks, it does so with the 131 * mutex not held. This is useful for cases where the subsystem that 132 * requested you to block needs to acquire the lock you were trying to 133 * acquire when the blocking request came. 134 * <p> 135 * It is usually not necessary to call this method instead of lock(), 136 * since most VM locks are held for short periods of time. 137 */ 138 @Unpreemptible("If the lock cannot be acquired, this method will allow the thread to be asynchronously blocked") 139 @NoInline 140 @NoOptCompile 141 public void lockWithHandshake() { 142 int mySlot = RVMThread.getCurrentThreadSlot(); 143 if (mySlot != holderSlot) { 144 lockWithHandshakeNoRec(); 145 if (VM.VerifyAssertions) VM._assert(holderSlot==-1); 146 if (VM.VerifyAssertions) VM._assert(recCount==0); 147 holderSlot = mySlot; 148 } 149 recCount++; 150 acquireCount++; 151 } 152 @NoInline 153 @NoOptCompile 154 @BaselineSaveLSRegisters 155 @Unpreemptible 156 private void lockWithHandshakeNoRec() { 157 RVMThread.saveThreadState(); 158 lockWithHandshakeNoRecImpl(); 159 } 160 @NoInline 161 @Unpreemptible 162 @NoOptCompile 163 private void lockWithHandshakeNoRecImpl() { 164 for (;;) { 165 RVMThread.enterNative(); 166 sysCall.sysMonitorEnter(monitor); 167 if (RVMThread.attemptLeaveNativeNoBlock()) { 168 return; 169 } else { 170 sysCall.sysMonitorExit(monitor); 171 RVMThread.leaveNative(); 172 } 173 } 174 } 175 /** 176 * Relock the mutex after using unlockCompletely, but do so "nicely". 177 */ 178 @NoInline 179 @NoOptCompile 180 @BaselineSaveLSRegisters 181 @Unpreemptible("If the lock cannot be reacquired, this method may allow the thread to be asynchronously blocked") 182 public void relockWithHandshake(int recCount) { 183 RVMThread.saveThreadState(); 184 relockWithHandshakeImpl(recCount); 185 } 186 @NoInline 187 @Unpreemptible 188 @NoOptCompile 189 private void relockWithHandshakeImpl(int recCount) { 190 for (;;) { 191 RVMThread.enterNative(); 192 sysCall.sysMonitorEnter(monitor); 193 if (RVMThread.attemptLeaveNativeNoBlock()) { 194 break; 195 } else { 196 sysCall.sysMonitorExit(monitor); 197 RVMThread.leaveNative(); 198 } 199 } 200 if (VM.VerifyAssertions) VM._assert(holderSlot==-1); 201 if (VM.VerifyAssertions) VM._assert(this.recCount==0); 202 holderSlot=RVMThread.getCurrentThreadSlot(); 203 this.recCount=recCount; 204 } 205 /** 206 * Release the lock. This method should (in principle) be non-blocking, 207 * and, as such, it does not notify the threading subsystem that it is 208 * blocking. 209 */ 210 @NoInline 211 @NoOptCompile 212 public void unlock() { 213 if (--recCount==0) { 214 holderSlot=-1; 215 sysCall.sysMonitorExit(monitor); 216 } 217 } 218 /** 219 * Completely release the lock, ignoring recursion. Returns the 220 * recursion count. 221 */ 222 @NoInline 223 @NoOptCompile 224 public int unlockCompletely() { 225 int result=recCount; 226 recCount=0; 227 holderSlot=-1; 228 sysCall.sysMonitorExit(monitor); 229 return result; 230 } 231 /** 232 * Wait until someone calls broadcast. 233 * <p> 234 * This blocking method method does not notify the threading subsystem 235 * that it is blocking. Thus, if someone (like, say, the GC) requests 236 * that the thread is blocked then their request will block until this 237 * method unblocks. If this sounds like it might be undesirable, call 238 * waitNicely instead. 239 */ 240 @NoInline 241 @NoOptCompile 242 public void waitNoHandshake() { 243 int recCount=this.recCount; 244 this.recCount=0; 245 holderSlot=-1; 246 sysCall.sysMonitorWait(monitor); 247 if (VM.VerifyAssertions) VM._assert(holderSlot==-1); 248 if (VM.VerifyAssertions) VM._assert(this.recCount==0); 249 this.recCount=recCount; 250 holderSlot=RVMThread.getCurrentThreadSlot(); 251 } 252 /** 253 * Wait until someone calls broadcast, or until the clock reaches the 254 * given time. 255 * <p> 256 * This blocking method method does not notify the threading subsystem 257 * that it is blocking. Thus, if someone (like, say, the GC) requests 258 * that the thread is blocked then their request will block until this 259 * method unblocks. If this sounds like it might be undesirable, call 260 * timedWaitAbsoluteNicely instead. 261 */ 262 @NoInline 263 @NoOptCompile 264 public void timedWaitAbsoluteNoHandshake(long whenWakeupNanos) { 265 int recCount=this.recCount; 266 this.recCount=0; 267 holderSlot=-1; 268 sysCall.sysMonitorTimedWaitAbsolute(monitor, whenWakeupNanos); 269 if (VM.VerifyAssertions) VM._assert(holderSlot==-1); 270 if (VM.VerifyAssertions) VM._assert(this.recCount==0); 271 this.recCount=recCount; 272 holderSlot=RVMThread.getCurrentThreadSlot(); 273 } 274 /** 275 * Wait until someone calls broadcast, or until at least the given 276 * number of nanoseconds pass. 277 * <p> 278 * This blocking method method does not notify the threading subsystem 279 * that it is blocking. Thus, if someone (like, say, the GC) requests 280 * that the thread is blocked then their request will block until this 281 * method unblocks. If this sounds like it might be undesirable, call 282 * timedWaitRelativeNicely instead. 283 */ 284 @NoInline 285 @NoOptCompile 286 public void timedWaitRelativeNoHandshake(long delayNanos) { 287 long now=sysCall.sysNanoTime(); 288 timedWaitAbsoluteNoHandshake(now+delayNanos); 289 } 290 /** 291 * Wait until someone calls broadcast. 292 * <p> 293 * This blocking method notifies the threading subsystem that it 294 * is blocking. Thus, it is generally safer than calling wait. But, 295 * its reliance on threading subsystem accounting methods may mean that 296 * it cannot be used in certain contexts (say, the threading subsystem 297 * itself). 298 * <p> 299 * This method will ensure that if it blocks, it does so with the 300 * mutex not held. This is useful for cases where the subsystem that 301 * requested you to block needs to acquire the lock you were trying to 302 * acquire when the blocking request came. 303 */ 304 @NoInline 305 @NoOptCompile 306 @BaselineSaveLSRegisters 307 @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked") 308 public void waitWithHandshake() { 309 RVMThread.saveThreadState(); 310 waitWithHandshakeImpl(); 311 } 312 @NoInline 313 @Unpreemptible 314 @NoOptCompile 315 private void waitWithHandshakeImpl() { 316 RVMThread.enterNative(); 317 waitNoHandshake(); 318 int recCount=unlockCompletely(); 319 RVMThread.leaveNative(); 320 relockWithHandshakeImpl(recCount); 321 } 322 /** 323 * Wait until someone calls broadcast, or until the clock reaches the 324 * given time. 325 * <p> 326 * This blocking method method notifies the threading subsystem that it 327 * is blocking. Thus, it is generally safer than calling 328 * timedWaitAbsolute. But, its reliance on threading subsystem accounting 329 * methods may mean that it cannot be used in certain contexts (say, the 330 * threading subsystem itself). 331 * <p> 332 * This method will ensure that if it blocks, it does so with the 333 * mutex not held. This is useful for cases where the subsystem that 334 * requested you to block needs to acquire the lock you were trying to 335 * acquire when the blocking request came. 336 */ 337 @NoInline 338 @NoOptCompile 339 @BaselineSaveLSRegisters 340 @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked") 341 public void timedWaitAbsoluteWithHandshake(long whenWakeupNanos) { 342 RVMThread.saveThreadState(); 343 timedWaitAbsoluteWithHandshakeImpl(whenWakeupNanos); 344 } 345 @NoInline 346 @Unpreemptible 347 @NoOptCompile 348 private void timedWaitAbsoluteWithHandshakeImpl(long whenWakeupNanos) { 349 RVMThread.enterNative(); 350 timedWaitAbsoluteNoHandshake(whenWakeupNanos); 351 int recCount=unlockCompletely(); 352 RVMThread.leaveNative(); 353 relockWithHandshakeImpl(recCount); 354 } 355 /** 356 * Wait until someone calls broadcast, or until at least the given 357 * number of nanoseconds pass. 358 * <p> 359 * This blocking method method notifies the threading subsystem that it 360 * is blocking. Thus, it is generally safer than calling 361 * timedWaitRelative. But, its reliance on threading subsystem accounting 362 * methods may mean that it cannot be used in certain contexts (say, the 363 * threading subsystem itself). 364 * <p> 365 * This method will ensure that if it blocks, it does so with the 366 * mutex not held. This is useful for cases where the subsystem that 367 * requested you to block needs to acquire the lock you were trying to 368 * acquire when the blocking request came. 369 */ 370 @NoInline 371 @NoOptCompile 372 @BaselineSaveLSRegisters 373 @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked") 374 public void timedWaitRelativeWithHandshake(long delayNanos) { 375 RVMThread.saveThreadState(); 376 timedWaitRelativeWithHandshakeImpl(delayNanos); 377 } 378 @NoInline 379 @Unpreemptible 380 @NoOptCompile 381 private void timedWaitRelativeWithHandshakeImpl(long delayNanos) { 382 RVMThread.enterNative(); 383 timedWaitRelativeNoHandshake(delayNanos); 384 int recCount=unlockCompletely(); 385 RVMThread.leaveNative(); 386 relockWithHandshakeImpl(recCount); 387 } 388 389 /** 390 * Send a broadcast, which should awaken anyone who is currently blocked 391 * in any of the wait methods. This method should (in principle) be 392 * non-blocking, and, as such, it does not notify the threading subsystem 393 * that it is blocking. 394 */ 395 @NoInline 396 @NoOptCompile 397 public void broadcast() { 398 sysCall.sysMonitorBroadcast(monitor); 399 } 400 /** 401 * Send a broadcast after first acquiring the lock. Release the lock 402 * after sending the broadcast. In most cases where you want to send 403 * a broadcast but you don't need to acquire the lock to set the 404 * condition that the other thread(s) are waiting on, you want to call 405 * this method instead of <code>broadcast</code>. 406 */ 407 @NoInline 408 @NoOptCompile 409 public void lockedBroadcastNoHandshake() { 410 lockNoHandshake(); 411 broadcast(); 412 unlock(); 413 } 414 415 @NoInline 416 public static boolean lockNoHandshake(Monitor l) { 417 if (l==null) { 418 return false; 419 } else { 420 l.lockNoHandshake(); 421 return true; 422 } 423 } 424 @NoInline 425 public static void unlock(boolean b, Monitor l) { 426 if (b) l.unlock(); 427 } 428 429 @NoInline 430 @NoOptCompile 431 @Unpreemptible 432 public static void lockWithHandshake(Monitor m1,Word priority1, 433 Monitor m2,Word priority2) { 434 if (priority1.LE(priority2)) { 435 m1.lockWithHandshake(); 436 m2.lockWithHandshake(); 437 } else { 438 m2.lockWithHandshake(); 439 m1.lockWithHandshake(); 440 } 441 } 442 } 443