001 package edu.rice.cs.cunit; 002 003 import edu.rice.cs.cunit.instrumentors.DoNotInstrument; 004 import edu.rice.cs.cunit.record.syncPoints.ISyncPoint; 005 006 /** 007 * Class that records synchronization points. 008 * 009 * NOTE: This class may not be instrumented with a strategy affecting synchronized methods or blocks! 010 * Do not instrument with SynchronizedMethodToBlockStrategy, SynchronizedBlockStrategy, 011 * CompactSynchronizedBlockStrategy, CompactSynchronizedBlockDebugStrategy, or 012 * CompactSynchronizedBlockReplayStrategy. 013 * 014 * @author Mathias Ricken 015 */ 016 @DoNotInstrument(instrumentors = "***.*Synchronized*;***.ObjectCallStrategy;***.AssignObjectIDStrategy") 017 public class SyncPointBuffer { 018 /** 019 * A method to retrieve the .class field; this is required for pre-1.5 compatibility where 020 * simple field access to the .class field is not allowed. 021 */ 022 public static final Class<?> _class() { 023 return SyncPointBuffer.class; 024 }; 025 026 /** 027 * Size of array. 028 */ 029 public static final int SIZE = 1 << 9; 030 031 /** 032 * Array of synchronization points. 033 */ 034 private static volatile ISyncPoint[] _syncPoints = new ISyncPoint[SIZE]; 035 036 /** 037 * Index to be used next. 038 */ 039 private static volatile int _index = 0; 040 041 /** 042 * Size of a record in the compact array. 043 */ 044 public static final int COMPACT_RECORD_SIZE = 2; 045 046 /** 047 * Size of a record in the compact array with debug info. 048 */ 049 public static final int COMPACT_DEBUG_RECORD_SIZE = 5; 050 051 /** 052 * Size of compact array. 053 */ 054 public static final int COMPACT_SIZE = 1 << 9; 055 056 /** 057 * Enumeration of sync point codes. 058 */ 059 public static enum SP { 060 /** 061 * Code for entering a synchronized block. 062 */ 063 MONITORENTER(1), 064 065 /** 066 * Code for leaving a synchronized block. 067 */ 068 MONITOREXIT(2), 069 070 /** 071 * Code for trying to enter a synchronized block. 072 */ 073 TRYMONITORENTER(3), 074 075 /** 076 * Code for the start of a thread. 077 */ 078 THREADSTART(4), 079 080 /** 081 * Code for the end of a thread. 082 */ 083 THREADEXIT(5), 084 085 /** 086 * Code for entering a synchronized block to assign an object ID. This synchronized block did not exist 087 * in the original program and is an artifact of the instrumentation. 088 * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless. 089 */ 090 OBJID_MONITORENTER(6), 091 092 /** 093 * Code for leaving a synchronized block to assign an object ID. This synchronized block did not exist 094 * in the original program and is an artifact of the instrumentation. 095 * Object ID is set to the newly assigned object ID. SyncPointBuffer.class is used as lock, but its object ID 096 * is rather meaningless. 097 */ 098 OBJID_MONITOREXIT(7), 099 100 /** 101 * Code for trying to enter a synchronized block to assign an object ID. This synchronized block did not exist 102 * in the original program and is an artifact of the instrumentation. 103 * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless. 104 */ 105 OBJID_TRYMONITORENTER(8), 106 107 /** 108 * Code for entering a synchronized block to assign a thread ID. This synchronized block did not exist 109 * in the original program and is an artifact of the instrumentation. 110 * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless. 111 */ 112 THREADID_MONITORENTER(9), 113 114 /** 115 * Code for leaving a synchronized block to assign a thread ID. This synchronized block did not exist 116 * in the original program and is an artifact of the instrumentation. 117 * Object ID is set to the newly assigned thread ID. SyncPointBuffer.class is used as lock, but its object ID 118 * is rather meaningless. 119 */ 120 THREADID_MONITOREXIT(10), 121 122 /** 123 * Code for trying to enter a synchronized block to assign a thread ID. This synchronized block did not exist 124 * in the original program and is an artifact of the instrumentation. 125 * Object ID is 0; since SyncPointBuffer.class is used as lock, the value is meaningless. 126 */ 127 THREADID_TRYMONITORENTER(11), 128 129 /** 130 * Code for the end of the trace. 131 */ 132 END(12), 133 134 /** 135 * Last code used. 136 */ 137 LAST_VALID_CODE(12); 138 139 /** 140 * Integer value of the enum. 141 */ 142 private int _value; 143 144 /** 145 * Constructor. 146 * @param value integer value 147 */ 148 SP(int value) { _value = value; } 149 150 /** 151 * Return the integer value of the enum. 152 * @return integer value, ranging from 1 to SP_LAST_VALID_CODE.value() (inclusive) 153 */ 154 public int intValue() { return _value; } 155 } 156 157 /** 158 * Compact array of synchronization points. 159 */ 160 private static volatile long[] _compactSyncPoints = new long[COMPACT_SIZE]; 161 162 /** 163 * Index to be used next for the compact array. 164 */ 165 private static volatile int _compactIndex = 0; 166 167 /** 168 * Size of replay array. 169 */ 170 public static final int REPLAY_SIZE = 1 << 9; 171 172 /** 173 * Record array of synchronization points. 174 */ 175 private static volatile long[] _replaySyncPoints = new long[REPLAY_SIZE]; 176 177 /** 178 * Object array with objects that threads may wait for. 179 */ 180 private static volatile Object[] _replayWaitArray = new Object[REPLAY_SIZE/COMPACT_RECORD_SIZE]; 181 182 /** 183 * Object that threads can wait for if they need to enter the algorithm. 184 */ 185 private static final Object _waitAlgoObj = new Object(); 186 187 /** 188 * Object that threads can wait for if they need to wait for a new buffer. 189 */ 190 private static final Object _newBufferWaitObj = new Object(); 191 192 /** 193 * Index to be used next for the replay array. 194 */ 195 private static volatile int _replayIndex = 0; 196 197 /** 198 * Index to be used next for the replay wait array. 199 */ 200 private static volatile int _replayWaitIndex = 0; 201 202 /** 203 * True if points should be recorded. 204 */ 205 private static volatile boolean _recording = false; 206 207 /** 208 * True if points should be recorded immediately. 209 */ 210 private static volatile boolean _transferImmediately = false; 211 212 /** 213 * Array for immediate transfer. 214 */ 215 private static volatile long[] _immediateTransfer = new long[COMPACT_DEBUG_RECORD_SIZE]; 216 217 /** 218 * True if scheduled replay has begun. 219 */ 220 private static volatile boolean _replaying = false; 221 222 /** 223 * True if the initial buffer for replay has been loaded. Since this starts out as false, the buffer will 224 * be loaded. 225 */ 226 private static volatile boolean _replayBufferLoaded = false; 227 228 /** 229 * Next object ID to be assigned. 230 */ 231 public static volatile long _nextObjectID = 0; 232 233 /** 234 * Next thread ID to be assigned. 235 */ 236 public static volatile long _nextThreadID = 0; 237 238 /** 239 * Message description. 240 */ 241 public static volatile String _message = null; 242 243 /** 244 * Number of running threads. 245 */ 246 public static volatile long _runningThreads = 0; 247 248 /** 249 * Adds a synchronization point to the list. 250 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would 251 * be the result. 252 * The monitor application has to check that no thread is currently holding the lock on SyncPointBuffer.class. 253 * Only then may it clear the list. 254 * @param sp synchronization point to add. 255 */ 256 public static synchronized void add(ISyncPoint sp) { 257 if (!_recording) { 258 return; 259 } 260 261 _syncPoints[_index] = sp; 262 _index = _index + 1; 263 if (SIZE==_index) { 264 transfer(); 265 } 266 } 267 268 /** 269 * Transfer and empty array. 270 * NOTE: The master should set a "method entry event" at the beginning of this method and transfer the array. 271 */ 272 public static void transfer() { 273 for (int i=0; i<SIZE; ++i) { 274 _syncPoints[i] = null; 275 } 276 _index = 0; 277 } 278 279 /** 280 * Adds a synchronization point to the compact list. 281 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would 282 * be the result. 283 * The monitor application has to check that no thread is currently holding the lock on SyncPointBuffer.class. 284 * Only then may it clear the list. 285 * @param code code for this event 286 * @param tid thread id 287 */ 288 public static synchronized void compactAdd(long code, long tid) { 289 if (!_recording) { 290 return; 291 } 292 293 if (_transferImmediately) { 294 _immediateTransfer[0] = tid; 295 _immediateTransfer[1] = code; 296 compactImmediateTransfer(); 297 } 298 else { 299 _compactSyncPoints[_compactIndex++] = tid; 300 _compactSyncPoints[_compactIndex++] = code; 301 if (COMPACT_SIZE<=_compactIndex) { 302 compactTransfer(); 303 } 304 } 305 } 306 307 /** 308 * Adds a synchronization point to the compact list. 309 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would 310 * be the result. 311 * The monitor application has to check that no thread is currently holding the lock on SyncPointBuffer.class. 312 * Only then may it clear the list. 313 * @param oid object id 314 * @param code code for this event 315 * @param tid thread id 316 * @param classIndex index of the class in the method database 317 * @param methodAndPC method index and PC 318 */ 319 public static synchronized void compactDebugAdd(long oid, long code, long tid, long classIndex, long methodAndPC) { 320 if (!_recording) { 321 return; 322 } 323 324 if (_transferImmediately) { 325 _immediateTransfer[0] = tid; 326 _immediateTransfer[1] = code; 327 _immediateTransfer[2] = classIndex; 328 _immediateTransfer[3] = methodAndPC; 329 _immediateTransfer[4] = oid; 330 compactImmediateTransfer(); 331 } 332 else { 333 _compactSyncPoints[_compactIndex++] = tid; 334 _compactSyncPoints[_compactIndex++] = code; 335 _compactSyncPoints[_compactIndex++] = classIndex; 336 _compactSyncPoints[_compactIndex++] = methodAndPC; 337 _compactSyncPoints[_compactIndex++] = oid; 338 if (COMPACT_SIZE-(COMPACT_SIZE%COMPACT_DEBUG_RECORD_SIZE)<=_compactIndex) { 339 compactTransfer(); 340 } 341 } 342 } 343 344 /** 345 * Transfer and empty compact array. 346 * NOTE: The master should set a "method entry event" at the beginning of this method and transfer the array. 347 */ 348 public static void compactTransfer() { 349 for (int i=0; i<COMPACT_SIZE; ++i) { 350 _compactSyncPoints[i] = 0; 351 } 352 } 353 354 /** 355 * Transfer immediately and empty compact array. 356 * NOTE: The master should set a "method entry event" at the beginning of this method and transfer the array. 357 */ 358 public static void compactImmediateTransfer() { 359 for (int i=0; i<COMPACT_DEBUG_RECORD_SIZE; ++i) { 360 _immediateTransfer[i] = 0; 361 } 362 } 363 364 /** 365 * Wait for this synchronization point in the compact list. 366 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would 367 * be the result. 368 * @param code code for this event 369 * @param tid thread id 370 */ 371 public static synchronized void compactWait(long code, long tid) { 372 compactWait(code, tid, -1, -1); 373 } 374 375 /** 376 * Notify the wait algorithm that a thread has ended and check if the next thread has to be woken up. 377 * <p/> 378 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would be the 379 * result. 380 * 381 * @param tid thread id 382 */ 383 public static synchronized void compactThreadExit(long tid) { 384 compactThreadExit(tid, -1, -1); 385 } 386 387 388 /** 389 * Wait for this synchronization point in the compact list. 390 * <p/> 391 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would be 392 * the result. 393 * 394 * @param code code for this event 395 * @param tid thread id 396 * @param classIndex index of the class in the method database 397 * @param methodAndPC method index and PC 398 */ 399 public static synchronized void compactWait(long code, long tid, long classIndex, long methodAndPC) { 400 if (!_replaying) { 401 return; 402 } 403 404 boolean oldReplaying = _replaying; 405 try { 406 _replaying = false; 407 408 monitorEnter(_waitAlgoObj); 409 setMessage(tid+" "+code+" - compactWait class="+Long.toHexString(classIndex)+" method="+ 410 Long.toHexString(methodAndPC >>> 32)+", PC="+Long.toHexString(methodAndPC & 0xFFFF)); 411 412 // If this is NOT the first sync point for this thread... 413 if (isOldThread()) { 414 // Advance the indices. 415 _replayIndex += 2; 416 ++_replayWaitIndex; 417 418 setMessage("\told thread"); 419 } 420 // Otherwise, if it was the first time... 421 else { 422 // Do not advance the indices. 423 424 // Set flag. 425 setOldThread(); 426 427 setMessage("\tnew thread, oldThread = "+isOldThread()); 428 } 429 430 // If the buffer has never been loaded, or if the index is at the end of the buffer... 431 if ((!_replayBufferLoaded) || (_replayIndex>=REPLAY_SIZE)) { 432 // Load the buffer and reset the indices. 433 replayTransfer(); 434 435 // Wake up all threads waiting for a buffer update. 436 synchronized(_newBufferWaitObj) { 437 _newBufferWaitObj.notifyAll(); 438 } 439 } 440 441 _replayIndex += 2; 442 ++_replayWaitIndex; 443 444 monitorExit(_waitAlgoObj); 445 /* 446 // If scheduled replay is enabled... 447 448 // monitorenter _waitAlgoObj (beginning of main synchronized block) 449 monitorEnter(_waitAlgoObj); 450 451 // If this is NOT the first sync point for this thread... 452 if (isOldThread()) { 453 // Advance the indices. 454 _replayIndex += 2; 455 ++_replayWaitIndex; 456 } 457 // Otherwise, if it was the first time... 458 else { 459 // Do not advance the indices. 460 461 // Set flag. 462 setOldThread(); 463 } 464 465 boolean exitMethod = false; 466 Object waitObject = null; 467 468 // Repeat this... ("RETRY" loop) 469 do { 470 // If the buffer has never been loaded, or if the index is at the end of the buffer... 471 if ((!_replayBufferLoaded) || (_replayIndex>=REPLAY_SIZE)) { 472 // Load the buffer and reset the indices. 473 replayTransfer(); 474 475 // Wake up all threads waiting for a buffer update. 476 synchronized(_newBufferWaitObj) { 477 _newBufferWaitObj.notifyAll(); 478 } 479 } 480 481 // If the current sync point marks the end of the schedule... 482 if (_replaySyncPoints[_replayIndex] == SP_END) { 483 // Disable scheduled replay. 484 _replaying = false; 485 486 // Wake up all threads waiting for a buffer update. 487 synchronized(_newBufferWaitObj) { 488 _newBufferWaitObj.notifyAll(); 489 } 490 491 // monitorexit _waitAlgoObj 492 monitorExit(_waitAlgoObj); 493 494 // Break out of the "RETRY" loop. 495 break; 496 } 497 498 boolean scan = false; 499 500 // If there's a thread waiting for this wait array entry... 501 if (_replayWaitArray[_replayWaitIndex] != null) { 502 // Notify it 503 Object o = _replayWaitArray[_replayWaitIndex]; 504 synchronized(o) { 505 o.notify(); 506 } 507 508 // Clear this entry in the wait array 509 _replayWaitArray[_replayWaitIndex] = null; 510 511 // Set a flag to scan ahead for the current sync point ("SCAN"). 512 scan = true; 513 514 // Do not advance indices. 515 } 516 else { 517 // If the current sync point in the array is the right one... 518 if (_replaySyncPoints[_replayIndex+1] == tid) { // right tid 519 if (_replaySyncPoints[_replayIndex] == code) { // right code { 520 // Do not advance indices. 521 522 // Allow the thread to exit the "RETRY" loop. 523 exitMethod = true; 524 } 525 else { 526 // Right tid, but wrong code 527 // oldReplaying = _replaying; 528 // _replaying = false; 529 // String msg = "Scanned ahead, found sync point " + _replaySyncPoints[_replayIndex] + 530 // " " + _replaySyncPoints[_replayIndex + 1] + " (wait array entry=" + 531 // _replayWaitArray[_replayWaitIndex] + ") at index " + 532 // (_replayIndex / 2) 533 // + ". Same thread, but different code or filled wait array entry!"; 534 // setMessage(msg); 535 // _replaying = oldReplaying; 536 } 537 } 538 // Otherwise... 539 else { 540 // Set a flag to scan ahead ("SCAN"). 541 scan = true; 542 } 543 } 544 // If the "SCAN" flag is set (i.e. either a thread was woken up 545 // or the current sync point did not match)... 546 if (scan) { 547 // Look for the sync points in the remaining part of the array. 548 int index = _replayIndex + COMPACT_RECORD_SIZE; 549 int waitIndex = _replayWaitIndex + 1; 550 while(index < REPLAY_SIZE) { 551 // If it could be found... 552 if (_replaySyncPoints[index + 1] == tid) { // right tid 553 if ((_replaySyncPoints[index] == code) && // right code 554 (_replayWaitArray[waitIndex] == null)) { // no one waiting for this one yet 555 // Insert a new object into corresponding slot of the wait array 556 // and set as "wait object" for this method. 557 waitObject = _replayWaitArray[waitIndex] = new Object(); 558 559 // Allow the thread to exit the "RETRY" loop. 560 exitMethod = true; 561 break; 562 } 563 else { 564 // right tid, but wrong code or someone already waiting for it 565 // oldReplaying = _replaying; 566 // _replaying = false; 567 // msg = "Scanned ahead, found sync point " + _replaySyncPoints[index] + 568 // " " + _replaySyncPoints[index + 1] + " (wait array entry=" + 569 // _replayWaitArray[waitIndex] + ") at index " + 570 // (index / 2) + ". Same thread, but different code or filled wait array entry!"; 571 // setMessage(msg); 572 // _replaying = oldReplaying; 573 } 574 } 575 index += COMPACT_RECORD_SIZE; 576 ++waitIndex; 577 } 578 579 // Otherwise, if it could not be found... 580 if (!exitMethod) { 581 // Set the new buffer wait object as "wait object" for this method. 582 waitObject = _newBufferWaitObj; 583 584 // Do not allow the thread to exit the "RETRY" loop. 585 } 586 587 // monitorenter waitObj (beginning of wait object synchronized block) 588 monitorEnter(waitObject); 589 } 590 591 // monitorexit _waitAlgoObj (end of main synchronized block) 592 monitorExit(_waitAlgoObj); 593 594 // If a "wait object" has been set for this method... 595 if (waitObject!=null) { 596 // Call wait() on that object (make sure to continue waiting if interrupted). 597 boolean stillWaiting = true; 598 do { 599 try { 600 waitObject.wait(); 601 stillWaiting = false; 602 } 603 catch(InterruptedException e) { 604 // do nothing, continue to wait 605 } 606 } while(stillWaiting); 607 608 // monitorexit waitObj (end of wait object synchronized block) 609 monitorExit(waitObject); 610 611 // Do not advance indices. 612 613 // If the thread is NOT allowed to exit the loop 614 // (i.e. it was waiting for a new buffer) AND scheduled replay is enabled... 615 if ((!exitMethod) && _replaying) { 616 // monitorenter _waitAlgoObj (beginning of main synchronized block for next iteration) 617 monitorEnter(_waitAlgoObj); 618 } 619 } 620 } while((!exitMethod) && _replaying); 621 // ...while the thread is not allowed to exit the loop and scheduled replay is enabled (end "RETRY" loop). 622 */ 623 } 624 finally { 625 _replaying = oldReplaying; 626 } 627 } 628 629 /** 630 * Notify the wait algorithm that a thread has ended and check if the next thread has to be woken up. 631 * NOTE: This method has to be synchronized, but it may NOT be instrumented as such! An infinite recursion would be 632 * the result. 633 * 634 * @param tid thread id 635 * @param classIndex index of the class in the method database 636 * @param methodAndPC method index and PC 637 */ 638 public static synchronized void compactThreadExit(long tid, long classIndex, long methodAndPC) { 639 if (!_replaying) { 640 return; 641 } 642 643 boolean oldReplaying = _replaying; 644 try { 645 _replaying = false; 646 setMessage(tid+" "+SP.THREADEXIT.intValue()+" - compactWait class="+Long.toHexString(classIndex)+ 647 " method="+Long.toHexString(methodAndPC >>> 32)+", PC="+Long.toHexString(methodAndPC & 0xFFFF)); 648 649 /* 650 // If scheduled replay is enabled... 651 652 // monitorenter _waitAlgoObj (beginning of main synchronized block) 653 monitorEnter(_waitAlgoObj); 654 655 // Advance the indices. 656 _replayIndex += 2; 657 ++_replayWaitIndex; 658 659 // If the index is at the end of the buffer... 660 if (_replayIndex>=REPLAY_SIZE) { 661 // Load the buffer and reset the indices. 662 replayTransfer(); 663 664 // Wake up all threads waiting for a buffer update. 665 synchronized(_newBufferWaitObj) { 666 _newBufferWaitObj.notifyAll(); 667 } 668 } 669 // Otherwise... 670 else { 671 Object o = _replayWaitArray[_replayWaitIndex]; 672 673 // If there's a thread waiting for this wait array entry... 674 if (o != null) { 675 // monitorenter _waitArray[index] (beginning of wait object synchronized block) 676 synchronized(o) { 677 // Notify it. 678 o.notify(); 679 } 680 } 681 // Otherwise, if the current sync point marks the end of the schedule... 682 else if (_replaySyncPoints[_replayIndex] == SP_END) { 683 // Disable scheduled replay. 684 _replaying = false; 685 686 // Wake up all threads waiting for a buffer update. 687 synchronized(_newBufferWaitObj) { 688 _newBufferWaitObj.notifyAll(); 689 } 690 } 691 // Otherwise... 692 else { 693 // Do nothing, because there's still a thread awake that will reach this sync point. 694 } 695 } 696 697 // monitorexit _waitAlgoObj (end of main synchronized block) 698 monitorExit(_waitAlgoObj); 699 */ 700 } 701 finally{ 702 _replaying = oldReplaying; 703 } 704 } 705 706 /** 707 * Transfer and and reset replay array. NOTE: The master should set a "method entry event" at the beginning of this 708 * method and transfer the array. 709 */ 710 public static void replayTransfer() { 711 _replayIndex = 0; 712 _replayWaitIndex = 0; 713 _replayBufferLoaded = true; 714 synchronized(_newBufferWaitObj) { 715 _newBufferWaitObj.notifyAll(); 716 } 717 } 718 719 /** 720 * Accessor for the recording flag. 721 * NOTE: This method has to be synchronized, but should not be instrumented. 722 * @return true if recording 723 */ 724 public static synchronized boolean isRecording() { 725 return _recording; 726 } 727 728 /** 729 * Mutator for the recording flag. 730 * NOTE: This method has to be synchronized, but should not be instrumented. 731 * @param recording true if recording should be enabled 732 */ 733 public static synchronized void setRecording(boolean recording) { 734 _recording = recording; 735 } 736 737 /** 738 * Notify the monitor application of a message. 739 * NOTE: The master should set a "method exit event" at the end of this method and process the error. 740 * @param message message string 741 */ 742 public static void setMessage(String message) { 743 _message = message; 744 } 745 746 /** 747 * Marker for monitorenter instructions. The invokestatic instruction should get replaced with a monitorenter. 748 * @param o object whose lock should be acquired 749 */ 750 public static void monitorEnter(Object o) { 751 // nothing to do 752 } 753 754 /** 755 * Marker for monitorexit instructions. The invokestatic instruction should get replaced with a monitorexit. 756 * @param o object whose lock should be released 757 */ 758 public static void monitorExit(Object o) { 759 // nothing to do 760 } 761 762 /** 763 * Marker for getting the value of the $$$oldThread$$$ field. The invokestatic instruction should get replaced with 764 * invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread; 765 * getfield java/lang/Thread.$$$oldThread$$$ 766 * @return value of the $$$oldThread$$$ field of the current thread (theoretically) 767 */ 768 public static boolean isOldThread() { 769 // nothing to do 770 return true; 771 } 772 773 /** 774 * Marker for setting $$$oldThread$$$ field. The invokestatic instruction should get replaced with 775 * iconst_1 776 * invokestatic java/lang/Thread.currentThread()Ljava/lang/Thread; 777 * setfield java/lang/Thread.$$$oldThread$$$ 778 */ 779 public static void setOldThread() { 780 // nothing to do 781 } 782 783 784 // 785 // Execution with random delays. 786 // 787 /** 788 * Length of the shortest delay in milliseconds. 789 * RANDOM_DELAY_MIN <= t < (RANDOM_DELAY_MIN + RANDOM_DELAY_MAGNITUDE) 790 */ 791 public static final int RANDOM_DELAY_MIN = 0; 792 793 /** 794 * Length of time in milliseconds between the shorted and the longest delay. 795 * RANDOM_DELAY_MIN <= t < (RANDOM_DELAY_MIN + RANDOM_DELAY_MAGNITUDE) 796 */ 797 public static final int RANDOM_DELAY_MAGNITUDE = 50; 798 799 /** 800 * Enable delay on thread start? 801 */ 802 public static boolean RANDOM_DELAY_THREAD_START = true; 803 804 /** 805 * Enable delay on thread exit? 806 */ 807 public static boolean RANDOM_DELAY_THREAD_EXIT = true; 808 809 /** 810 * Enable delay on thread run? 811 */ 812 public static boolean RANDOM_DELAY_THREAD_RUN = true; 813 814 /** 815 * Enable delay on thread join? 816 */ 817 public static boolean RANDOM_DELAY_THREAD_JOIN = true; 818 819 /** 820 * Enable delay before notify? 821 */ 822 public static boolean RANDOM_DELAY_PRE_NOTIFY = true; 823 824 /** 825 * Enable delay after notify? 826 */ 827 public static boolean RANDOM_DELAY_POST_NOTIFY = true; 828 829 /** 830 * Enable delay before wait? 831 */ 832 public static boolean RANDOM_DELAY_PRE_WAIT = true; 833 834 /** 835 * Enable delay after wait? 836 */ 837 public static boolean RANDOM_DELAY_POST_WAIT = true; 838 839 /** 840 * Enable delay before monitorenter/exit?? 841 */ 842 public static boolean RANDOM_DELAY_PRE_MONITOR = true; 843 844 /** 845 * Enable delay after monitorenter/exit? 846 */ 847 public static boolean RANDOM_DELAY_POST_MONITOR = true; 848 /** 849 * Sleep for a random amount of time, up to RANDOM_DELAY_MAGNITUDE milliseconds, if there is concurrency. 850 * @param delay true if delay is enabled 851 */ 852 public static void randomDelay(boolean delay) { 853 if (delay && (_runningThreads>1)) { 854 try { 855 Thread.sleep(((long)(RANDOM_DELAY_MIN + Math.random() * RANDOM_DELAY_MAGNITUDE))); 856 } 857 catch(InterruptedException e) { /* ignore */ } 858 } 859 } 860 861 /** 862 * Increment the number of running thread, and then sleep for a while if there is concurrency. 863 * @param delay true if delay is enabled 864 */ 865 public static void delayThreadStart(boolean delay) { 866 synchronized(SyncPointBuffer.class) { ++_runningThreads; } 867 randomDelay(delay); 868 } 869 870 /** 871 * Sleep for a while if there is concurrency, and then decrement the number of running threads. 872 * @param delay true if delay is enabled 873 */ 874 public static void delayThreadExit(boolean delay) { 875 randomDelay(delay); 876 synchronized(SyncPointBuffer.class) { --_runningThreads; } 877 } 878 879 /** 880 * Throw an exception if no other thread is alive anymore, otherwise sleep for a while. 881 * @param delay true if delay is enabled 882 */ 883 public static void delayObjectWait(boolean delay) { 884 synchronized(SyncPointBuffer.class) { 885 if (_runningThreads<=2) { 886 throw new AssertionError("Call to Object.wait with only one user thread alive (_runningThreads=="+_runningThreads+")"); 887 }; 888 } 889 randomDelay(delay); 890 } 891 892 893 // 894 // Execution with random yields. 895 // 896 /** 897 * Probability of a yield. 898 */ 899 public static float RANDOM_YIELD_PROB = 0.5f; 900 901 /** 902 * Enable yield on thread start? 903 */ 904 public static boolean RANDOM_YIELD_THREAD_START = true; 905 906 /** 907 * Enable yield on thread exit? 908 */ 909 public static boolean RANDOM_YIELD_THREAD_EXIT = true; 910 911 /** 912 * Enable yield on thread run? 913 */ 914 public static boolean RANDOM_YIELD_THREAD_RUN = true; 915 916 /** 917 * Enable yield on thread join? 918 */ 919 public static boolean RANDOM_YIELD_THREAD_JOIN = true; 920 921 /** 922 * Enable yield before notify? 923 */ 924 public static boolean RANDOM_YIELD_PRE_NOTIFY = true; 925 926 /** 927 * Enable yield after notify? 928 */ 929 public static boolean RANDOM_YIELD_POST_NOTIFY = true; 930 931 /** 932 * Enable yield before wait? 933 */ 934 public static boolean RANDOM_YIELD_PRE_WAIT = true; 935 936 /** 937 * Enable yield after wait? 938 */ 939 public static boolean RANDOM_YIELD_POST_WAIT = true; 940 941 /** 942 * Enable yield before monitorenter/exit?? 943 */ 944 public static boolean RANDOM_YIELD_PRE_MONITOR = true; 945 946 /** 947 * Enable yield after monitorenter/exit? 948 */ 949 public static boolean RANDOM_YIELD_POST_MONITOR = true; 950 951 /** 952 * Yield if random number < RANDOM_YIELD_PROB, but only if there is concurrency. 953 * @param yield true if yield is enabled 954 */ 955 public static void randomYield(boolean yield) { 956 if (yield && (_runningThreads>1)) { 957 // Math.random 958 if ((RANDOM_YIELD_PROB>=1) || ((RANDOM_YIELD_PROB>0) && (Math.random()<RANDOM_YIELD_PROB))) { 959 Thread.yield(); 960 } 961 } 962 } 963 964 /** 965 * Increment the number of running thread, and then do a random yield. 966 * @param yield true if yield is enabled 967 */ 968 public static void yieldThreadStart(boolean yield) { 969 synchronized(SyncPointBuffer.class) { ++_runningThreads; } 970 randomYield(yield); 971 } 972 973 /** 974 * Do a random yield, and then decrement the number of running threads. 975 * @param yield true if yield is enabled 976 */ 977 public static void yieldThreadExit(boolean yield) { 978 randomYield(yield); 979 synchronized(SyncPointBuffer.class) { --_runningThreads; } 980 } 981 982 /** 983 * Throw an exception if no other thread is alive anymore, otherwise do a random yield. 984 * @param yield true if yield is enabled 985 */ 986 public static void yieldObjectWait(boolean yield) { 987 synchronized(SyncPointBuffer.class) { 988 if (_runningThreads<=2) { 989 throw new AssertionError("Call to Object.wait with only one user thread alive (_runningThreads=="+_runningThreads+")"); 990 }; 991 } 992 randomYield(yield); 993 } 994 }