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 }