27 import java.util.Objects; |
27 import java.util.Objects; |
28 import java.util.concurrent.BrokenBarrierException; |
28 import java.util.concurrent.BrokenBarrierException; |
29 import java.util.concurrent.CyclicBarrier; |
29 import java.util.concurrent.CyclicBarrier; |
30 |
30 |
31 import com.oracle.java.testlibrary.Asserts; |
31 import com.oracle.java.testlibrary.Asserts; |
32 import com.oracle.java.testlibrary.Utils; |
32 import sun.hotspot.WhiteBox; |
33 import sun.misc.Unsafe; |
|
34 |
33 |
35 /** |
34 /** |
36 * Base class for different transactional execution abortion |
35 * Base class for different transactional execution abortion |
37 * provokers aimed to force abort due to specified reason. |
36 * provokers aimed to force abort due to specified reason. |
38 */ |
37 */ |
39 public abstract class AbortProvoker implements CompilableTest { |
38 public abstract class AbortProvoker implements CompilableTest { |
40 public static final long DEFAULT_ITERATIONS = 10000L; |
39 public static final long DEFAULT_ITERATIONS = 10000L; |
|
40 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); |
|
41 @SuppressWarnings("unused") |
|
42 private static int sharedState = 0; |
41 /** |
43 /** |
42 * Inflates monitor associated with object {@code monitor}. |
44 * Inflates monitor associated with object {@code monitor}. |
43 * Inflation is forced by entering the same monitor from |
45 * Inflation is forced by entering the same monitor from |
44 * two different threads. |
46 * two different threads. |
45 * |
47 * |
46 * @param monitor monitor to be inflated. |
48 * @param monitor monitor to be inflated. |
47 * @return inflated monitor. |
49 * @return inflated monitor. |
48 * @throws Exception if something went wrong. |
50 * @throws Exception if something went wrong. |
49 */ |
51 */ |
50 public static Object inflateMonitor(Object monitor) throws Exception { |
52 public static Object inflateMonitor(Object monitor) throws Exception { |
51 Unsafe unsafe = Utils.getUnsafe(); |
|
52 CyclicBarrier barrier = new CyclicBarrier(2); |
53 CyclicBarrier barrier = new CyclicBarrier(2); |
53 |
54 |
54 Runnable inflatingRunnable = () -> { |
55 Runnable inflatingRunnable = () -> { |
55 unsafe.monitorEnter(monitor); |
56 synchronized (monitor) { |
56 try { |
57 try { |
57 barrier.await(); |
58 barrier.await(); |
58 barrier.await(); |
59 } catch (BrokenBarrierException | InterruptedException e) { |
59 } catch (InterruptedException | BrokenBarrierException e) { |
60 throw new RuntimeException( |
60 throw new RuntimeException( |
61 "Synchronization issue occurred.", e); |
61 "Synchronization issue occurred.", e); |
62 } |
62 } finally { |
63 try { |
63 unsafe.monitorExit(monitor); |
64 monitor.wait(); |
|
65 } catch (InterruptedException e) { |
|
66 throw new AssertionError("The thread waiting on an" |
|
67 + " inflated monitor was interrupted, thus test" |
|
68 + " results may be incorrect.", e); |
|
69 } |
64 } |
70 } |
65 }; |
71 }; |
66 |
72 |
67 Thread t = new Thread(inflatingRunnable); |
73 Thread t = new Thread(inflatingRunnable); |
|
74 t.setDaemon(true); |
68 t.start(); |
75 t.start(); |
69 // Wait until thread t enters the monitor. |
76 // Wait until thread t enters the monitor. |
70 barrier.await(); |
77 barrier.await(); |
71 // At this point monitor will be owned by thread t, |
78 synchronized (monitor) { |
72 // so our attempt to enter the same monitor will force |
79 // At this point thread t is already waiting on the monitor. |
73 // monitor inflation. |
80 // Modifying static field just to avoid lock's elimination. |
74 Asserts.assertFalse(unsafe.tryMonitorEnter(monitor), |
81 sharedState++; |
75 "Not supposed to enter the monitor first"); |
82 } |
76 barrier.await(); |
83 verifyMonitorState(monitor, true /* inflated */); |
77 t.join(); |
|
78 return monitor; |
84 return monitor; |
79 } |
85 } |
80 |
86 |
|
87 /** |
|
88 * Verifies that {@code monitor} is a stack-lock or inflated lock depending |
|
89 * on {@code shouldBeInflated} value. If {@code monitor} is inflated while |
|
90 * it is expected that it should be a stack-lock, then this method attempts |
|
91 * to deflate it by forcing a safepoint and then verifies the state once |
|
92 * again. |
|
93 * |
|
94 * @param monitor monitor to be verified. |
|
95 * @param shouldBeInflated flag indicating whether or not monitor is |
|
96 * expected to be inflated. |
|
97 * @throws RuntimeException if the {@code monitor} in a wrong state. |
|
98 */ |
|
99 public static void verifyMonitorState(Object monitor, |
|
100 boolean shouldBeInflated) { |
|
101 if (!shouldBeInflated && WHITE_BOX.isMonitorInflated(monitor)) { |
|
102 WHITE_BOX.forceSafepoint(); |
|
103 } |
|
104 Asserts.assertEQ(WHITE_BOX.isMonitorInflated(monitor), shouldBeInflated, |
|
105 "Monitor in a wrong state."); |
|
106 } |
|
107 /** |
|
108 * Verifies that monitor used by the {@code provoker} is a stack-lock or |
|
109 * inflated lock depending on {@code shouldBeInflated} value. If such |
|
110 * monitor is inflated while it is expected that it should be a stack-lock, |
|
111 * then this method attempts to deflate it by forcing a safepoint and then |
|
112 * verifies the state once again. |
|
113 * |
|
114 * @param provoker AbortProvoker whose monitor's state should be verified. |
|
115 * @param shouldBeInflated flag indicating whether or not monitor is |
|
116 * expected to be inflated. |
|
117 * @throws RuntimeException if the {@code monitor} in a wrong state. |
|
118 */ |
|
119 public static void verifyMonitorState(AbortProvoker provoker, |
|
120 boolean shouldBeInflated) { |
|
121 verifyMonitorState(provoker.monitor, shouldBeInflated); |
|
122 } |
81 |
123 |
82 /** |
124 /** |
83 * Get instance of specified AbortProvoker, inflate associated monitor |
125 * Get instance of specified AbortProvoker, inflate associated monitor |
84 * if needed and then invoke forceAbort method in a loop. |
126 * if needed and then invoke forceAbort method in a loop. |
85 * |
127 * |