annotate src/share/vm/runtime/synchronizer.cpp @ 1721:413ad0331a0c

6977924: Changes for 6975078 produce build error with certain gcc versions Summary: The changes introduced for 6975078 assign badHeapOopVal to the _allocation field in the ResourceObj class. In 32 bit linux builds with certain versions of gcc this assignment will be flagged as an error while compiling allocation.cpp. In 32 bit builds the constant value badHeapOopVal (which is cast to an intptr_t) is negative. The _allocation field is typed as an unsigned intptr_t and gcc catches this as an error. Reviewed-by: jcoomes, ysr, phh
author johnc
date Wed, 18 Aug 2010 10:59:06 -0700
parents bfc89697cccb
children fa83ab460c54
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1 /*
1552
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 702
diff changeset
2 * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
18 *
1552
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 702
diff changeset
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 702
diff changeset
20 * or visit www.oracle.com if you need additional information or have any
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 702
diff changeset
21 * questions.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
a61af66fc99e Initial load
duke
parents:
diff changeset
25 # include "incls/_precompiled.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
26 # include "incls/_synchronizer.cpp.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
27
a61af66fc99e Initial load
duke
parents:
diff changeset
28 #if defined(__GNUC__) && !defined(IA64)
a61af66fc99e Initial load
duke
parents:
diff changeset
29 // Need to inhibit inlining for older versions of GCC to avoid build-time failures
a61af66fc99e Initial load
duke
parents:
diff changeset
30 #define ATTR __attribute__((noinline))
a61af66fc99e Initial load
duke
parents:
diff changeset
31 #else
a61af66fc99e Initial load
duke
parents:
diff changeset
32 #define ATTR
a61af66fc99e Initial load
duke
parents:
diff changeset
33 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
34
a61af66fc99e Initial load
duke
parents:
diff changeset
35 // Native markword accessors for synchronization and hashCode().
a61af66fc99e Initial load
duke
parents:
diff changeset
36 //
a61af66fc99e Initial load
duke
parents:
diff changeset
37 // The "core" versions of monitor enter and exit reside in this file.
a61af66fc99e Initial load
duke
parents:
diff changeset
38 // The interpreter and compilers contain specialized transliterated
a61af66fc99e Initial load
duke
parents:
diff changeset
39 // variants of the enter-exit fast-path operations. See i486.ad fast_lock(),
a61af66fc99e Initial load
duke
parents:
diff changeset
40 // for instance. If you make changes here, make sure to modify the
a61af66fc99e Initial load
duke
parents:
diff changeset
41 // interpreter, and both C1 and C2 fast-path inline locking code emission.
a61af66fc99e Initial load
duke
parents:
diff changeset
42 //
a61af66fc99e Initial load
duke
parents:
diff changeset
43 // TODO: merge the objectMonitor and synchronizer classes.
a61af66fc99e Initial load
duke
parents:
diff changeset
44 //
a61af66fc99e Initial load
duke
parents:
diff changeset
45 // -----------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
46
a61af66fc99e Initial load
duke
parents:
diff changeset
47 #ifdef DTRACE_ENABLED
a61af66fc99e Initial load
duke
parents:
diff changeset
48
a61af66fc99e Initial load
duke
parents:
diff changeset
49 // Only bother with this argument setup if dtrace is available
a61af66fc99e Initial load
duke
parents:
diff changeset
50 // TODO-FIXME: probes should not fire when caller is _blocked. assert() accordingly.
a61af66fc99e Initial load
duke
parents:
diff changeset
51
a61af66fc99e Initial load
duke
parents:
diff changeset
52 HS_DTRACE_PROBE_DECL5(hotspot, monitor__wait,
a61af66fc99e Initial load
duke
parents:
diff changeset
53 jlong, uintptr_t, char*, int, long);
a61af66fc99e Initial load
duke
parents:
diff changeset
54 HS_DTRACE_PROBE_DECL4(hotspot, monitor__waited,
a61af66fc99e Initial load
duke
parents:
diff changeset
55 jlong, uintptr_t, char*, int);
a61af66fc99e Initial load
duke
parents:
diff changeset
56 HS_DTRACE_PROBE_DECL4(hotspot, monitor__notify,
a61af66fc99e Initial load
duke
parents:
diff changeset
57 jlong, uintptr_t, char*, int);
a61af66fc99e Initial load
duke
parents:
diff changeset
58 HS_DTRACE_PROBE_DECL4(hotspot, monitor__notifyAll,
a61af66fc99e Initial load
duke
parents:
diff changeset
59 jlong, uintptr_t, char*, int);
a61af66fc99e Initial load
duke
parents:
diff changeset
60 HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__enter,
a61af66fc99e Initial load
duke
parents:
diff changeset
61 jlong, uintptr_t, char*, int);
a61af66fc99e Initial load
duke
parents:
diff changeset
62 HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__entered,
a61af66fc99e Initial load
duke
parents:
diff changeset
63 jlong, uintptr_t, char*, int);
a61af66fc99e Initial load
duke
parents:
diff changeset
64 HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__exit,
a61af66fc99e Initial load
duke
parents:
diff changeset
65 jlong, uintptr_t, char*, int);
a61af66fc99e Initial load
duke
parents:
diff changeset
66
a61af66fc99e Initial load
duke
parents:
diff changeset
67 #define DTRACE_MONITOR_PROBE_COMMON(klassOop, thread) \
a61af66fc99e Initial load
duke
parents:
diff changeset
68 char* bytes = NULL; \
a61af66fc99e Initial load
duke
parents:
diff changeset
69 int len = 0; \
a61af66fc99e Initial load
duke
parents:
diff changeset
70 jlong jtid = SharedRuntime::get_java_tid(thread); \
a61af66fc99e Initial load
duke
parents:
diff changeset
71 symbolOop klassname = ((oop)(klassOop))->klass()->klass_part()->name(); \
a61af66fc99e Initial load
duke
parents:
diff changeset
72 if (klassname != NULL) { \
a61af66fc99e Initial load
duke
parents:
diff changeset
73 bytes = (char*)klassname->bytes(); \
a61af66fc99e Initial load
duke
parents:
diff changeset
74 len = klassname->utf8_length(); \
a61af66fc99e Initial load
duke
parents:
diff changeset
75 }
a61af66fc99e Initial load
duke
parents:
diff changeset
76
a61af66fc99e Initial load
duke
parents:
diff changeset
77 #define DTRACE_MONITOR_WAIT_PROBE(monitor, klassOop, thread, millis) \
a61af66fc99e Initial load
duke
parents:
diff changeset
78 { \
a61af66fc99e Initial load
duke
parents:
diff changeset
79 if (DTraceMonitorProbes) { \
a61af66fc99e Initial load
duke
parents:
diff changeset
80 DTRACE_MONITOR_PROBE_COMMON(klassOop, thread); \
a61af66fc99e Initial load
duke
parents:
diff changeset
81 HS_DTRACE_PROBE5(hotspot, monitor__wait, jtid, \
a61af66fc99e Initial load
duke
parents:
diff changeset
82 (monitor), bytes, len, (millis)); \
a61af66fc99e Initial load
duke
parents:
diff changeset
83 } \
a61af66fc99e Initial load
duke
parents:
diff changeset
84 }
a61af66fc99e Initial load
duke
parents:
diff changeset
85
a61af66fc99e Initial load
duke
parents:
diff changeset
86 #define DTRACE_MONITOR_PROBE(probe, monitor, klassOop, thread) \
a61af66fc99e Initial load
duke
parents:
diff changeset
87 { \
a61af66fc99e Initial load
duke
parents:
diff changeset
88 if (DTraceMonitorProbes) { \
a61af66fc99e Initial load
duke
parents:
diff changeset
89 DTRACE_MONITOR_PROBE_COMMON(klassOop, thread); \
a61af66fc99e Initial load
duke
parents:
diff changeset
90 HS_DTRACE_PROBE4(hotspot, monitor__##probe, jtid, \
a61af66fc99e Initial load
duke
parents:
diff changeset
91 (uintptr_t)(monitor), bytes, len); \
a61af66fc99e Initial load
duke
parents:
diff changeset
92 } \
a61af66fc99e Initial load
duke
parents:
diff changeset
93 }
a61af66fc99e Initial load
duke
parents:
diff changeset
94
a61af66fc99e Initial load
duke
parents:
diff changeset
95 #else // ndef DTRACE_ENABLED
a61af66fc99e Initial load
duke
parents:
diff changeset
96
a61af66fc99e Initial load
duke
parents:
diff changeset
97 #define DTRACE_MONITOR_WAIT_PROBE(klassOop, thread, millis, mon) {;}
a61af66fc99e Initial load
duke
parents:
diff changeset
98 #define DTRACE_MONITOR_PROBE(probe, klassOop, thread, mon) {;}
a61af66fc99e Initial load
duke
parents:
diff changeset
99
a61af66fc99e Initial load
duke
parents:
diff changeset
100 #endif // ndef DTRACE_ENABLED
a61af66fc99e Initial load
duke
parents:
diff changeset
101
a61af66fc99e Initial load
duke
parents:
diff changeset
102 // ObjectWaiter serves as a "proxy" or surrogate thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
103 // TODO-FIXME: Eliminate ObjectWaiter and use the thread-specific
a61af66fc99e Initial load
duke
parents:
diff changeset
104 // ParkEvent instead. Beware, however, that the JVMTI code
a61af66fc99e Initial load
duke
parents:
diff changeset
105 // knows about ObjectWaiters, so we'll have to reconcile that code.
a61af66fc99e Initial load
duke
parents:
diff changeset
106 // See next_waiter(), first_waiter(), etc.
a61af66fc99e Initial load
duke
parents:
diff changeset
107
a61af66fc99e Initial load
duke
parents:
diff changeset
108 class ObjectWaiter : public StackObj {
a61af66fc99e Initial load
duke
parents:
diff changeset
109 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
110 enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
a61af66fc99e Initial load
duke
parents:
diff changeset
111 enum Sorted { PREPEND, APPEND, SORTED } ;
a61af66fc99e Initial load
duke
parents:
diff changeset
112 ObjectWaiter * volatile _next;
a61af66fc99e Initial load
duke
parents:
diff changeset
113 ObjectWaiter * volatile _prev;
a61af66fc99e Initial load
duke
parents:
diff changeset
114 Thread* _thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
115 ParkEvent * _event;
a61af66fc99e Initial load
duke
parents:
diff changeset
116 volatile int _notified ;
a61af66fc99e Initial load
duke
parents:
diff changeset
117 volatile TStates TState ;
a61af66fc99e Initial load
duke
parents:
diff changeset
118 Sorted _Sorted ; // List placement disposition
a61af66fc99e Initial load
duke
parents:
diff changeset
119 bool _active ; // Contention monitoring is enabled
a61af66fc99e Initial load
duke
parents:
diff changeset
120 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
121 ObjectWaiter(Thread* thread) {
a61af66fc99e Initial load
duke
parents:
diff changeset
122 _next = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
123 _prev = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
124 _notified = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
125 TState = TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
126 _thread = thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
127 _event = thread->_ParkEvent ;
a61af66fc99e Initial load
duke
parents:
diff changeset
128 _active = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
129 assert (_event != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
130 }
a61af66fc99e Initial load
duke
parents:
diff changeset
131
a61af66fc99e Initial load
duke
parents:
diff changeset
132 void wait_reenter_begin(ObjectMonitor *mon) {
a61af66fc99e Initial load
duke
parents:
diff changeset
133 JavaThread *jt = (JavaThread *)this->_thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
134 _active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
a61af66fc99e Initial load
duke
parents:
diff changeset
135 }
a61af66fc99e Initial load
duke
parents:
diff changeset
136
a61af66fc99e Initial load
duke
parents:
diff changeset
137 void wait_reenter_end(ObjectMonitor *mon) {
a61af66fc99e Initial load
duke
parents:
diff changeset
138 JavaThread *jt = (JavaThread *)this->_thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
139 JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
a61af66fc99e Initial load
duke
parents:
diff changeset
140 }
a61af66fc99e Initial load
duke
parents:
diff changeset
141 };
a61af66fc99e Initial load
duke
parents:
diff changeset
142
a61af66fc99e Initial load
duke
parents:
diff changeset
143 enum ManifestConstants {
a61af66fc99e Initial load
duke
parents:
diff changeset
144 ClearResponsibleAtSTW = 0,
a61af66fc99e Initial load
duke
parents:
diff changeset
145 MaximumRecheckInterval = 1000
a61af66fc99e Initial load
duke
parents:
diff changeset
146 } ;
a61af66fc99e Initial load
duke
parents:
diff changeset
147
a61af66fc99e Initial load
duke
parents:
diff changeset
148
a61af66fc99e Initial load
duke
parents:
diff changeset
149 #undef TEVENT
a61af66fc99e Initial load
duke
parents:
diff changeset
150 #define TEVENT(nom) {if (SyncVerbose) FEVENT(nom); }
a61af66fc99e Initial load
duke
parents:
diff changeset
151
a61af66fc99e Initial load
duke
parents:
diff changeset
152 #define FEVENT(nom) { static volatile int ctr = 0 ; int v = ++ctr ; if ((v & (v-1)) == 0) { ::printf (#nom " : %d \n", v); ::fflush(stdout); }}
a61af66fc99e Initial load
duke
parents:
diff changeset
153
a61af66fc99e Initial load
duke
parents:
diff changeset
154 #undef TEVENT
a61af66fc99e Initial load
duke
parents:
diff changeset
155 #define TEVENT(nom) {;}
a61af66fc99e Initial load
duke
parents:
diff changeset
156
a61af66fc99e Initial load
duke
parents:
diff changeset
157 // Performance concern:
a61af66fc99e Initial load
duke
parents:
diff changeset
158 // OrderAccess::storestore() calls release() which STs 0 into the global volatile
a61af66fc99e Initial load
duke
parents:
diff changeset
159 // OrderAccess::Dummy variable. This store is unnecessary for correctness.
a61af66fc99e Initial load
duke
parents:
diff changeset
160 // Many threads STing into a common location causes considerable cache migration
a61af66fc99e Initial load
duke
parents:
diff changeset
161 // or "sloshing" on large SMP system. As such, I avoid using OrderAccess::storestore()
a61af66fc99e Initial load
duke
parents:
diff changeset
162 // until it's repaired. In some cases OrderAccess::fence() -- which incurs local
a61af66fc99e Initial load
duke
parents:
diff changeset
163 // latency on the executing processor -- is a better choice as it scales on SMP
a61af66fc99e Initial load
duke
parents:
diff changeset
164 // systems. See http://blogs.sun.com/dave/entry/biased_locking_in_hotspot for a
a61af66fc99e Initial load
duke
parents:
diff changeset
165 // discussion of coherency costs. Note that all our current reference platforms
a61af66fc99e Initial load
duke
parents:
diff changeset
166 // provide strong ST-ST order, so the issue is moot on IA32, x64, and SPARC.
a61af66fc99e Initial load
duke
parents:
diff changeset
167 //
a61af66fc99e Initial load
duke
parents:
diff changeset
168 // As a general policy we use "volatile" to control compiler-based reordering
a61af66fc99e Initial load
duke
parents:
diff changeset
169 // and explicit fences (barriers) to control for architectural reordering performed
a61af66fc99e Initial load
duke
parents:
diff changeset
170 // by the CPU(s) or platform.
a61af66fc99e Initial load
duke
parents:
diff changeset
171
a61af66fc99e Initial load
duke
parents:
diff changeset
172 static int MBFence (int x) { OrderAccess::fence(); return x; }
a61af66fc99e Initial load
duke
parents:
diff changeset
173
a61af66fc99e Initial load
duke
parents:
diff changeset
174 struct SharedGlobals {
a61af66fc99e Initial load
duke
parents:
diff changeset
175 // These are highly shared mostly-read variables.
a61af66fc99e Initial load
duke
parents:
diff changeset
176 // To avoid false-sharing they need to be the sole occupants of a $ line.
a61af66fc99e Initial load
duke
parents:
diff changeset
177 double padPrefix [8];
a61af66fc99e Initial load
duke
parents:
diff changeset
178 volatile int stwRandom ;
a61af66fc99e Initial load
duke
parents:
diff changeset
179 volatile int stwCycle ;
a61af66fc99e Initial load
duke
parents:
diff changeset
180
a61af66fc99e Initial load
duke
parents:
diff changeset
181 // Hot RW variables -- Sequester to avoid false-sharing
a61af66fc99e Initial load
duke
parents:
diff changeset
182 double padSuffix [16];
a61af66fc99e Initial load
duke
parents:
diff changeset
183 volatile int hcSequence ;
a61af66fc99e Initial load
duke
parents:
diff changeset
184 double padFinal [8] ;
a61af66fc99e Initial load
duke
parents:
diff changeset
185 } ;
a61af66fc99e Initial load
duke
parents:
diff changeset
186
a61af66fc99e Initial load
duke
parents:
diff changeset
187 static SharedGlobals GVars ;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
188 static int MonitorScavengeThreshold = 1000000 ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
189 static volatile int ForceMonitorScavenge = 0 ; // Scavenge required and pending
0
a61af66fc99e Initial load
duke
parents:
diff changeset
190
a61af66fc99e Initial load
duke
parents:
diff changeset
191
a61af66fc99e Initial load
duke
parents:
diff changeset
192 // Tunables ...
a61af66fc99e Initial load
duke
parents:
diff changeset
193 // The knob* variables are effectively final. Once set they should
a61af66fc99e Initial load
duke
parents:
diff changeset
194 // never be modified hence. Consider using __read_mostly with GCC.
a61af66fc99e Initial load
duke
parents:
diff changeset
195
a61af66fc99e Initial load
duke
parents:
diff changeset
196 static int Knob_LogSpins = 0 ; // enable jvmstat tally for spins
a61af66fc99e Initial load
duke
parents:
diff changeset
197 static int Knob_HandOff = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
198 static int Knob_Verbose = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
199 static int Knob_ReportSettings = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
200
a61af66fc99e Initial load
duke
parents:
diff changeset
201 static int Knob_SpinLimit = 5000 ; // derived by an external tool -
a61af66fc99e Initial load
duke
parents:
diff changeset
202 static int Knob_SpinBase = 0 ; // Floor AKA SpinMin
a61af66fc99e Initial load
duke
parents:
diff changeset
203 static int Knob_SpinBackOff = 0 ; // spin-loop backoff
a61af66fc99e Initial load
duke
parents:
diff changeset
204 static int Knob_CASPenalty = -1 ; // Penalty for failed CAS
a61af66fc99e Initial load
duke
parents:
diff changeset
205 static int Knob_OXPenalty = -1 ; // Penalty for observed _owner change
a61af66fc99e Initial load
duke
parents:
diff changeset
206 static int Knob_SpinSetSucc = 1 ; // spinners set the _succ field
a61af66fc99e Initial load
duke
parents:
diff changeset
207 static int Knob_SpinEarly = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
208 static int Knob_SuccEnabled = 1 ; // futile wake throttling
a61af66fc99e Initial load
duke
parents:
diff changeset
209 static int Knob_SuccRestrict = 0 ; // Limit successors + spinners to at-most-one
a61af66fc99e Initial load
duke
parents:
diff changeset
210 static int Knob_MaxSpinners = -1 ; // Should be a function of # CPUs
a61af66fc99e Initial load
duke
parents:
diff changeset
211 static int Knob_Bonus = 100 ; // spin success bonus
a61af66fc99e Initial load
duke
parents:
diff changeset
212 static int Knob_BonusB = 100 ; // spin success bonus
a61af66fc99e Initial load
duke
parents:
diff changeset
213 static int Knob_Penalty = 200 ; // spin failure penalty
a61af66fc99e Initial load
duke
parents:
diff changeset
214 static int Knob_Poverty = 1000 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
215 static int Knob_SpinAfterFutile = 1 ; // Spin after returning from park()
a61af66fc99e Initial load
duke
parents:
diff changeset
216 static int Knob_FixedSpin = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
217 static int Knob_OState = 3 ; // Spinner checks thread state of _owner
a61af66fc99e Initial load
duke
parents:
diff changeset
218 static int Knob_UsePause = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
219 static int Knob_ExitPolicy = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
220 static int Knob_PreSpin = 10 ; // 20-100 likely better
a61af66fc99e Initial load
duke
parents:
diff changeset
221 static int Knob_ResetEvent = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
222 static int BackOffMask = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
223
a61af66fc99e Initial load
duke
parents:
diff changeset
224 static int Knob_FastHSSEC = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
225 static int Knob_MoveNotifyee = 2 ; // notify() - disposition of notifyee
a61af66fc99e Initial load
duke
parents:
diff changeset
226 static int Knob_QMode = 0 ; // EntryList-cxq policy - queue discipline
a61af66fc99e Initial load
duke
parents:
diff changeset
227 static volatile int InitDone = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
228
a61af66fc99e Initial load
duke
parents:
diff changeset
229
a61af66fc99e Initial load
duke
parents:
diff changeset
230 // hashCode() generation :
a61af66fc99e Initial load
duke
parents:
diff changeset
231 //
a61af66fc99e Initial load
duke
parents:
diff changeset
232 // Possibilities:
a61af66fc99e Initial load
duke
parents:
diff changeset
233 // * MD5Digest of {obj,stwRandom}
a61af66fc99e Initial load
duke
parents:
diff changeset
234 // * CRC32 of {obj,stwRandom} or any linear-feedback shift register function.
a61af66fc99e Initial load
duke
parents:
diff changeset
235 // * A DES- or AES-style SBox[] mechanism
a61af66fc99e Initial load
duke
parents:
diff changeset
236 // * One of the Phi-based schemes, such as:
a61af66fc99e Initial load
duke
parents:
diff changeset
237 // 2654435761 = 2^32 * Phi (golden ratio)
a61af66fc99e Initial load
duke
parents:
diff changeset
238 // HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stwRandom ;
a61af66fc99e Initial load
duke
parents:
diff changeset
239 // * A variation of Marsaglia's shift-xor RNG scheme.
a61af66fc99e Initial load
duke
parents:
diff changeset
240 // * (obj ^ stwRandom) is appealing, but can result
a61af66fc99e Initial load
duke
parents:
diff changeset
241 // in undesirable regularity in the hashCode values of adjacent objects
a61af66fc99e Initial load
duke
parents:
diff changeset
242 // (objects allocated back-to-back, in particular). This could potentially
a61af66fc99e Initial load
duke
parents:
diff changeset
243 // result in hashtable collisions and reduced hashtable efficiency.
a61af66fc99e Initial load
duke
parents:
diff changeset
244 // There are simple ways to "diffuse" the middle address bits over the
a61af66fc99e Initial load
duke
parents:
diff changeset
245 // generated hashCode values:
a61af66fc99e Initial load
duke
parents:
diff changeset
246 //
a61af66fc99e Initial load
duke
parents:
diff changeset
247
a61af66fc99e Initial load
duke
parents:
diff changeset
248 static inline intptr_t get_next_hash(Thread * Self, oop obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
249 intptr_t value = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
250 if (hashCode == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
251 // This form uses an unguarded global Park-Miller RNG,
a61af66fc99e Initial load
duke
parents:
diff changeset
252 // so it's possible for two threads to race and generate the same RNG.
a61af66fc99e Initial load
duke
parents:
diff changeset
253 // On MP system we'll have lots of RW access to a global, so the
a61af66fc99e Initial load
duke
parents:
diff changeset
254 // mechanism induces lots of coherency traffic.
a61af66fc99e Initial load
duke
parents:
diff changeset
255 value = os::random() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
256 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
257 if (hashCode == 1) {
a61af66fc99e Initial load
duke
parents:
diff changeset
258 // This variation has the property of being stable (idempotent)
a61af66fc99e Initial load
duke
parents:
diff changeset
259 // between STW operations. This can be useful in some of the 1-0
a61af66fc99e Initial load
duke
parents:
diff changeset
260 // synchronization schemes.
a61af66fc99e Initial load
duke
parents:
diff changeset
261 intptr_t addrBits = intptr_t(obj) >> 3 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
262 value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
a61af66fc99e Initial load
duke
parents:
diff changeset
263 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
264 if (hashCode == 2) {
a61af66fc99e Initial load
duke
parents:
diff changeset
265 value = 1 ; // for sensitivity testing
a61af66fc99e Initial load
duke
parents:
diff changeset
266 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
267 if (hashCode == 3) {
a61af66fc99e Initial load
duke
parents:
diff changeset
268 value = ++GVars.hcSequence ;
a61af66fc99e Initial load
duke
parents:
diff changeset
269 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
270 if (hashCode == 4) {
a61af66fc99e Initial load
duke
parents:
diff changeset
271 value = intptr_t(obj) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
272 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
273 // Marsaglia's xor-shift scheme with thread-specific state
a61af66fc99e Initial load
duke
parents:
diff changeset
274 // This is probably the best overall implementation -- we'll
a61af66fc99e Initial load
duke
parents:
diff changeset
275 // likely make this the default in future releases.
a61af66fc99e Initial load
duke
parents:
diff changeset
276 unsigned t = Self->_hashStateX ;
a61af66fc99e Initial load
duke
parents:
diff changeset
277 t ^= (t << 11) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
278 Self->_hashStateX = Self->_hashStateY ;
a61af66fc99e Initial load
duke
parents:
diff changeset
279 Self->_hashStateY = Self->_hashStateZ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
280 Self->_hashStateZ = Self->_hashStateW ;
a61af66fc99e Initial load
duke
parents:
diff changeset
281 unsigned v = Self->_hashStateW ;
a61af66fc99e Initial load
duke
parents:
diff changeset
282 v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
283 Self->_hashStateW = v ;
a61af66fc99e Initial load
duke
parents:
diff changeset
284 value = v ;
a61af66fc99e Initial load
duke
parents:
diff changeset
285 }
a61af66fc99e Initial load
duke
parents:
diff changeset
286
a61af66fc99e Initial load
duke
parents:
diff changeset
287 value &= markOopDesc::hash_mask;
a61af66fc99e Initial load
duke
parents:
diff changeset
288 if (value == 0) value = 0xBAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
289 assert (value != markOopDesc::no_hash, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
290 TEVENT (hashCode: GENERATE) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
291 return value;
a61af66fc99e Initial load
duke
parents:
diff changeset
292 }
a61af66fc99e Initial load
duke
parents:
diff changeset
293
a61af66fc99e Initial load
duke
parents:
diff changeset
294 void BasicLock::print_on(outputStream* st) const {
a61af66fc99e Initial load
duke
parents:
diff changeset
295 st->print("monitor");
a61af66fc99e Initial load
duke
parents:
diff changeset
296 }
a61af66fc99e Initial load
duke
parents:
diff changeset
297
a61af66fc99e Initial load
duke
parents:
diff changeset
298 void BasicLock::move_to(oop obj, BasicLock* dest) {
a61af66fc99e Initial load
duke
parents:
diff changeset
299 // Check to see if we need to inflate the lock. This is only needed
a61af66fc99e Initial load
duke
parents:
diff changeset
300 // if an object is locked using "this" lightweight monitor. In that
a61af66fc99e Initial load
duke
parents:
diff changeset
301 // case, the displaced_header() is unlocked, because the
a61af66fc99e Initial load
duke
parents:
diff changeset
302 // displaced_header() contains the header for the originally unlocked
a61af66fc99e Initial load
duke
parents:
diff changeset
303 // object. However the object could have already been inflated. But it
a61af66fc99e Initial load
duke
parents:
diff changeset
304 // does not matter, the inflation will just a no-op. For other cases,
a61af66fc99e Initial load
duke
parents:
diff changeset
305 // the displaced header will be either 0x0 or 0x3, which are location
a61af66fc99e Initial load
duke
parents:
diff changeset
306 // independent, therefore the BasicLock is free to move.
a61af66fc99e Initial load
duke
parents:
diff changeset
307 //
a61af66fc99e Initial load
duke
parents:
diff changeset
308 // During OSR we may need to relocate a BasicLock (which contains a
a61af66fc99e Initial load
duke
parents:
diff changeset
309 // displaced word) from a location in an interpreter frame to a
a61af66fc99e Initial load
duke
parents:
diff changeset
310 // new location in a compiled frame. "this" refers to the source
a61af66fc99e Initial load
duke
parents:
diff changeset
311 // basiclock in the interpreter frame. "dest" refers to the destination
a61af66fc99e Initial load
duke
parents:
diff changeset
312 // basiclock in the new compiled frame. We *always* inflate in move_to().
a61af66fc99e Initial load
duke
parents:
diff changeset
313 // The always-Inflate policy works properly, but in 1.5.0 it can sometimes
a61af66fc99e Initial load
duke
parents:
diff changeset
314 // cause performance problems in code that makes heavy use of a small # of
a61af66fc99e Initial load
duke
parents:
diff changeset
315 // uncontended locks. (We'd inflate during OSR, and then sync performance
a61af66fc99e Initial load
duke
parents:
diff changeset
316 // would subsequently plummet because the thread would be forced thru the slow-path).
a61af66fc99e Initial load
duke
parents:
diff changeset
317 // This problem has been made largely moot on IA32 by inlining the inflated fast-path
a61af66fc99e Initial load
duke
parents:
diff changeset
318 // operations in Fast_Lock and Fast_Unlock in i486.ad.
a61af66fc99e Initial load
duke
parents:
diff changeset
319 //
a61af66fc99e Initial load
duke
parents:
diff changeset
320 // Note that there is a way to safely swing the object's markword from
a61af66fc99e Initial load
duke
parents:
diff changeset
321 // one stack location to another. This avoids inflation. Obviously,
a61af66fc99e Initial load
duke
parents:
diff changeset
322 // we need to ensure that both locations refer to the current thread's stack.
a61af66fc99e Initial load
duke
parents:
diff changeset
323 // There are some subtle concurrency issues, however, and since the benefit is
a61af66fc99e Initial load
duke
parents:
diff changeset
324 // is small (given the support for inflated fast-path locking in the fast_lock, etc)
a61af66fc99e Initial load
duke
parents:
diff changeset
325 // we'll leave that optimization for another time.
a61af66fc99e Initial load
duke
parents:
diff changeset
326
a61af66fc99e Initial load
duke
parents:
diff changeset
327 if (displaced_header()->is_neutral()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
328 ObjectSynchronizer::inflate_helper(obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
329 // WARNING: We can not put check here, because the inflation
a61af66fc99e Initial load
duke
parents:
diff changeset
330 // will not update the displaced header. Once BasicLock is inflated,
a61af66fc99e Initial load
duke
parents:
diff changeset
331 // no one should ever look at its content.
a61af66fc99e Initial load
duke
parents:
diff changeset
332 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
333 // Typically the displaced header will be 0 (recursive stack lock) or
a61af66fc99e Initial load
duke
parents:
diff changeset
334 // unused_mark. Naively we'd like to assert that the displaced mark
a61af66fc99e Initial load
duke
parents:
diff changeset
335 // value is either 0, neutral, or 3. But with the advent of the
a61af66fc99e Initial load
duke
parents:
diff changeset
336 // store-before-CAS avoidance in fast_lock/compiler_lock_object
a61af66fc99e Initial load
duke
parents:
diff changeset
337 // we can find any flavor mark in the displaced mark.
a61af66fc99e Initial load
duke
parents:
diff changeset
338 }
a61af66fc99e Initial load
duke
parents:
diff changeset
339 // [RGV] The next line appears to do nothing!
a61af66fc99e Initial load
duke
parents:
diff changeset
340 intptr_t dh = (intptr_t) displaced_header();
a61af66fc99e Initial load
duke
parents:
diff changeset
341 dest->set_displaced_header(displaced_header());
a61af66fc99e Initial load
duke
parents:
diff changeset
342 }
a61af66fc99e Initial load
duke
parents:
diff changeset
343
a61af66fc99e Initial load
duke
parents:
diff changeset
344 // -----------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
345
a61af66fc99e Initial load
duke
parents:
diff changeset
346 // standard constructor, allows locking failures
a61af66fc99e Initial load
duke
parents:
diff changeset
347 ObjectLocker::ObjectLocker(Handle obj, Thread* thread, bool doLock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
348 _dolock = doLock;
a61af66fc99e Initial load
duke
parents:
diff changeset
349 _thread = thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
350 debug_only(if (StrictSafepointChecks) _thread->check_for_valid_safepoint_state(false);)
a61af66fc99e Initial load
duke
parents:
diff changeset
351 _obj = obj;
a61af66fc99e Initial load
duke
parents:
diff changeset
352
a61af66fc99e Initial load
duke
parents:
diff changeset
353 if (_dolock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
354 TEVENT (ObjectLocker) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
355
a61af66fc99e Initial load
duke
parents:
diff changeset
356 ObjectSynchronizer::fast_enter(_obj, &_lock, false, _thread);
a61af66fc99e Initial load
duke
parents:
diff changeset
357 }
a61af66fc99e Initial load
duke
parents:
diff changeset
358 }
a61af66fc99e Initial load
duke
parents:
diff changeset
359
a61af66fc99e Initial load
duke
parents:
diff changeset
360 ObjectLocker::~ObjectLocker() {
a61af66fc99e Initial load
duke
parents:
diff changeset
361 if (_dolock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
362 ObjectSynchronizer::fast_exit(_obj(), &_lock, _thread);
a61af66fc99e Initial load
duke
parents:
diff changeset
363 }
a61af66fc99e Initial load
duke
parents:
diff changeset
364 }
a61af66fc99e Initial load
duke
parents:
diff changeset
365
a61af66fc99e Initial load
duke
parents:
diff changeset
366 // -----------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
367
a61af66fc99e Initial load
duke
parents:
diff changeset
368
a61af66fc99e Initial load
duke
parents:
diff changeset
369 PerfCounter * ObjectSynchronizer::_sync_Inflations = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
370 PerfCounter * ObjectSynchronizer::_sync_Deflations = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
371 PerfCounter * ObjectSynchronizer::_sync_ContendedLockAttempts = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
372 PerfCounter * ObjectSynchronizer::_sync_FutileWakeups = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
373 PerfCounter * ObjectSynchronizer::_sync_Parks = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
374 PerfCounter * ObjectSynchronizer::_sync_EmptyNotifications = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
375 PerfCounter * ObjectSynchronizer::_sync_Notifications = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
376 PerfCounter * ObjectSynchronizer::_sync_PrivateA = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
377 PerfCounter * ObjectSynchronizer::_sync_PrivateB = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
378 PerfCounter * ObjectSynchronizer::_sync_SlowExit = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
379 PerfCounter * ObjectSynchronizer::_sync_SlowEnter = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
380 PerfCounter * ObjectSynchronizer::_sync_SlowNotify = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
381 PerfCounter * ObjectSynchronizer::_sync_SlowNotifyAll = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
382 PerfCounter * ObjectSynchronizer::_sync_FailedSpins = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
383 PerfCounter * ObjectSynchronizer::_sync_SuccessfulSpins = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
384 PerfCounter * ObjectSynchronizer::_sync_MonInCirculation = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
385 PerfCounter * ObjectSynchronizer::_sync_MonScavenged = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
386 PerfLongVariable * ObjectSynchronizer::_sync_MonExtant = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
387
a61af66fc99e Initial load
duke
parents:
diff changeset
388 // One-shot global initialization for the sync subsystem.
a61af66fc99e Initial load
duke
parents:
diff changeset
389 // We could also defer initialization and initialize on-demand
a61af66fc99e Initial load
duke
parents:
diff changeset
390 // the first time we call inflate(). Initialization would
a61af66fc99e Initial load
duke
parents:
diff changeset
391 // be protected - like so many things - by the MonitorCache_lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
392
a61af66fc99e Initial load
duke
parents:
diff changeset
393 void ObjectSynchronizer::Initialize () {
a61af66fc99e Initial load
duke
parents:
diff changeset
394 static int InitializationCompleted = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
395 assert (InitializationCompleted == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
396 InitializationCompleted = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
397 if (UsePerfData) {
a61af66fc99e Initial load
duke
parents:
diff changeset
398 EXCEPTION_MARK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
399 #define NEWPERFCOUNTER(n) {n = PerfDataManager::create_counter(SUN_RT, #n, PerfData::U_Events,CHECK); }
a61af66fc99e Initial load
duke
parents:
diff changeset
400 #define NEWPERFVARIABLE(n) {n = PerfDataManager::create_variable(SUN_RT, #n, PerfData::U_Events,CHECK); }
a61af66fc99e Initial load
duke
parents:
diff changeset
401 NEWPERFCOUNTER(_sync_Inflations) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
402 NEWPERFCOUNTER(_sync_Deflations) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
403 NEWPERFCOUNTER(_sync_ContendedLockAttempts) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
404 NEWPERFCOUNTER(_sync_FutileWakeups) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
405 NEWPERFCOUNTER(_sync_Parks) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
406 NEWPERFCOUNTER(_sync_EmptyNotifications) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
407 NEWPERFCOUNTER(_sync_Notifications) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
408 NEWPERFCOUNTER(_sync_SlowEnter) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
409 NEWPERFCOUNTER(_sync_SlowExit) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
410 NEWPERFCOUNTER(_sync_SlowNotify) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
411 NEWPERFCOUNTER(_sync_SlowNotifyAll) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
412 NEWPERFCOUNTER(_sync_FailedSpins) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
413 NEWPERFCOUNTER(_sync_SuccessfulSpins) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
414 NEWPERFCOUNTER(_sync_PrivateA) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
415 NEWPERFCOUNTER(_sync_PrivateB) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
416 NEWPERFCOUNTER(_sync_MonInCirculation) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
417 NEWPERFCOUNTER(_sync_MonScavenged) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
418 NEWPERFVARIABLE(_sync_MonExtant) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
419 #undef NEWPERFCOUNTER
a61af66fc99e Initial load
duke
parents:
diff changeset
420 }
a61af66fc99e Initial load
duke
parents:
diff changeset
421 }
a61af66fc99e Initial load
duke
parents:
diff changeset
422
a61af66fc99e Initial load
duke
parents:
diff changeset
423 // Compile-time asserts
a61af66fc99e Initial load
duke
parents:
diff changeset
424 // When possible, it's better to catch errors deterministically at
a61af66fc99e Initial load
duke
parents:
diff changeset
425 // compile-time than at runtime. The down-side to using compile-time
a61af66fc99e Initial load
duke
parents:
diff changeset
426 // asserts is that error message -- often something about negative array
a61af66fc99e Initial load
duke
parents:
diff changeset
427 // indices -- is opaque.
a61af66fc99e Initial load
duke
parents:
diff changeset
428
513
2328d1d3f8cf 6781583: Hotspot build fails on linux 64 bit platform with gcc 4.3.2
xlu
parents: 478
diff changeset
429 #define CTASSERT(x) { int tag[1-(2*!(x))]; printf ("Tag @" INTPTR_FORMAT "\n", (intptr_t)tag); }
0
a61af66fc99e Initial load
duke
parents:
diff changeset
430
a61af66fc99e Initial load
duke
parents:
diff changeset
431 void ObjectMonitor::ctAsserts() {
a61af66fc99e Initial load
duke
parents:
diff changeset
432 CTASSERT(offset_of (ObjectMonitor, _header) == 0);
a61af66fc99e Initial load
duke
parents:
diff changeset
433 }
a61af66fc99e Initial load
duke
parents:
diff changeset
434
a61af66fc99e Initial load
duke
parents:
diff changeset
435 static int Adjust (volatile int * adr, int dx) {
a61af66fc99e Initial load
duke
parents:
diff changeset
436 int v ;
a61af66fc99e Initial load
duke
parents:
diff changeset
437 for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
438 return v ;
a61af66fc99e Initial load
duke
parents:
diff changeset
439 }
a61af66fc99e Initial load
duke
parents:
diff changeset
440
a61af66fc99e Initial load
duke
parents:
diff changeset
441 // Ad-hoc mutual exclusion primitives: SpinLock and Mux
a61af66fc99e Initial load
duke
parents:
diff changeset
442 //
a61af66fc99e Initial load
duke
parents:
diff changeset
443 // We employ SpinLocks _only for low-contention, fixed-length
a61af66fc99e Initial load
duke
parents:
diff changeset
444 // short-duration critical sections where we're concerned
a61af66fc99e Initial load
duke
parents:
diff changeset
445 // about native mutex_t or HotSpot Mutex:: latency.
a61af66fc99e Initial load
duke
parents:
diff changeset
446 // The mux construct provides a spin-then-block mutual exclusion
a61af66fc99e Initial load
duke
parents:
diff changeset
447 // mechanism.
a61af66fc99e Initial load
duke
parents:
diff changeset
448 //
a61af66fc99e Initial load
duke
parents:
diff changeset
449 // Testing has shown that contention on the ListLock guarding gFreeList
a61af66fc99e Initial load
duke
parents:
diff changeset
450 // is common. If we implement ListLock as a simple SpinLock it's common
a61af66fc99e Initial load
duke
parents:
diff changeset
451 // for the JVM to devolve to yielding with little progress. This is true
a61af66fc99e Initial load
duke
parents:
diff changeset
452 // despite the fact that the critical sections protected by ListLock are
a61af66fc99e Initial load
duke
parents:
diff changeset
453 // extremely short.
a61af66fc99e Initial load
duke
parents:
diff changeset
454 //
a61af66fc99e Initial load
duke
parents:
diff changeset
455 // TODO-FIXME: ListLock should be of type SpinLock.
a61af66fc99e Initial load
duke
parents:
diff changeset
456 // We should make this a 1st-class type, integrated into the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
457 // hierarchy as leaf-locks. Critically, the SpinLock structure
a61af66fc99e Initial load
duke
parents:
diff changeset
458 // should have sufficient padding to avoid false-sharing and excessive
a61af66fc99e Initial load
duke
parents:
diff changeset
459 // cache-coherency traffic.
a61af66fc99e Initial load
duke
parents:
diff changeset
460
a61af66fc99e Initial load
duke
parents:
diff changeset
461
a61af66fc99e Initial load
duke
parents:
diff changeset
462 typedef volatile int SpinLockT ;
a61af66fc99e Initial load
duke
parents:
diff changeset
463
a61af66fc99e Initial load
duke
parents:
diff changeset
464 void Thread::SpinAcquire (volatile int * adr, const char * LockName) {
a61af66fc99e Initial load
duke
parents:
diff changeset
465 if (Atomic::cmpxchg (1, adr, 0) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
466 return ; // normal fast-path return
a61af66fc99e Initial load
duke
parents:
diff changeset
467 }
a61af66fc99e Initial load
duke
parents:
diff changeset
468
a61af66fc99e Initial load
duke
parents:
diff changeset
469 // Slow-path : We've encountered contention -- Spin/Yield/Block strategy.
a61af66fc99e Initial load
duke
parents:
diff changeset
470 TEVENT (SpinAcquire - ctx) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
471 int ctr = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
472 int Yields = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
473 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
474 while (*adr != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
475 ++ctr ;
a61af66fc99e Initial load
duke
parents:
diff changeset
476 if ((ctr & 0xFFF) == 0 || !os::is_MP()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
477 if (Yields > 5) {
a61af66fc99e Initial load
duke
parents:
diff changeset
478 // Consider using a simple NakedSleep() instead.
a61af66fc99e Initial load
duke
parents:
diff changeset
479 // Then SpinAcquire could be called by non-JVM threads
a61af66fc99e Initial load
duke
parents:
diff changeset
480 Thread::current()->_ParkEvent->park(1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
481 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
482 os::NakedYield() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
483 ++Yields ;
a61af66fc99e Initial load
duke
parents:
diff changeset
484 }
a61af66fc99e Initial load
duke
parents:
diff changeset
485 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
486 SpinPause() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
487 }
a61af66fc99e Initial load
duke
parents:
diff changeset
488 }
a61af66fc99e Initial load
duke
parents:
diff changeset
489 if (Atomic::cmpxchg (1, adr, 0) == 0) return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
490 }
a61af66fc99e Initial load
duke
parents:
diff changeset
491 }
a61af66fc99e Initial load
duke
parents:
diff changeset
492
a61af66fc99e Initial load
duke
parents:
diff changeset
493 void Thread::SpinRelease (volatile int * adr) {
a61af66fc99e Initial load
duke
parents:
diff changeset
494 assert (*adr != 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
495 OrderAccess::fence() ; // guarantee at least release consistency.
a61af66fc99e Initial load
duke
parents:
diff changeset
496 // Roach-motel semantics.
a61af66fc99e Initial load
duke
parents:
diff changeset
497 // It's safe if subsequent LDs and STs float "up" into the critical section,
a61af66fc99e Initial load
duke
parents:
diff changeset
498 // but prior LDs and STs within the critical section can't be allowed
a61af66fc99e Initial load
duke
parents:
diff changeset
499 // to reorder or float past the ST that releases the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
500 *adr = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
501 }
a61af66fc99e Initial load
duke
parents:
diff changeset
502
a61af66fc99e Initial load
duke
parents:
diff changeset
503 // muxAcquire and muxRelease:
a61af66fc99e Initial load
duke
parents:
diff changeset
504 //
a61af66fc99e Initial load
duke
parents:
diff changeset
505 // * muxAcquire and muxRelease support a single-word lock-word construct.
a61af66fc99e Initial load
duke
parents:
diff changeset
506 // The LSB of the word is set IFF the lock is held.
a61af66fc99e Initial load
duke
parents:
diff changeset
507 // The remainder of the word points to the head of a singly-linked list
a61af66fc99e Initial load
duke
parents:
diff changeset
508 // of threads blocked on the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
509 //
a61af66fc99e Initial load
duke
parents:
diff changeset
510 // * The current implementation of muxAcquire-muxRelease uses its own
a61af66fc99e Initial load
duke
parents:
diff changeset
511 // dedicated Thread._MuxEvent instance. If we're interested in
a61af66fc99e Initial load
duke
parents:
diff changeset
512 // minimizing the peak number of extant ParkEvent instances then
a61af66fc99e Initial load
duke
parents:
diff changeset
513 // we could eliminate _MuxEvent and "borrow" _ParkEvent as long
a61af66fc99e Initial load
duke
parents:
diff changeset
514 // as certain invariants were satisfied. Specifically, care would need
a61af66fc99e Initial load
duke
parents:
diff changeset
515 // to be taken with regards to consuming unpark() "permits".
a61af66fc99e Initial load
duke
parents:
diff changeset
516 // A safe rule of thumb is that a thread would never call muxAcquire()
a61af66fc99e Initial load
duke
parents:
diff changeset
517 // if it's enqueued (cxq, EntryList, WaitList, etc) and will subsequently
a61af66fc99e Initial load
duke
parents:
diff changeset
518 // park(). Otherwise the _ParkEvent park() operation in muxAcquire() could
a61af66fc99e Initial load
duke
parents:
diff changeset
519 // consume an unpark() permit intended for monitorenter, for instance.
a61af66fc99e Initial load
duke
parents:
diff changeset
520 // One way around this would be to widen the restricted-range semaphore
a61af66fc99e Initial load
duke
parents:
diff changeset
521 // implemented in park(). Another alternative would be to provide
a61af66fc99e Initial load
duke
parents:
diff changeset
522 // multiple instances of the PlatformEvent() for each thread. One
a61af66fc99e Initial load
duke
parents:
diff changeset
523 // instance would be dedicated to muxAcquire-muxRelease, for instance.
a61af66fc99e Initial load
duke
parents:
diff changeset
524 //
a61af66fc99e Initial load
duke
parents:
diff changeset
525 // * Usage:
a61af66fc99e Initial load
duke
parents:
diff changeset
526 // -- Only as leaf locks
a61af66fc99e Initial load
duke
parents:
diff changeset
527 // -- for short-term locking only as muxAcquire does not perform
a61af66fc99e Initial load
duke
parents:
diff changeset
528 // thread state transitions.
a61af66fc99e Initial load
duke
parents:
diff changeset
529 //
a61af66fc99e Initial load
duke
parents:
diff changeset
530 // Alternatives:
a61af66fc99e Initial load
duke
parents:
diff changeset
531 // * We could implement muxAcquire and muxRelease with MCS or CLH locks
a61af66fc99e Initial load
duke
parents:
diff changeset
532 // but with parking or spin-then-park instead of pure spinning.
a61af66fc99e Initial load
duke
parents:
diff changeset
533 // * Use Taura-Oyama-Yonenzawa locks.
a61af66fc99e Initial load
duke
parents:
diff changeset
534 // * It's possible to construct a 1-0 lock if we encode the lockword as
a61af66fc99e Initial load
duke
parents:
diff changeset
535 // (List,LockByte). Acquire will CAS the full lockword while Release
a61af66fc99e Initial load
duke
parents:
diff changeset
536 // will STB 0 into the LockByte. The 1-0 scheme admits stranding, so
a61af66fc99e Initial load
duke
parents:
diff changeset
537 // acquiring threads use timers (ParkTimed) to detect and recover from
a61af66fc99e Initial load
duke
parents:
diff changeset
538 // the stranding window. Thread/Node structures must be aligned on 256-byte
a61af66fc99e Initial load
duke
parents:
diff changeset
539 // boundaries by using placement-new.
a61af66fc99e Initial load
duke
parents:
diff changeset
540 // * Augment MCS with advisory back-link fields maintained with CAS().
a61af66fc99e Initial load
duke
parents:
diff changeset
541 // Pictorially: LockWord -> T1 <-> T2 <-> T3 <-> ... <-> Tn <-> Owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
542 // The validity of the backlinks must be ratified before we trust the value.
a61af66fc99e Initial load
duke
parents:
diff changeset
543 // If the backlinks are invalid the exiting thread must back-track through the
a61af66fc99e Initial load
duke
parents:
diff changeset
544 // the forward links, which are always trustworthy.
a61af66fc99e Initial load
duke
parents:
diff changeset
545 // * Add a successor indication. The LockWord is currently encoded as
a61af66fc99e Initial load
duke
parents:
diff changeset
546 // (List, LOCKBIT:1). We could also add a SUCCBIT or an explicit _succ variable
a61af66fc99e Initial load
duke
parents:
diff changeset
547 // to provide the usual futile-wakeup optimization.
a61af66fc99e Initial load
duke
parents:
diff changeset
548 // See RTStt for details.
a61af66fc99e Initial load
duke
parents:
diff changeset
549 // * Consider schedctl.sc_nopreempt to cover the critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
550 //
a61af66fc99e Initial load
duke
parents:
diff changeset
551
a61af66fc99e Initial load
duke
parents:
diff changeset
552
a61af66fc99e Initial load
duke
parents:
diff changeset
553 typedef volatile intptr_t MutexT ; // Mux Lock-word
a61af66fc99e Initial load
duke
parents:
diff changeset
554 enum MuxBits { LOCKBIT = 1 } ;
a61af66fc99e Initial load
duke
parents:
diff changeset
555
a61af66fc99e Initial load
duke
parents:
diff changeset
556 void Thread::muxAcquire (volatile intptr_t * Lock, const char * LockName) {
a61af66fc99e Initial load
duke
parents:
diff changeset
557 intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
558 if (w == 0) return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
559 if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
560 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
561 }
a61af66fc99e Initial load
duke
parents:
diff changeset
562
a61af66fc99e Initial load
duke
parents:
diff changeset
563 TEVENT (muxAcquire - Contention) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
564 ParkEvent * const Self = Thread::current()->_MuxEvent ;
a61af66fc99e Initial load
duke
parents:
diff changeset
565 assert ((intptr_t(Self) & LOCKBIT) == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
566 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
567 int its = (os::is_MP() ? 100 : 0) + 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
568
a61af66fc99e Initial load
duke
parents:
diff changeset
569 // Optional spin phase: spin-then-park strategy
a61af66fc99e Initial load
duke
parents:
diff changeset
570 while (--its >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
571 w = *Lock ;
a61af66fc99e Initial load
duke
parents:
diff changeset
572 if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
573 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
574 }
a61af66fc99e Initial load
duke
parents:
diff changeset
575 }
a61af66fc99e Initial load
duke
parents:
diff changeset
576
a61af66fc99e Initial load
duke
parents:
diff changeset
577 Self->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
578 Self->OnList = intptr_t(Lock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
579 // The following fence() isn't _strictly necessary as the subsequent
a61af66fc99e Initial load
duke
parents:
diff changeset
580 // CAS() both serializes execution and ratifies the fetched *Lock value.
a61af66fc99e Initial load
duke
parents:
diff changeset
581 OrderAccess::fence();
a61af66fc99e Initial load
duke
parents:
diff changeset
582 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
583 w = *Lock ;
a61af66fc99e Initial load
duke
parents:
diff changeset
584 if ((w & LOCKBIT) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
585 if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
586 Self->OnList = 0 ; // hygiene - allows stronger asserts
a61af66fc99e Initial load
duke
parents:
diff changeset
587 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
588 }
a61af66fc99e Initial load
duke
parents:
diff changeset
589 continue ; // Interference -- *Lock changed -- Just retry
a61af66fc99e Initial load
duke
parents:
diff changeset
590 }
a61af66fc99e Initial load
duke
parents:
diff changeset
591 assert (w & LOCKBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
592 Self->ListNext = (ParkEvent *) (w & ~LOCKBIT );
a61af66fc99e Initial load
duke
parents:
diff changeset
593 if (Atomic::cmpxchg_ptr (intptr_t(Self)|LOCKBIT, Lock, w) == w) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
594 }
a61af66fc99e Initial load
duke
parents:
diff changeset
595
a61af66fc99e Initial load
duke
parents:
diff changeset
596 while (Self->OnList != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
597 Self->park() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
598 }
a61af66fc99e Initial load
duke
parents:
diff changeset
599 }
a61af66fc99e Initial load
duke
parents:
diff changeset
600 }
a61af66fc99e Initial load
duke
parents:
diff changeset
601
a61af66fc99e Initial load
duke
parents:
diff changeset
602 void Thread::muxAcquireW (volatile intptr_t * Lock, ParkEvent * ev) {
a61af66fc99e Initial load
duke
parents:
diff changeset
603 intptr_t w = Atomic::cmpxchg_ptr (LOCKBIT, Lock, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
604 if (w == 0) return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
605 if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
606 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
607 }
a61af66fc99e Initial load
duke
parents:
diff changeset
608
a61af66fc99e Initial load
duke
parents:
diff changeset
609 TEVENT (muxAcquire - Contention) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
610 ParkEvent * ReleaseAfter = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
611 if (ev == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
612 ev = ReleaseAfter = ParkEvent::Allocate (NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
613 }
a61af66fc99e Initial load
duke
parents:
diff changeset
614 assert ((intptr_t(ev) & LOCKBIT) == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
615 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
616 guarantee (ev->OnList == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
617 int its = (os::is_MP() ? 100 : 0) + 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
618
a61af66fc99e Initial load
duke
parents:
diff changeset
619 // Optional spin phase: spin-then-park strategy
a61af66fc99e Initial load
duke
parents:
diff changeset
620 while (--its >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
621 w = *Lock ;
a61af66fc99e Initial load
duke
parents:
diff changeset
622 if ((w & LOCKBIT) == 0 && Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
623 if (ReleaseAfter != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
624 ParkEvent::Release (ReleaseAfter) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
625 }
a61af66fc99e Initial load
duke
parents:
diff changeset
626 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
627 }
a61af66fc99e Initial load
duke
parents:
diff changeset
628 }
a61af66fc99e Initial load
duke
parents:
diff changeset
629
a61af66fc99e Initial load
duke
parents:
diff changeset
630 ev->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
631 ev->OnList = intptr_t(Lock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
632 // The following fence() isn't _strictly necessary as the subsequent
a61af66fc99e Initial load
duke
parents:
diff changeset
633 // CAS() both serializes execution and ratifies the fetched *Lock value.
a61af66fc99e Initial load
duke
parents:
diff changeset
634 OrderAccess::fence();
a61af66fc99e Initial load
duke
parents:
diff changeset
635 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
636 w = *Lock ;
a61af66fc99e Initial load
duke
parents:
diff changeset
637 if ((w & LOCKBIT) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
638 if (Atomic::cmpxchg_ptr (w|LOCKBIT, Lock, w) == w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
639 ev->OnList = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
640 // We call ::Release while holding the outer lock, thus
a61af66fc99e Initial load
duke
parents:
diff changeset
641 // artificially lengthening the critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
642 // Consider deferring the ::Release() until the subsequent unlock(),
a61af66fc99e Initial load
duke
parents:
diff changeset
643 // after we've dropped the outer lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
644 if (ReleaseAfter != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
645 ParkEvent::Release (ReleaseAfter) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
646 }
a61af66fc99e Initial load
duke
parents:
diff changeset
647 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
648 }
a61af66fc99e Initial load
duke
parents:
diff changeset
649 continue ; // Interference -- *Lock changed -- Just retry
a61af66fc99e Initial load
duke
parents:
diff changeset
650 }
a61af66fc99e Initial load
duke
parents:
diff changeset
651 assert (w & LOCKBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
652 ev->ListNext = (ParkEvent *) (w & ~LOCKBIT );
a61af66fc99e Initial load
duke
parents:
diff changeset
653 if (Atomic::cmpxchg_ptr (intptr_t(ev)|LOCKBIT, Lock, w) == w) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
654 }
a61af66fc99e Initial load
duke
parents:
diff changeset
655
a61af66fc99e Initial load
duke
parents:
diff changeset
656 while (ev->OnList != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
657 ev->park() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
658 }
a61af66fc99e Initial load
duke
parents:
diff changeset
659 }
a61af66fc99e Initial load
duke
parents:
diff changeset
660 }
a61af66fc99e Initial load
duke
parents:
diff changeset
661
a61af66fc99e Initial load
duke
parents:
diff changeset
662 // Release() must extract a successor from the list and then wake that thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
663 // It can "pop" the front of the list or use a detach-modify-reattach (DMR) scheme
a61af66fc99e Initial load
duke
parents:
diff changeset
664 // similar to that used by ParkEvent::Allocate() and ::Release(). DMR-based
a61af66fc99e Initial load
duke
parents:
diff changeset
665 // Release() would :
a61af66fc99e Initial load
duke
parents:
diff changeset
666 // (A) CAS() or swap() null to *Lock, releasing the lock and detaching the list.
a61af66fc99e Initial load
duke
parents:
diff changeset
667 // (B) Extract a successor from the private list "in-hand"
a61af66fc99e Initial load
duke
parents:
diff changeset
668 // (C) attempt to CAS() the residual back into *Lock over null.
a61af66fc99e Initial load
duke
parents:
diff changeset
669 // If there were any newly arrived threads and the CAS() would fail.
a61af66fc99e Initial load
duke
parents:
diff changeset
670 // In that case Release() would detach the RATs, re-merge the list in-hand
a61af66fc99e Initial load
duke
parents:
diff changeset
671 // with the RATs and repeat as needed. Alternately, Release() might
a61af66fc99e Initial load
duke
parents:
diff changeset
672 // detach and extract a successor, but then pass the residual list to the wakee.
a61af66fc99e Initial load
duke
parents:
diff changeset
673 // The wakee would be responsible for reattaching and remerging before it
a61af66fc99e Initial load
duke
parents:
diff changeset
674 // competed for the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
675 //
a61af66fc99e Initial load
duke
parents:
diff changeset
676 // Both "pop" and DMR are immune from ABA corruption -- there can be
a61af66fc99e Initial load
duke
parents:
diff changeset
677 // multiple concurrent pushers, but only one popper or detacher.
a61af66fc99e Initial load
duke
parents:
diff changeset
678 // This implementation pops from the head of the list. This is unfair,
a61af66fc99e Initial load
duke
parents:
diff changeset
679 // but tends to provide excellent throughput as hot threads remain hot.
a61af66fc99e Initial load
duke
parents:
diff changeset
680 // (We wake recently run threads first).
a61af66fc99e Initial load
duke
parents:
diff changeset
681
a61af66fc99e Initial load
duke
parents:
diff changeset
682 void Thread::muxRelease (volatile intptr_t * Lock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
683 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
684 const intptr_t w = Atomic::cmpxchg_ptr (0, Lock, LOCKBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
685 assert (w & LOCKBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
686 if (w == LOCKBIT) return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
687 ParkEvent * List = (ParkEvent *) (w & ~LOCKBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
688 assert (List != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
689 assert (List->OnList == intptr_t(Lock), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
690 ParkEvent * nxt = List->ListNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
691
a61af66fc99e Initial load
duke
parents:
diff changeset
692 // The following CAS() releases the lock and pops the head element.
a61af66fc99e Initial load
duke
parents:
diff changeset
693 if (Atomic::cmpxchg_ptr (intptr_t(nxt), Lock, w) != w) {
a61af66fc99e Initial load
duke
parents:
diff changeset
694 continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
695 }
a61af66fc99e Initial load
duke
parents:
diff changeset
696 List->OnList = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
697 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
698 List->unpark () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
699 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
700 }
a61af66fc99e Initial load
duke
parents:
diff changeset
701 }
a61af66fc99e Initial load
duke
parents:
diff changeset
702
a61af66fc99e Initial load
duke
parents:
diff changeset
703 // ObjectMonitor Lifecycle
a61af66fc99e Initial load
duke
parents:
diff changeset
704 // -----------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
705 // Inflation unlinks monitors from the global gFreeList and
a61af66fc99e Initial load
duke
parents:
diff changeset
706 // associates them with objects. Deflation -- which occurs at
a61af66fc99e Initial load
duke
parents:
diff changeset
707 // STW-time -- disassociates idle monitors from objects. Such
a61af66fc99e Initial load
duke
parents:
diff changeset
708 // scavenged monitors are returned to the gFreeList.
a61af66fc99e Initial load
duke
parents:
diff changeset
709 //
a61af66fc99e Initial load
duke
parents:
diff changeset
710 // The global list is protected by ListLock. All the critical sections
a61af66fc99e Initial load
duke
parents:
diff changeset
711 // are short and operate in constant-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
712 //
a61af66fc99e Initial load
duke
parents:
diff changeset
713 // ObjectMonitors reside in type-stable memory (TSM) and are immortal.
a61af66fc99e Initial load
duke
parents:
diff changeset
714 //
a61af66fc99e Initial load
duke
parents:
diff changeset
715 // Lifecycle:
a61af66fc99e Initial load
duke
parents:
diff changeset
716 // -- unassigned and on the global free list
a61af66fc99e Initial load
duke
parents:
diff changeset
717 // -- unassigned and on a thread's private omFreeList
a61af66fc99e Initial load
duke
parents:
diff changeset
718 // -- assigned to an object. The object is inflated and the mark refers
a61af66fc99e Initial load
duke
parents:
diff changeset
719 // to the objectmonitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
720 //
a61af66fc99e Initial load
duke
parents:
diff changeset
721 // TODO-FIXME:
a61af66fc99e Initial load
duke
parents:
diff changeset
722 //
a61af66fc99e Initial load
duke
parents:
diff changeset
723 // * We currently protect the gFreeList with a simple lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
724 // An alternate lock-free scheme would be to pop elements from the gFreeList
a61af66fc99e Initial load
duke
parents:
diff changeset
725 // with CAS. This would be safe from ABA corruption as long we only
a61af66fc99e Initial load
duke
parents:
diff changeset
726 // recycled previously appearing elements onto the list in deflate_idle_monitors()
a61af66fc99e Initial load
duke
parents:
diff changeset
727 // at STW-time. Completely new elements could always be pushed onto the gFreeList
a61af66fc99e Initial load
duke
parents:
diff changeset
728 // with CAS. Elements that appeared previously on the list could only
a61af66fc99e Initial load
duke
parents:
diff changeset
729 // be installed at STW-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
730 //
a61af66fc99e Initial load
duke
parents:
diff changeset
731 // * For efficiency and to help reduce the store-before-CAS penalty
a61af66fc99e Initial load
duke
parents:
diff changeset
732 // the objectmonitors on gFreeList or local free lists should be ready to install
a61af66fc99e Initial load
duke
parents:
diff changeset
733 // with the exception of _header and _object. _object can be set after inflation.
a61af66fc99e Initial load
duke
parents:
diff changeset
734 // In particular, keep all objectMonitors on a thread's private list in ready-to-install
a61af66fc99e Initial load
duke
parents:
diff changeset
735 // state with m.Owner set properly.
a61af66fc99e Initial load
duke
parents:
diff changeset
736 //
a61af66fc99e Initial load
duke
parents:
diff changeset
737 // * We could all diffuse contention by using multiple global (FreeList, Lock)
a61af66fc99e Initial load
duke
parents:
diff changeset
738 // pairs -- threads could use trylock() and a cyclic-scan strategy to search for
a61af66fc99e Initial load
duke
parents:
diff changeset
739 // an unlocked free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
740 //
a61af66fc99e Initial load
duke
parents:
diff changeset
741 // * Add lifecycle tags and assert()s.
a61af66fc99e Initial load
duke
parents:
diff changeset
742 //
a61af66fc99e Initial load
duke
parents:
diff changeset
743 // * Be more consistent about when we clear an objectmonitor's fields:
a61af66fc99e Initial load
duke
parents:
diff changeset
744 // A. After extracting the objectmonitor from a free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
745 // B. After adding an objectmonitor to a free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
746 //
a61af66fc99e Initial load
duke
parents:
diff changeset
747
a61af66fc99e Initial load
duke
parents:
diff changeset
748 ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
749 ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
750 ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
751 int ObjectSynchronizer::gOmInUseCount = 0;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
752 static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
753 static volatile int MonitorFreeCount = 0 ; // # on gFreeList
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
754 static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation
0
a61af66fc99e Initial load
duke
parents:
diff changeset
755 #define CHAINMARKER ((oop)-1)
a61af66fc99e Initial load
duke
parents:
diff changeset
756
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
757 // Constraining monitor pool growth via MonitorBound ...
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
758 //
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
759 // The monitor pool is grow-only. We scavenge at STW safepoint-time, but the
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
760 // the rate of scavenging is driven primarily by GC. As such, we can find
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
761 // an inordinate number of monitors in circulation.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
762 // To avoid that scenario we can artificially induce a STW safepoint
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
763 // if the pool appears to be growing past some reasonable bound.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
764 // Generally we favor time in space-time tradeoffs, but as there's no
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
765 // natural back-pressure on the # of extant monitors we need to impose some
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
766 // type of limit. Beware that if MonitorBound is set to too low a value
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
767 // we could just loop. In addition, if MonitorBound is set to a low value
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
768 // we'll incur more safepoints, which are harmful to performance.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
769 // See also: GuaranteedSafepointInterval
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
770 //
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
771 // As noted elsewhere, the correct long-term solution is to deflate at
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
772 // monitorexit-time, in which case the number of inflated objects is bounded
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
773 // by the number of threads. That policy obviates the need for scavenging at
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
774 // STW safepoint time. As an aside, scavenging can be time-consuming when the
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
775 // # of extant monitors is large. Unfortunately there's a day-1 assumption baked
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
776 // into much HotSpot code that the object::monitor relationship, once established
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
777 // or observed, will remain stable except over potential safepoints.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
778 //
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
779 // We can use either a blocking synchronous VM operation or an async VM operation.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
780 // -- If we use a blocking VM operation :
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
781 // Calls to ScavengeCheck() should be inserted only into 'safe' locations in paths
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
782 // that lead to ::inflate() or ::omAlloc().
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
783 // Even though the safepoint will not directly induce GC, a GC might
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
784 // piggyback on the safepoint operation, so the caller should hold no naked oops.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
785 // Furthermore, monitor::object relationships are NOT necessarily stable over this call
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
786 // unless the caller has made provisions to "pin" the object to the monitor, say
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
787 // by incrementing the monitor's _count field.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
788 // -- If we use a non-blocking asynchronous VM operation :
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
789 // the constraints above don't apply. The safepoint will fire in the future
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
790 // at a more convenient time. On the other hand the latency between posting and
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
791 // running the safepoint introduces or admits "slop" or laxity during which the
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
792 // monitor population can climb further above the threshold. The monitor population,
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
793 // however, tends to converge asymptotically over time to a count that's slightly
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
794 // above the target value specified by MonitorBound. That is, we avoid unbounded
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
795 // growth, albeit with some imprecision.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
796 //
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
797 // The current implementation uses asynchronous VM operations.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
798 //
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
799 // Ideally we'd check if (MonitorPopulation > MonitorBound) in omAlloc()
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
800 // immediately before trying to grow the global list via allocation.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
801 // If the predicate was true then we'd induce a synchronous safepoint, wait
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
802 // for the safepoint to complete, and then again to allocate from the global
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
803 // free list. This approach is much simpler and precise, admitting no "slop".
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
804 // Unfortunately we can't safely safepoint in the midst of omAlloc(), so
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
805 // instead we use asynchronous safepoints.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
806
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
807 static void InduceScavenge (Thread * Self, const char * Whence) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
808 // Induce STW safepoint to trim monitors
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
809 // Ultimately, this results in a call to deflate_idle_monitors() in the near future.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
810 // More precisely, trigger an asynchronous STW safepoint as the number
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
811 // of active monitors passes the specified threshold.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
812 // TODO: assert thread state is reasonable
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
813
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
814 if (ForceMonitorScavenge == 0 && Atomic::xchg (1, &ForceMonitorScavenge) == 0) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
815 if (Knob_Verbose) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
816 ::printf ("Monitor scavenge - Induced STW @%s (%d)\n", Whence, ForceMonitorScavenge) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
817 ::fflush(stdout) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
818 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
819 // Induce a 'null' safepoint to scavenge monitors
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
820 // Must VM_Operation instance be heap allocated as the op will be enqueue and posted
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
821 // to the VMthread and have a lifespan longer than that of this activation record.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
822 // The VMThread will delete the op when completed.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
823 VMThread::execute (new VM_ForceAsyncSafepoint()) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
824
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
825 if (Knob_Verbose) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
826 ::printf ("Monitor scavenge - STW posted @%s (%d)\n", Whence, ForceMonitorScavenge) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
827 ::fflush(stdout) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
828 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
829 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
830 }
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
831 /* Too slow for general assert or debug
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
832 void ObjectSynchronizer::verifyInUse (Thread *Self) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
833 ObjectMonitor* mid;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
834 int inusetally = 0;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
835 for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
836 inusetally ++;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
837 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
838 assert(inusetally == Self->omInUseCount, "inuse count off");
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
839
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
840 int freetally = 0;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
841 for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
842 freetally ++;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
843 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
844 assert(freetally == Self->omFreeCount, "free count off");
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
845 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
846 */
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
847
0
a61af66fc99e Initial load
duke
parents:
diff changeset
848 ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
849 // A large MAXPRIVATE value reduces both list lock contention
a61af66fc99e Initial load
duke
parents:
diff changeset
850 // and list coherency traffic, but also tends to increase the
a61af66fc99e Initial load
duke
parents:
diff changeset
851 // number of objectMonitors in circulation as well as the STW
a61af66fc99e Initial load
duke
parents:
diff changeset
852 // scavenge costs. As usual, we lean toward time in space-time
a61af66fc99e Initial load
duke
parents:
diff changeset
853 // tradeoffs.
a61af66fc99e Initial load
duke
parents:
diff changeset
854 const int MAXPRIVATE = 1024 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
855 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
856 ObjectMonitor * m ;
a61af66fc99e Initial load
duke
parents:
diff changeset
857
a61af66fc99e Initial load
duke
parents:
diff changeset
858 // 1: try to allocate from the thread's local omFreeList.
a61af66fc99e Initial load
duke
parents:
diff changeset
859 // Threads will attempt to allocate first from their local list, then
a61af66fc99e Initial load
duke
parents:
diff changeset
860 // from the global list, and only after those attempts fail will the thread
a61af66fc99e Initial load
duke
parents:
diff changeset
861 // attempt to instantiate new monitors. Thread-local free lists take
a61af66fc99e Initial load
duke
parents:
diff changeset
862 // heat off the ListLock and improve allocation latency, as well as reducing
a61af66fc99e Initial load
duke
parents:
diff changeset
863 // coherency traffic on the shared global list.
a61af66fc99e Initial load
duke
parents:
diff changeset
864 m = Self->omFreeList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
865 if (m != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
866 Self->omFreeList = m->FreeNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
867 Self->omFreeCount -- ;
a61af66fc99e Initial load
duke
parents:
diff changeset
868 // CONSIDER: set m->FreeNext = BAD -- diagnostic hygiene
a61af66fc99e Initial load
duke
parents:
diff changeset
869 guarantee (m->object() == NULL, "invariant") ;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
870 if (MonitorInUseLists) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
871 m->FreeNext = Self->omInUseList;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
872 Self->omInUseList = m;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
873 Self->omInUseCount ++;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
874 // verifyInUse(Self);
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
875 } else {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
876 m->FreeNext = NULL;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
877 }
0
a61af66fc99e Initial load
duke
parents:
diff changeset
878 return m ;
a61af66fc99e Initial load
duke
parents:
diff changeset
879 }
a61af66fc99e Initial load
duke
parents:
diff changeset
880
a61af66fc99e Initial load
duke
parents:
diff changeset
881 // 2: try to allocate from the global gFreeList
a61af66fc99e Initial load
duke
parents:
diff changeset
882 // CONSIDER: use muxTry() instead of muxAcquire().
a61af66fc99e Initial load
duke
parents:
diff changeset
883 // If the muxTry() fails then drop immediately into case 3.
a61af66fc99e Initial load
duke
parents:
diff changeset
884 // If we're using thread-local free lists then try
a61af66fc99e Initial load
duke
parents:
diff changeset
885 // to reprovision the caller's free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
886 if (gFreeList != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
887 // Reprovision the thread's omFreeList.
a61af66fc99e Initial load
duke
parents:
diff changeset
888 // Use bulk transfers to reduce the allocation rate and heat
a61af66fc99e Initial load
duke
parents:
diff changeset
889 // on various locks.
a61af66fc99e Initial load
duke
parents:
diff changeset
890 Thread::muxAcquire (&ListLock, "omAlloc") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
891 for (int i = Self->omFreeProvision; --i >= 0 && gFreeList != NULL; ) {
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
892 MonitorFreeCount --;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
893 ObjectMonitor * take = gFreeList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
894 gFreeList = take->FreeNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
895 guarantee (take->object() == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
896 guarantee (!take->is_busy(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
897 take->Recycle() ;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
898 omRelease (Self, take, false) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
899 }
a61af66fc99e Initial load
duke
parents:
diff changeset
900 Thread::muxRelease (&ListLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
901 Self->omFreeProvision += 1 + (Self->omFreeProvision/2) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
902 if (Self->omFreeProvision > MAXPRIVATE ) Self->omFreeProvision = MAXPRIVATE ;
a61af66fc99e Initial load
duke
parents:
diff changeset
903 TEVENT (omFirst - reprovision) ;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
904
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
905 const int mx = MonitorBound ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
906 if (mx > 0 && (MonitorPopulation-MonitorFreeCount) > mx) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
907 // We can't safely induce a STW safepoint from omAlloc() as our thread
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
908 // state may not be appropriate for such activities and callers may hold
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
909 // naked oops, so instead we defer the action.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
910 InduceScavenge (Self, "omAlloc") ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
911 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
912 continue;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
913 }
a61af66fc99e Initial load
duke
parents:
diff changeset
914
a61af66fc99e Initial load
duke
parents:
diff changeset
915 // 3: allocate a block of new ObjectMonitors
a61af66fc99e Initial load
duke
parents:
diff changeset
916 // Both the local and global free lists are empty -- resort to malloc().
a61af66fc99e Initial load
duke
parents:
diff changeset
917 // In the current implementation objectMonitors are TSM - immortal.
a61af66fc99e Initial load
duke
parents:
diff changeset
918 assert (_BLOCKSIZE > 1, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
919 ObjectMonitor * temp = new ObjectMonitor[_BLOCKSIZE];
a61af66fc99e Initial load
duke
parents:
diff changeset
920
a61af66fc99e Initial load
duke
parents:
diff changeset
921 // NOTE: (almost) no way to recover if allocation failed.
a61af66fc99e Initial load
duke
parents:
diff changeset
922 // We might be able to induce a STW safepoint and scavenge enough
a61af66fc99e Initial load
duke
parents:
diff changeset
923 // objectMonitors to permit progress.
a61af66fc99e Initial load
duke
parents:
diff changeset
924 if (temp == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
925 vm_exit_out_of_memory (sizeof (ObjectMonitor[_BLOCKSIZE]), "Allocate ObjectMonitors") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
926 }
a61af66fc99e Initial load
duke
parents:
diff changeset
927
a61af66fc99e Initial load
duke
parents:
diff changeset
928 // Format the block.
a61af66fc99e Initial load
duke
parents:
diff changeset
929 // initialize the linked list, each monitor points to its next
a61af66fc99e Initial load
duke
parents:
diff changeset
930 // forming the single linked free list, the very first monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
931 // will points to next block, which forms the block list.
a61af66fc99e Initial load
duke
parents:
diff changeset
932 // The trick of using the 1st element in the block as gBlockList
a61af66fc99e Initial load
duke
parents:
diff changeset
933 // linkage should be reconsidered. A better implementation would
a61af66fc99e Initial load
duke
parents:
diff changeset
934 // look like: class Block { Block * next; int N; ObjectMonitor Body [N] ; }
a61af66fc99e Initial load
duke
parents:
diff changeset
935
a61af66fc99e Initial load
duke
parents:
diff changeset
936 for (int i = 1; i < _BLOCKSIZE ; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
937 temp[i].FreeNext = &temp[i+1];
a61af66fc99e Initial load
duke
parents:
diff changeset
938 }
a61af66fc99e Initial load
duke
parents:
diff changeset
939
a61af66fc99e Initial load
duke
parents:
diff changeset
940 // terminate the last monitor as the end of list
a61af66fc99e Initial load
duke
parents:
diff changeset
941 temp[_BLOCKSIZE - 1].FreeNext = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
942
a61af66fc99e Initial load
duke
parents:
diff changeset
943 // Element [0] is reserved for global list linkage
a61af66fc99e Initial load
duke
parents:
diff changeset
944 temp[0].set_object(CHAINMARKER);
a61af66fc99e Initial load
duke
parents:
diff changeset
945
a61af66fc99e Initial load
duke
parents:
diff changeset
946 // Consider carving out this thread's current request from the
a61af66fc99e Initial load
duke
parents:
diff changeset
947 // block in hand. This avoids some lock traffic and redundant
a61af66fc99e Initial load
duke
parents:
diff changeset
948 // list activity.
a61af66fc99e Initial load
duke
parents:
diff changeset
949
a61af66fc99e Initial load
duke
parents:
diff changeset
950 // Acquire the ListLock to manipulate BlockList and FreeList.
a61af66fc99e Initial load
duke
parents:
diff changeset
951 // An Oyama-Taura-Yonezawa scheme might be more efficient.
a61af66fc99e Initial load
duke
parents:
diff changeset
952 Thread::muxAcquire (&ListLock, "omAlloc [2]") ;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
953 MonitorPopulation += _BLOCKSIZE-1;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
954 MonitorFreeCount += _BLOCKSIZE-1;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
955
a61af66fc99e Initial load
duke
parents:
diff changeset
956 // Add the new block to the list of extant blocks (gBlockList).
a61af66fc99e Initial load
duke
parents:
diff changeset
957 // The very first objectMonitor in a block is reserved and dedicated.
a61af66fc99e Initial load
duke
parents:
diff changeset
958 // It serves as blocklist "next" linkage.
a61af66fc99e Initial load
duke
parents:
diff changeset
959 temp[0].FreeNext = gBlockList;
a61af66fc99e Initial load
duke
parents:
diff changeset
960 gBlockList = temp;
a61af66fc99e Initial load
duke
parents:
diff changeset
961
a61af66fc99e Initial load
duke
parents:
diff changeset
962 // Add the new string of objectMonitors to the global free list
a61af66fc99e Initial load
duke
parents:
diff changeset
963 temp[_BLOCKSIZE - 1].FreeNext = gFreeList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
964 gFreeList = temp + 1;
a61af66fc99e Initial load
duke
parents:
diff changeset
965 Thread::muxRelease (&ListLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
966 TEVENT (Allocate block of monitors) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
967 }
a61af66fc99e Initial load
duke
parents:
diff changeset
968 }
a61af66fc99e Initial load
duke
parents:
diff changeset
969
a61af66fc99e Initial load
duke
parents:
diff changeset
970 // Place "m" on the caller's private per-thread omFreeList.
a61af66fc99e Initial load
duke
parents:
diff changeset
971 // In practice there's no need to clamp or limit the number of
a61af66fc99e Initial load
duke
parents:
diff changeset
972 // monitors on a thread's omFreeList as the only time we'll call
a61af66fc99e Initial load
duke
parents:
diff changeset
973 // omRelease is to return a monitor to the free list after a CAS
a61af66fc99e Initial load
duke
parents:
diff changeset
974 // attempt failed. This doesn't allow unbounded #s of monitors to
a61af66fc99e Initial load
duke
parents:
diff changeset
975 // accumulate on a thread's free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
976 //
a61af66fc99e Initial load
duke
parents:
diff changeset
977 // In the future the usage of omRelease() might change and monitors
a61af66fc99e Initial load
duke
parents:
diff changeset
978 // could migrate between free lists. In that case to avoid excessive
a61af66fc99e Initial load
duke
parents:
diff changeset
979 // accumulation we could limit omCount to (omProvision*2), otherwise return
a61af66fc99e Initial load
duke
parents:
diff changeset
980 // the objectMonitor to the global list. We should drain (return) in reasonable chunks.
a61af66fc99e Initial load
duke
parents:
diff changeset
981 // That is, *not* one-at-a-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
982
a61af66fc99e Initial load
duke
parents:
diff changeset
983
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
984 void ObjectSynchronizer::omRelease (Thread * Self, ObjectMonitor * m, bool fromPerThreadAlloc) {
0
a61af66fc99e Initial load
duke
parents:
diff changeset
985 guarantee (m->object() == NULL, "invariant") ;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
986
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
987 // Remove from omInUseList
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
988 if (MonitorInUseLists && fromPerThreadAlloc) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
989 ObjectMonitor* curmidinuse = NULL;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
990 for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; ) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
991 if (m == mid) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
992 // extract from per-thread in-use-list
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
993 if (mid == Self->omInUseList) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
994 Self->omInUseList = mid->FreeNext;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
995 } else if (curmidinuse != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
996 curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
997 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
998 Self->omInUseCount --;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
999 // verifyInUse(Self);
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1000 break;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1001 } else {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1002 curmidinuse = mid;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1003 mid = mid->FreeNext;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1004 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1005 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1006 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1007
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1008 // FreeNext is used for both onInUseList and omFreeList, so clear old before setting new
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1009 m->FreeNext = Self->omFreeList ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1010 Self->omFreeList = m ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1011 Self->omFreeCount ++ ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1012 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1013
a61af66fc99e Initial load
duke
parents:
diff changeset
1014 // Return the monitors of a moribund thread's local free list to
a61af66fc99e Initial load
duke
parents:
diff changeset
1015 // the global free list. Typically a thread calls omFlush() when
a61af66fc99e Initial load
duke
parents:
diff changeset
1016 // it's dying. We could also consider having the VM thread steal
a61af66fc99e Initial load
duke
parents:
diff changeset
1017 // monitors from threads that have not run java code over a few
a61af66fc99e Initial load
duke
parents:
diff changeset
1018 // consecutive STW safepoints. Relatedly, we might decay
a61af66fc99e Initial load
duke
parents:
diff changeset
1019 // omFreeProvision at STW safepoints.
a61af66fc99e Initial load
duke
parents:
diff changeset
1020 //
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1021 // Also return the monitors of a moribund thread"s omInUseList to
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1022 // a global gOmInUseList under the global list lock so these
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1023 // will continue to be scanned.
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1024 //
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1025 // We currently call omFlush() from the Thread:: dtor _after the thread
a61af66fc99e Initial load
duke
parents:
diff changeset
1026 // has been excised from the thread list and is no longer a mutator.
a61af66fc99e Initial load
duke
parents:
diff changeset
1027 // That means that omFlush() can run concurrently with a safepoint and
a61af66fc99e Initial load
duke
parents:
diff changeset
1028 // the scavenge operator. Calling omFlush() from JavaThread::exit() might
a61af66fc99e Initial load
duke
parents:
diff changeset
1029 // be a better choice as we could safely reason that that the JVM is
a61af66fc99e Initial load
duke
parents:
diff changeset
1030 // not at a safepoint at the time of the call, and thus there could
a61af66fc99e Initial load
duke
parents:
diff changeset
1031 // be not inopportune interleavings between omFlush() and the scavenge
a61af66fc99e Initial load
duke
parents:
diff changeset
1032 // operator.
a61af66fc99e Initial load
duke
parents:
diff changeset
1033
a61af66fc99e Initial load
duke
parents:
diff changeset
1034 void ObjectSynchronizer::omFlush (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1035 ObjectMonitor * List = Self->omFreeList ; // Null-terminated SLL
a61af66fc99e Initial load
duke
parents:
diff changeset
1036 Self->omFreeList = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1037 ObjectMonitor * Tail = NULL ;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1038 int Tally = 0;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1039 if (List != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1040 ObjectMonitor * s ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1041 for (s = List ; s != NULL ; s = s->FreeNext) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1042 Tally ++ ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1043 Tail = s ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1044 guarantee (s->object() == NULL, "invariant") ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1045 guarantee (!s->is_busy(), "invariant") ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1046 s->set_owner (NULL) ; // redundant but good hygiene
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1047 TEVENT (omFlush - Move one) ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1048 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1049 guarantee (Tail != NULL && List != NULL, "invariant") ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1050 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1051
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1052 ObjectMonitor * InUseList = Self->omInUseList;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1053 ObjectMonitor * InUseTail = NULL ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1054 int InUseTally = 0;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1055 if (InUseList != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1056 Self->omInUseList = NULL;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1057 ObjectMonitor *curom;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1058 for (curom = InUseList; curom != NULL; curom = curom->FreeNext) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1059 InUseTail = curom;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1060 InUseTally++;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1061 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1062 // TODO debug
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1063 assert(Self->omInUseCount == InUseTally, "inuse count off");
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1064 Self->omInUseCount = 0;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1065 guarantee (InUseTail != NULL && InUseList != NULL, "invariant");
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1066 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1067
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1068 Thread::muxAcquire (&ListLock, "omFlush") ;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1069 if (Tail != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1070 Tail->FreeNext = gFreeList ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1071 gFreeList = List ;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1072 MonitorFreeCount += Tally;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1073 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1074
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1075 if (InUseTail != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1076 InUseTail->FreeNext = gOmInUseList;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1077 gOmInUseList = InUseList;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1078 gOmInUseCount += InUseTally;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1079 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1080
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1081 Thread::muxRelease (&ListLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1082 TEVENT (omFlush) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1083 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1084
a61af66fc99e Initial load
duke
parents:
diff changeset
1085
a61af66fc99e Initial load
duke
parents:
diff changeset
1086 // Get the next block in the block list.
a61af66fc99e Initial load
duke
parents:
diff changeset
1087 static inline ObjectMonitor* next(ObjectMonitor* block) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1088 assert(block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
1089 block = block->FreeNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1090 assert(block == NULL || block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
1091 return block;
a61af66fc99e Initial load
duke
parents:
diff changeset
1092 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1093
a61af66fc99e Initial load
duke
parents:
diff changeset
1094 // Fast path code shared by multiple functions
a61af66fc99e Initial load
duke
parents:
diff changeset
1095 ObjectMonitor* ObjectSynchronizer::inflate_helper(oop obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1096 markOop mark = obj->mark();
a61af66fc99e Initial load
duke
parents:
diff changeset
1097 if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1098 assert(ObjectSynchronizer::verify_objmon_isinpool(mark->monitor()), "monitor is invalid");
a61af66fc99e Initial load
duke
parents:
diff changeset
1099 assert(mark->monitor()->header()->is_neutral(), "monitor must record a good object header");
a61af66fc99e Initial load
duke
parents:
diff changeset
1100 return mark->monitor();
a61af66fc99e Initial load
duke
parents:
diff changeset
1101 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1102 return ObjectSynchronizer::inflate(Thread::current(), obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1103 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1104
a61af66fc99e Initial load
duke
parents:
diff changeset
1105 // Note that we could encounter some performance loss through false-sharing as
a61af66fc99e Initial load
duke
parents:
diff changeset
1106 // multiple locks occupy the same $ line. Padding might be appropriate.
a61af66fc99e Initial load
duke
parents:
diff changeset
1107
a61af66fc99e Initial load
duke
parents:
diff changeset
1108 #define NINFLATIONLOCKS 256
a61af66fc99e Initial load
duke
parents:
diff changeset
1109 static volatile intptr_t InflationLocks [NINFLATIONLOCKS] ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1110
a61af66fc99e Initial load
duke
parents:
diff changeset
1111 static markOop ReadStableMark (oop obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1112 markOop mark = obj->mark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1113 if (!mark->is_being_inflated()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1114 return mark ; // normal fast-path return
a61af66fc99e Initial load
duke
parents:
diff changeset
1115 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1116
a61af66fc99e Initial load
duke
parents:
diff changeset
1117 int its = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1118 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1119 markOop mark = obj->mark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1120 if (!mark->is_being_inflated()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1121 return mark ; // normal fast-path return
a61af66fc99e Initial load
duke
parents:
diff changeset
1122 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1123
a61af66fc99e Initial load
duke
parents:
diff changeset
1124 // The object is being inflated by some other thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
1125 // The caller of ReadStableMark() must wait for inflation to complete.
a61af66fc99e Initial load
duke
parents:
diff changeset
1126 // Avoid live-lock
a61af66fc99e Initial load
duke
parents:
diff changeset
1127 // TODO: consider calling SafepointSynchronize::do_call_back() while
a61af66fc99e Initial load
duke
parents:
diff changeset
1128 // spinning to see if there's a safepoint pending. If so, immediately
a61af66fc99e Initial load
duke
parents:
diff changeset
1129 // yielding or blocking would be appropriate. Avoid spinning while
a61af66fc99e Initial load
duke
parents:
diff changeset
1130 // there is a safepoint pending.
a61af66fc99e Initial load
duke
parents:
diff changeset
1131 // TODO: add inflation contention performance counters.
a61af66fc99e Initial load
duke
parents:
diff changeset
1132 // TODO: restrict the aggregate number of spinners.
a61af66fc99e Initial load
duke
parents:
diff changeset
1133
a61af66fc99e Initial load
duke
parents:
diff changeset
1134 ++its ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1135 if (its > 10000 || !os::is_MP()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1136 if (its & 1) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1137 os::NakedYield() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1138 TEVENT (Inflate: INFLATING - yield) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1139 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1140 // Note that the following code attenuates the livelock problem but is not
a61af66fc99e Initial load
duke
parents:
diff changeset
1141 // a complete remedy. A more complete solution would require that the inflating
a61af66fc99e Initial load
duke
parents:
diff changeset
1142 // thread hold the associated inflation lock. The following code simply restricts
a61af66fc99e Initial load
duke
parents:
diff changeset
1143 // the number of spinners to at most one. We'll have N-2 threads blocked
a61af66fc99e Initial load
duke
parents:
diff changeset
1144 // on the inflationlock, 1 thread holding the inflation lock and using
a61af66fc99e Initial load
duke
parents:
diff changeset
1145 // a yield/park strategy, and 1 thread in the midst of inflation.
a61af66fc99e Initial load
duke
parents:
diff changeset
1146 // A more refined approach would be to change the encoding of INFLATING
a61af66fc99e Initial load
duke
parents:
diff changeset
1147 // to allow encapsulation of a native thread pointer. Threads waiting for
a61af66fc99e Initial load
duke
parents:
diff changeset
1148 // inflation to complete would use CAS to push themselves onto a singly linked
a61af66fc99e Initial load
duke
parents:
diff changeset
1149 // list rooted at the markword. Once enqueued, they'd loop, checking a per-thread flag
a61af66fc99e Initial load
duke
parents:
diff changeset
1150 // and calling park(). When inflation was complete the thread that accomplished inflation
a61af66fc99e Initial load
duke
parents:
diff changeset
1151 // would detach the list and set the markword to inflated with a single CAS and
a61af66fc99e Initial load
duke
parents:
diff changeset
1152 // then for each thread on the list, set the flag and unpark() the thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
1153 // This is conceptually similar to muxAcquire-muxRelease, except that muxRelease
a61af66fc99e Initial load
duke
parents:
diff changeset
1154 // wakes at most one thread whereas we need to wake the entire list.
a61af66fc99e Initial load
duke
parents:
diff changeset
1155 int ix = (intptr_t(obj) >> 5) & (NINFLATIONLOCKS-1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1156 int YieldThenBlock = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1157 assert (ix >= 0 && ix < NINFLATIONLOCKS, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1158 assert ((NINFLATIONLOCKS & (NINFLATIONLOCKS-1)) == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1159 Thread::muxAcquire (InflationLocks + ix, "InflationLock") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1160 while (obj->mark() == markOopDesc::INFLATING()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1161 // Beware: NakedYield() is advisory and has almost no effect on some platforms
a61af66fc99e Initial load
duke
parents:
diff changeset
1162 // so we periodically call Self->_ParkEvent->park(1).
a61af66fc99e Initial load
duke
parents:
diff changeset
1163 // We use a mixed spin/yield/block mechanism.
a61af66fc99e Initial load
duke
parents:
diff changeset
1164 if ((YieldThenBlock++) >= 16) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1165 Thread::current()->_ParkEvent->park(1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1166 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1167 os::NakedYield() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1168 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1169 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1170 Thread::muxRelease (InflationLocks + ix ) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1171 TEVENT (Inflate: INFLATING - yield/park) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1172 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1173 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1174 SpinPause() ; // SMP-polite spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
1175 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1176 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1177 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1178
a61af66fc99e Initial load
duke
parents:
diff changeset
1179 ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1180 // Inflate mutates the heap ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1181 // Relaxing assertion for bug 6320749.
a61af66fc99e Initial load
duke
parents:
diff changeset
1182 assert (Universe::verify_in_progress() ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1183 !SafepointSynchronize::is_at_safepoint(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1184
a61af66fc99e Initial load
duke
parents:
diff changeset
1185 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1186 const markOop mark = object->mark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1187 assert (!mark->has_bias_pattern(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1188
a61af66fc99e Initial load
duke
parents:
diff changeset
1189 // The mark can be in one of the following states:
a61af66fc99e Initial load
duke
parents:
diff changeset
1190 // * Inflated - just return
a61af66fc99e Initial load
duke
parents:
diff changeset
1191 // * Stack-locked - coerce it to inflated
a61af66fc99e Initial load
duke
parents:
diff changeset
1192 // * INFLATING - busy wait for conversion to complete
a61af66fc99e Initial load
duke
parents:
diff changeset
1193 // * Neutral - aggressively inflate the object.
a61af66fc99e Initial load
duke
parents:
diff changeset
1194 // * BIASED - Illegal. We should never see this
a61af66fc99e Initial load
duke
parents:
diff changeset
1195
a61af66fc99e Initial load
duke
parents:
diff changeset
1196 // CASE: inflated
a61af66fc99e Initial load
duke
parents:
diff changeset
1197 if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1198 ObjectMonitor * inf = mark->monitor() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1199 assert (inf->header()->is_neutral(), "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
1200 assert (inf->object() == object, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1201 assert (ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid");
a61af66fc99e Initial load
duke
parents:
diff changeset
1202 return inf ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1203 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1204
a61af66fc99e Initial load
duke
parents:
diff changeset
1205 // CASE: inflation in progress - inflating over a stack-lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1206 // Some other thread is converting from stack-locked to inflated.
a61af66fc99e Initial load
duke
parents:
diff changeset
1207 // Only that thread can complete inflation -- other threads must wait.
a61af66fc99e Initial load
duke
parents:
diff changeset
1208 // The INFLATING value is transient.
a61af66fc99e Initial load
duke
parents:
diff changeset
1209 // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish.
a61af66fc99e Initial load
duke
parents:
diff changeset
1210 // We could always eliminate polling by parking the thread on some auxiliary list.
a61af66fc99e Initial load
duke
parents:
diff changeset
1211 if (mark == markOopDesc::INFLATING()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1212 TEVENT (Inflate: spin while INFLATING) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1213 ReadStableMark(object) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1214 continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1215 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1216
a61af66fc99e Initial load
duke
parents:
diff changeset
1217 // CASE: stack-locked
a61af66fc99e Initial load
duke
parents:
diff changeset
1218 // Could be stack-locked either by this thread or by some other thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
1219 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1220 // Note that we allocate the objectmonitor speculatively, _before_ attempting
a61af66fc99e Initial load
duke
parents:
diff changeset
1221 // to install INFLATING into the mark word. We originally installed INFLATING,
a61af66fc99e Initial load
duke
parents:
diff changeset
1222 // allocated the objectmonitor, and then finally STed the address of the
a61af66fc99e Initial load
duke
parents:
diff changeset
1223 // objectmonitor into the mark. This was correct, but artificially lengthened
a61af66fc99e Initial load
duke
parents:
diff changeset
1224 // the interval in which INFLATED appeared in the mark, thus increasing
a61af66fc99e Initial load
duke
parents:
diff changeset
1225 // the odds of inflation contention.
a61af66fc99e Initial load
duke
parents:
diff changeset
1226 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1227 // We now use per-thread private objectmonitor free lists.
a61af66fc99e Initial load
duke
parents:
diff changeset
1228 // These list are reprovisioned from the global free list outside the
a61af66fc99e Initial load
duke
parents:
diff changeset
1229 // critical INFLATING...ST interval. A thread can transfer
a61af66fc99e Initial load
duke
parents:
diff changeset
1230 // multiple objectmonitors en-mass from the global free list to its local free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
1231 // This reduces coherency traffic and lock contention on the global free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
1232 // Using such local free lists, it doesn't matter if the omAlloc() call appears
a61af66fc99e Initial load
duke
parents:
diff changeset
1233 // before or after the CAS(INFLATING) operation.
a61af66fc99e Initial load
duke
parents:
diff changeset
1234 // See the comments in omAlloc().
a61af66fc99e Initial load
duke
parents:
diff changeset
1235
a61af66fc99e Initial load
duke
parents:
diff changeset
1236 if (mark->has_locker()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1237 ObjectMonitor * m = omAlloc (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1238 // Optimistically prepare the objectmonitor - anticipate successful CAS
a61af66fc99e Initial load
duke
parents:
diff changeset
1239 // We do this before the CAS in order to minimize the length of time
a61af66fc99e Initial load
duke
parents:
diff changeset
1240 // in which INFLATING appears in the mark.
a61af66fc99e Initial load
duke
parents:
diff changeset
1241 m->Recycle();
a61af66fc99e Initial load
duke
parents:
diff changeset
1242 m->_Responsible = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1243 m->OwnerIsThread = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1244 m->_recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1245 m->_SpinDuration = Knob_SpinLimit ; // Consider: maintain by type/class
a61af66fc99e Initial load
duke
parents:
diff changeset
1246
a61af66fc99e Initial load
duke
parents:
diff changeset
1247 markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1248 if (cmp != mark) {
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1249 omRelease (Self, m, true) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1250 continue ; // Interference -- just retry
a61af66fc99e Initial load
duke
parents:
diff changeset
1251 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1252
a61af66fc99e Initial load
duke
parents:
diff changeset
1253 // We've successfully installed INFLATING (0) into the mark-word.
a61af66fc99e Initial load
duke
parents:
diff changeset
1254 // This is the only case where 0 will appear in a mark-work.
a61af66fc99e Initial load
duke
parents:
diff changeset
1255 // Only the singular thread that successfully swings the mark-word
a61af66fc99e Initial load
duke
parents:
diff changeset
1256 // to 0 can perform (or more precisely, complete) inflation.
a61af66fc99e Initial load
duke
parents:
diff changeset
1257 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1258 // Why do we CAS a 0 into the mark-word instead of just CASing the
a61af66fc99e Initial load
duke
parents:
diff changeset
1259 // mark-word from the stack-locked value directly to the new inflated state?
a61af66fc99e Initial load
duke
parents:
diff changeset
1260 // Consider what happens when a thread unlocks a stack-locked object.
a61af66fc99e Initial load
duke
parents:
diff changeset
1261 // It attempts to use CAS to swing the displaced header value from the
a61af66fc99e Initial load
duke
parents:
diff changeset
1262 // on-stack basiclock back into the object header. Recall also that the
a61af66fc99e Initial load
duke
parents:
diff changeset
1263 // header value (hashcode, etc) can reside in (a) the object header, or
a61af66fc99e Initial load
duke
parents:
diff changeset
1264 // (b) a displaced header associated with the stack-lock, or (c) a displaced
a61af66fc99e Initial load
duke
parents:
diff changeset
1265 // header in an objectMonitor. The inflate() routine must copy the header
a61af66fc99e Initial load
duke
parents:
diff changeset
1266 // value from the basiclock on the owner's stack to the objectMonitor, all
a61af66fc99e Initial load
duke
parents:
diff changeset
1267 // the while preserving the hashCode stability invariants. If the owner
a61af66fc99e Initial load
duke
parents:
diff changeset
1268 // decides to release the lock while the value is 0, the unlock will fail
a61af66fc99e Initial load
duke
parents:
diff changeset
1269 // and control will eventually pass from slow_exit() to inflate. The owner
a61af66fc99e Initial load
duke
parents:
diff changeset
1270 // will then spin, waiting for the 0 value to disappear. Put another way,
a61af66fc99e Initial load
duke
parents:
diff changeset
1271 // the 0 causes the owner to stall if the owner happens to try to
a61af66fc99e Initial load
duke
parents:
diff changeset
1272 // drop the lock (restoring the header from the basiclock to the object)
a61af66fc99e Initial load
duke
parents:
diff changeset
1273 // while inflation is in-progress. This protocol avoids races that might
a61af66fc99e Initial load
duke
parents:
diff changeset
1274 // would otherwise permit hashCode values to change or "flicker" for an object.
a61af66fc99e Initial load
duke
parents:
diff changeset
1275 // Critically, while object->mark is 0 mark->displaced_mark_helper() is stable.
a61af66fc99e Initial load
duke
parents:
diff changeset
1276 // 0 serves as a "BUSY" inflate-in-progress indicator.
a61af66fc99e Initial load
duke
parents:
diff changeset
1277
a61af66fc99e Initial load
duke
parents:
diff changeset
1278
a61af66fc99e Initial load
duke
parents:
diff changeset
1279 // fetch the displaced mark from the owner's stack.
a61af66fc99e Initial load
duke
parents:
diff changeset
1280 // The owner can't die or unwind past the lock while our INFLATING
a61af66fc99e Initial load
duke
parents:
diff changeset
1281 // object is in the mark. Furthermore the owner can't complete
a61af66fc99e Initial load
duke
parents:
diff changeset
1282 // an unlock on the object, either.
a61af66fc99e Initial load
duke
parents:
diff changeset
1283 markOop dmw = mark->displaced_mark_helper() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1284 assert (dmw->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1285
a61af66fc99e Initial load
duke
parents:
diff changeset
1286 // Setup monitor fields to proper values -- prepare the monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
1287 m->set_header(dmw) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1288
a61af66fc99e Initial load
duke
parents:
diff changeset
1289 // Optimization: if the mark->locker stack address is associated
a61af66fc99e Initial load
duke
parents:
diff changeset
1290 // with this thread we could simply set m->_owner = Self and
702
b9fba36710f2 6699669: Hotspot server leaves synchronized block with monitor in bad state
xlu
parents: 579
diff changeset
1291 // m->OwnerIsThread = 1. Note that a thread can inflate an object
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1292 // that it has stack-locked -- as might happen in wait() -- directly
a61af66fc99e Initial load
duke
parents:
diff changeset
1293 // with CAS. That is, we can avoid the xchg-NULL .... ST idiom.
702
b9fba36710f2 6699669: Hotspot server leaves synchronized block with monitor in bad state
xlu
parents: 579
diff changeset
1294 m->set_owner(mark->locker());
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1295 m->set_object(object);
a61af66fc99e Initial load
duke
parents:
diff changeset
1296 // TODO-FIXME: assert BasicLock->dhw != 0.
a61af66fc99e Initial load
duke
parents:
diff changeset
1297
a61af66fc99e Initial load
duke
parents:
diff changeset
1298 // Must preserve store ordering. The monitor state must
a61af66fc99e Initial load
duke
parents:
diff changeset
1299 // be stable at the time of publishing the monitor address.
a61af66fc99e Initial load
duke
parents:
diff changeset
1300 guarantee (object->mark() == markOopDesc::INFLATING(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1301 object->release_set_mark(markOopDesc::encode(m));
a61af66fc99e Initial load
duke
parents:
diff changeset
1302
a61af66fc99e Initial load
duke
parents:
diff changeset
1303 // Hopefully the performance counters are allocated on distinct cache lines
a61af66fc99e Initial load
duke
parents:
diff changeset
1304 // to avoid false sharing on MP systems ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1305 if (_sync_Inflations != NULL) _sync_Inflations->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1306 TEVENT(Inflate: overwrite stacklock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1307 if (TraceMonitorInflation) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1308 if (object->is_instance()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1309 ResourceMark rm;
a61af66fc99e Initial load
duke
parents:
diff changeset
1310 tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",
a61af66fc99e Initial load
duke
parents:
diff changeset
1311 (intptr_t) object, (intptr_t) object->mark(),
a61af66fc99e Initial load
duke
parents:
diff changeset
1312 Klass::cast(object->klass())->external_name());
a61af66fc99e Initial load
duke
parents:
diff changeset
1313 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1314 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1315 return m ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1316 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1317
a61af66fc99e Initial load
duke
parents:
diff changeset
1318 // CASE: neutral
a61af66fc99e Initial load
duke
parents:
diff changeset
1319 // TODO-FIXME: for entry we currently inflate and then try to CAS _owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
1320 // If we know we're inflating for entry it's better to inflate by swinging a
a61af66fc99e Initial load
duke
parents:
diff changeset
1321 // pre-locked objectMonitor pointer into the object header. A successful
a61af66fc99e Initial load
duke
parents:
diff changeset
1322 // CAS inflates the object *and* confers ownership to the inflating thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
1323 // In the current implementation we use a 2-step mechanism where we CAS()
a61af66fc99e Initial load
duke
parents:
diff changeset
1324 // to inflate and then CAS() again to try to swing _owner from NULL to Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
1325 // An inflateTry() method that we could call from fast_enter() and slow_enter()
a61af66fc99e Initial load
duke
parents:
diff changeset
1326 // would be useful.
a61af66fc99e Initial load
duke
parents:
diff changeset
1327
a61af66fc99e Initial load
duke
parents:
diff changeset
1328 assert (mark->is_neutral(), "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
1329 ObjectMonitor * m = omAlloc (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1330 // prepare m for installation - set monitor to initial state
a61af66fc99e Initial load
duke
parents:
diff changeset
1331 m->Recycle();
a61af66fc99e Initial load
duke
parents:
diff changeset
1332 m->set_header(mark);
a61af66fc99e Initial load
duke
parents:
diff changeset
1333 m->set_owner(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
1334 m->set_object(object);
a61af66fc99e Initial load
duke
parents:
diff changeset
1335 m->OwnerIsThread = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1336 m->_recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1337 m->_Responsible = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1338 m->_SpinDuration = Knob_SpinLimit ; // consider: keep metastats by type/class
a61af66fc99e Initial load
duke
parents:
diff changeset
1339
a61af66fc99e Initial load
duke
parents:
diff changeset
1340 if (Atomic::cmpxchg_ptr (markOopDesc::encode(m), object->mark_addr(), mark) != mark) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1341 m->set_object (NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1342 m->set_owner (NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1343 m->OwnerIsThread = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1344 m->Recycle() ;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1345 omRelease (Self, m, true) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1346 m = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1347 continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1348 // interference - the markword changed - just retry.
a61af66fc99e Initial load
duke
parents:
diff changeset
1349 // The state-transitions are one-way, so there's no chance of
a61af66fc99e Initial load
duke
parents:
diff changeset
1350 // live-lock -- "Inflated" is an absorbing state.
a61af66fc99e Initial load
duke
parents:
diff changeset
1351 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1352
a61af66fc99e Initial load
duke
parents:
diff changeset
1353 // Hopefully the performance counters are allocated on distinct
a61af66fc99e Initial load
duke
parents:
diff changeset
1354 // cache lines to avoid false sharing on MP systems ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1355 if (_sync_Inflations != NULL) _sync_Inflations->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1356 TEVENT(Inflate: overwrite neutral) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1357 if (TraceMonitorInflation) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1358 if (object->is_instance()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1359 ResourceMark rm;
a61af66fc99e Initial load
duke
parents:
diff changeset
1360 tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",
a61af66fc99e Initial load
duke
parents:
diff changeset
1361 (intptr_t) object, (intptr_t) object->mark(),
a61af66fc99e Initial load
duke
parents:
diff changeset
1362 Klass::cast(object->klass())->external_name());
a61af66fc99e Initial load
duke
parents:
diff changeset
1363 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1364 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1365 return m ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1366 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1367 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1368
a61af66fc99e Initial load
duke
parents:
diff changeset
1369
a61af66fc99e Initial load
duke
parents:
diff changeset
1370 // This the fast monitor enter. The interpreter and compiler use
a61af66fc99e Initial load
duke
parents:
diff changeset
1371 // some assembly copies of this code. Make sure update those code
a61af66fc99e Initial load
duke
parents:
diff changeset
1372 // if the following function is changed. The implementation is
a61af66fc99e Initial load
duke
parents:
diff changeset
1373 // extremely sensitive to race condition. Be careful.
a61af66fc99e Initial load
duke
parents:
diff changeset
1374
a61af66fc99e Initial load
duke
parents:
diff changeset
1375 void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1376 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1377 if (!SafepointSynchronize::is_at_safepoint()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1378 BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1379 if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1380 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
1381 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1382 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1383 assert(!attempt_rebias, "can not rebias toward VM thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
1384 BiasedLocking::revoke_at_safepoint(obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1385 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1386 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
702
b9fba36710f2 6699669: Hotspot server leaves synchronized block with monitor in bad state
xlu
parents: 579
diff changeset
1387 }
b9fba36710f2 6699669: Hotspot server leaves synchronized block with monitor in bad state
xlu
parents: 579
diff changeset
1388
b9fba36710f2 6699669: Hotspot server leaves synchronized block with monitor in bad state
xlu
parents: 579
diff changeset
1389 slow_enter (obj, lock, THREAD) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1390 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1391
a61af66fc99e Initial load
duke
parents:
diff changeset
1392 void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1393 assert(!object->mark()->has_bias_pattern(), "should not see bias pattern here");
a61af66fc99e Initial load
duke
parents:
diff changeset
1394 // if displaced header is null, the previous enter is recursive enter, no-op
a61af66fc99e Initial load
duke
parents:
diff changeset
1395 markOop dhw = lock->displaced_header();
a61af66fc99e Initial load
duke
parents:
diff changeset
1396 markOop mark ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1397 if (dhw == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1398 // Recursive stack-lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1399 // Diagnostics -- Could be: stack-locked, inflating, inflated.
a61af66fc99e Initial load
duke
parents:
diff changeset
1400 mark = object->mark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1401 assert (!mark->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1402 if (mark->has_locker() && mark != markOopDesc::INFLATING()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1403 assert(THREAD->is_lock_owned((address)mark->locker()), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1404 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1405 if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1406 ObjectMonitor * m = mark->monitor() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1407 assert(((oop)(m->object()))->mark() == mark, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1408 assert(m->is_entered(THREAD), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1409 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1410 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1411 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1412
a61af66fc99e Initial load
duke
parents:
diff changeset
1413 mark = object->mark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1414
a61af66fc99e Initial load
duke
parents:
diff changeset
1415 // If the object is stack-locked by the current thread, try to
a61af66fc99e Initial load
duke
parents:
diff changeset
1416 // swing the displaced header from the box back to the mark.
a61af66fc99e Initial load
duke
parents:
diff changeset
1417 if (mark == (markOop) lock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1418 assert (dhw->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1419 if ((markOop) Atomic::cmpxchg_ptr (dhw, object->mark_addr(), mark) == mark) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1420 TEVENT (fast_exit: release stacklock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1421 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
1422 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1423 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1424
a61af66fc99e Initial load
duke
parents:
diff changeset
1425 ObjectSynchronizer::inflate(THREAD, object)->exit (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1426 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1427
a61af66fc99e Initial load
duke
parents:
diff changeset
1428 // This routine is used to handle interpreter/compiler slow case
a61af66fc99e Initial load
duke
parents:
diff changeset
1429 // We don't need to use fast path here, because it must have been
a61af66fc99e Initial load
duke
parents:
diff changeset
1430 // failed in the interpreter/compiler code.
a61af66fc99e Initial load
duke
parents:
diff changeset
1431 void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1432 markOop mark = obj->mark();
a61af66fc99e Initial load
duke
parents:
diff changeset
1433 assert(!mark->has_bias_pattern(), "should not see bias pattern here");
a61af66fc99e Initial load
duke
parents:
diff changeset
1434
a61af66fc99e Initial load
duke
parents:
diff changeset
1435 if (mark->is_neutral()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1436 // Anticipate successful CAS -- the ST of the displaced mark must
a61af66fc99e Initial load
duke
parents:
diff changeset
1437 // be visible <= the ST performed by the CAS.
a61af66fc99e Initial load
duke
parents:
diff changeset
1438 lock->set_displaced_header(mark);
a61af66fc99e Initial load
duke
parents:
diff changeset
1439 if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1440 TEVENT (slow_enter: release stacklock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1441 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1442 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1443 // Fall through to inflate() ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1444 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
1445 if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1446 assert(lock != mark->locker(), "must not re-lock the same lock");
a61af66fc99e Initial load
duke
parents:
diff changeset
1447 assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
a61af66fc99e Initial load
duke
parents:
diff changeset
1448 lock->set_displaced_header(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
1449 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
1450 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1451
a61af66fc99e Initial load
duke
parents:
diff changeset
1452 #if 0
a61af66fc99e Initial load
duke
parents:
diff changeset
1453 // The following optimization isn't particularly useful.
a61af66fc99e Initial load
duke
parents:
diff changeset
1454 if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1455 lock->set_displaced_header (NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1456 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1457 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1458 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1459
a61af66fc99e Initial load
duke
parents:
diff changeset
1460 // The object header will never be displaced to this lock,
a61af66fc99e Initial load
duke
parents:
diff changeset
1461 // so it does not matter what the value is, except that it
a61af66fc99e Initial load
duke
parents:
diff changeset
1462 // must be non-zero to avoid looking like a re-entrant lock,
a61af66fc99e Initial load
duke
parents:
diff changeset
1463 // and must not look locked either.
a61af66fc99e Initial load
duke
parents:
diff changeset
1464 lock->set_displaced_header(markOopDesc::unused_mark());
a61af66fc99e Initial load
duke
parents:
diff changeset
1465 ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1466 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1467
a61af66fc99e Initial load
duke
parents:
diff changeset
1468 // This routine is used to handle interpreter/compiler slow case
a61af66fc99e Initial load
duke
parents:
diff changeset
1469 // We don't need to use fast path here, because it must have
a61af66fc99e Initial load
duke
parents:
diff changeset
1470 // failed in the interpreter/compiler code. Simply use the heavy
a61af66fc99e Initial load
duke
parents:
diff changeset
1471 // weight monitor should be ok, unless someone find otherwise.
a61af66fc99e Initial load
duke
parents:
diff changeset
1472 void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1473 fast_exit (object, lock, THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1474 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1475
a61af66fc99e Initial load
duke
parents:
diff changeset
1476 // NOTE: must use heavy weight monitor to handle jni monitor enter
a61af66fc99e Initial load
duke
parents:
diff changeset
1477 void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) { // possible entry from jni enter
a61af66fc99e Initial load
duke
parents:
diff changeset
1478 // the current locking is from JNI instead of Java code
a61af66fc99e Initial load
duke
parents:
diff changeset
1479 TEVENT (jni_enter) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1480 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1481 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1482 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1483 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1484 THREAD->set_current_pending_monitor_is_from_java(false);
a61af66fc99e Initial load
duke
parents:
diff changeset
1485 ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1486 THREAD->set_current_pending_monitor_is_from_java(true);
a61af66fc99e Initial load
duke
parents:
diff changeset
1487 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1488
a61af66fc99e Initial load
duke
parents:
diff changeset
1489 // NOTE: must use heavy weight monitor to handle jni monitor enter
a61af66fc99e Initial load
duke
parents:
diff changeset
1490 bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1491 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1492 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1493 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1494 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1495
a61af66fc99e Initial load
duke
parents:
diff changeset
1496 ObjectMonitor* monitor = ObjectSynchronizer::inflate_helper(obj());
a61af66fc99e Initial load
duke
parents:
diff changeset
1497 return monitor->try_enter(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1498 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1499
a61af66fc99e Initial load
duke
parents:
diff changeset
1500
a61af66fc99e Initial load
duke
parents:
diff changeset
1501 // NOTE: must use heavy weight monitor to handle jni monitor exit
a61af66fc99e Initial load
duke
parents:
diff changeset
1502 void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1503 TEVENT (jni_exit) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1504 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1505 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1506 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1507 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1508
a61af66fc99e Initial load
duke
parents:
diff changeset
1509 ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1510 // If this thread has locked the object, exit the monitor. Note: can't use
a61af66fc99e Initial load
duke
parents:
diff changeset
1511 // monitor->check(CHECK); must exit even if an exception is pending.
a61af66fc99e Initial load
duke
parents:
diff changeset
1512 if (monitor->check(THREAD)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1513 monitor->exit(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1514 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1515 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1516
a61af66fc99e Initial load
duke
parents:
diff changeset
1517 // complete_exit()/reenter() are used to wait on a nested lock
a61af66fc99e Initial load
duke
parents:
diff changeset
1518 // i.e. to give up an outer lock completely and then re-enter
a61af66fc99e Initial load
duke
parents:
diff changeset
1519 // Used when holding nested locks - lock acquisition order: lock1 then lock2
a61af66fc99e Initial load
duke
parents:
diff changeset
1520 // 1) complete_exit lock1 - saving recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
1521 // 2) wait on lock2
a61af66fc99e Initial load
duke
parents:
diff changeset
1522 // 3) when notified on lock2, unlock lock2
a61af66fc99e Initial load
duke
parents:
diff changeset
1523 // 4) reenter lock1 with original recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
1524 // 5) lock lock2
a61af66fc99e Initial load
duke
parents:
diff changeset
1525 // NOTE: must use heavy weight monitor to handle complete_exit/reenter()
a61af66fc99e Initial load
duke
parents:
diff changeset
1526 intptr_t ObjectSynchronizer::complete_exit(Handle obj, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1527 TEVENT (complete_exit) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1528 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1529 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1530 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1531 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1532
a61af66fc99e Initial load
duke
parents:
diff changeset
1533 ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
a61af66fc99e Initial load
duke
parents:
diff changeset
1534
a61af66fc99e Initial load
duke
parents:
diff changeset
1535 return monitor->complete_exit(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1536 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1537
a61af66fc99e Initial load
duke
parents:
diff changeset
1538 // NOTE: must use heavy weight monitor to handle complete_exit/reenter()
a61af66fc99e Initial load
duke
parents:
diff changeset
1539 void ObjectSynchronizer::reenter(Handle obj, intptr_t recursion, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1540 TEVENT (reenter) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1541 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1542 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1543 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1544 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1545
a61af66fc99e Initial load
duke
parents:
diff changeset
1546 ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
a61af66fc99e Initial load
duke
parents:
diff changeset
1547
a61af66fc99e Initial load
duke
parents:
diff changeset
1548 monitor->reenter(recursion, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1549 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1550
a61af66fc99e Initial load
duke
parents:
diff changeset
1551 // This exists only as a workaround of dtrace bug 6254741
a61af66fc99e Initial load
duke
parents:
diff changeset
1552 int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1553 DTRACE_MONITOR_PROBE(waited, monitor, obj(), thr);
a61af66fc99e Initial load
duke
parents:
diff changeset
1554 return 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
1555 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1556
a61af66fc99e Initial load
duke
parents:
diff changeset
1557 // NOTE: must use heavy weight monitor to handle wait()
a61af66fc99e Initial load
duke
parents:
diff changeset
1558 void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1559 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1560 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1561 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1562 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1563 if (millis < 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1564 TEVENT (wait - throw IAX) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1565 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
1566 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1567 ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
a61af66fc99e Initial load
duke
parents:
diff changeset
1568 DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
a61af66fc99e Initial load
duke
parents:
diff changeset
1569 monitor->wait(millis, true, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1570
a61af66fc99e Initial load
duke
parents:
diff changeset
1571 /* This dummy call is in place to get around dtrace bug 6254741. Once
a61af66fc99e Initial load
duke
parents:
diff changeset
1572 that's fixed we can uncomment the following line and remove the call */
a61af66fc99e Initial load
duke
parents:
diff changeset
1573 // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1574 dtrace_waited_probe(monitor, obj, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1575 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1576
a61af66fc99e Initial load
duke
parents:
diff changeset
1577 void ObjectSynchronizer::waitUninterruptibly (Handle obj, jlong millis, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1578 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1579 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1580 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1581 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1582 if (millis < 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1583 TEVENT (wait - throw IAX) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1584 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
1585 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1586 ObjectSynchronizer::inflate(THREAD, obj()) -> wait(millis, false, THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1587 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1588
a61af66fc99e Initial load
duke
parents:
diff changeset
1589 void ObjectSynchronizer::notify(Handle obj, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1590 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1591 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1592 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1593 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1594
a61af66fc99e Initial load
duke
parents:
diff changeset
1595 markOop mark = obj->mark();
a61af66fc99e Initial load
duke
parents:
diff changeset
1596 if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1597 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
1598 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1599 ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1600 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1601
a61af66fc99e Initial load
duke
parents:
diff changeset
1602 // NOTE: see comment of notify()
a61af66fc99e Initial load
duke
parents:
diff changeset
1603 void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1604 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1605 BiasedLocking::revoke_and_rebias(obj, false, THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1606 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1607 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1608
a61af66fc99e Initial load
duke
parents:
diff changeset
1609 markOop mark = obj->mark();
a61af66fc99e Initial load
duke
parents:
diff changeset
1610 if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1611 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
1612 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1613 ObjectSynchronizer::inflate(THREAD, obj())->notifyAll(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1614 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1615
a61af66fc99e Initial load
duke
parents:
diff changeset
1616 intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1617 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1618 // NOTE: many places throughout the JVM do not expect a safepoint
a61af66fc99e Initial load
duke
parents:
diff changeset
1619 // to be taken here, in particular most operations on perm gen
a61af66fc99e Initial load
duke
parents:
diff changeset
1620 // objects. However, we only ever bias Java instances and all of
a61af66fc99e Initial load
duke
parents:
diff changeset
1621 // the call sites of identity_hash that might revoke biases have
a61af66fc99e Initial load
duke
parents:
diff changeset
1622 // been checked to make sure they can handle a safepoint. The
a61af66fc99e Initial load
duke
parents:
diff changeset
1623 // added check of the bias pattern is to avoid useless calls to
a61af66fc99e Initial load
duke
parents:
diff changeset
1624 // thread-local storage.
a61af66fc99e Initial load
duke
parents:
diff changeset
1625 if (obj->mark()->has_bias_pattern()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1626 // Box and unbox the raw reference just in case we cause a STW safepoint.
a61af66fc99e Initial load
duke
parents:
diff changeset
1627 Handle hobj (Self, obj) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1628 // Relaxing assertion for bug 6320749.
a61af66fc99e Initial load
duke
parents:
diff changeset
1629 assert (Universe::verify_in_progress() ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1630 !SafepointSynchronize::is_at_safepoint(),
a61af66fc99e Initial load
duke
parents:
diff changeset
1631 "biases should not be seen by VM thread here");
a61af66fc99e Initial load
duke
parents:
diff changeset
1632 BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
a61af66fc99e Initial load
duke
parents:
diff changeset
1633 obj = hobj() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1634 assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1635 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1636 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1637
a61af66fc99e Initial load
duke
parents:
diff changeset
1638 // hashCode() is a heap mutator ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1639 // Relaxing assertion for bug 6320749.
a61af66fc99e Initial load
duke
parents:
diff changeset
1640 assert (Universe::verify_in_progress() ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1641 !SafepointSynchronize::is_at_safepoint(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1642 assert (Universe::verify_in_progress() ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1643 Self->is_Java_thread() , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1644 assert (Universe::verify_in_progress() ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1645 ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1646
a61af66fc99e Initial load
duke
parents:
diff changeset
1647 ObjectMonitor* monitor = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
1648 markOop temp, test;
a61af66fc99e Initial load
duke
parents:
diff changeset
1649 intptr_t hash;
a61af66fc99e Initial load
duke
parents:
diff changeset
1650 markOop mark = ReadStableMark (obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1651
a61af66fc99e Initial load
duke
parents:
diff changeset
1652 // object should remain ineligible for biased locking
a61af66fc99e Initial load
duke
parents:
diff changeset
1653 assert (!mark->has_bias_pattern(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1654
a61af66fc99e Initial load
duke
parents:
diff changeset
1655 if (mark->is_neutral()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1656 hash = mark->hash(); // this is a normal header
a61af66fc99e Initial load
duke
parents:
diff changeset
1657 if (hash) { // if it has hash, just return it
a61af66fc99e Initial load
duke
parents:
diff changeset
1658 return hash;
a61af66fc99e Initial load
duke
parents:
diff changeset
1659 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1660 hash = get_next_hash(Self, obj); // allocate a new hash code
a61af66fc99e Initial load
duke
parents:
diff changeset
1661 temp = mark->copy_set_hash(hash); // merge the hash code into header
a61af66fc99e Initial load
duke
parents:
diff changeset
1662 // use (machine word version) atomic operation to install the hash
a61af66fc99e Initial load
duke
parents:
diff changeset
1663 test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
a61af66fc99e Initial load
duke
parents:
diff changeset
1664 if (test == mark) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1665 return hash;
a61af66fc99e Initial load
duke
parents:
diff changeset
1666 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1667 // If atomic operation failed, we must inflate the header
a61af66fc99e Initial load
duke
parents:
diff changeset
1668 // into heavy weight monitor. We could add more code here
a61af66fc99e Initial load
duke
parents:
diff changeset
1669 // for fast path, but it does not worth the complexity.
a61af66fc99e Initial load
duke
parents:
diff changeset
1670 } else if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1671 monitor = mark->monitor();
a61af66fc99e Initial load
duke
parents:
diff changeset
1672 temp = monitor->header();
a61af66fc99e Initial load
duke
parents:
diff changeset
1673 assert (temp->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1674 hash = temp->hash();
a61af66fc99e Initial load
duke
parents:
diff changeset
1675 if (hash) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1676 return hash;
a61af66fc99e Initial load
duke
parents:
diff changeset
1677 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1678 // Skip to the following code to reduce code size
a61af66fc99e Initial load
duke
parents:
diff changeset
1679 } else if (Self->is_lock_owned((address)mark->locker())) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1680 temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
a61af66fc99e Initial load
duke
parents:
diff changeset
1681 assert (temp->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1682 hash = temp->hash(); // by current thread, check if the displaced
a61af66fc99e Initial load
duke
parents:
diff changeset
1683 if (hash) { // header contains hash code
a61af66fc99e Initial load
duke
parents:
diff changeset
1684 return hash;
a61af66fc99e Initial load
duke
parents:
diff changeset
1685 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1686 // WARNING:
a61af66fc99e Initial load
duke
parents:
diff changeset
1687 // The displaced header is strictly immutable.
a61af66fc99e Initial load
duke
parents:
diff changeset
1688 // It can NOT be changed in ANY cases. So we have
a61af66fc99e Initial load
duke
parents:
diff changeset
1689 // to inflate the header into heavyweight monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
1690 // even the current thread owns the lock. The reason
a61af66fc99e Initial load
duke
parents:
diff changeset
1691 // is the BasicLock (stack slot) will be asynchronously
a61af66fc99e Initial load
duke
parents:
diff changeset
1692 // read by other threads during the inflate() function.
a61af66fc99e Initial load
duke
parents:
diff changeset
1693 // Any change to stack may not propagate to other threads
a61af66fc99e Initial load
duke
parents:
diff changeset
1694 // correctly.
a61af66fc99e Initial load
duke
parents:
diff changeset
1695 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1696
a61af66fc99e Initial load
duke
parents:
diff changeset
1697 // Inflate the monitor to set hash code
a61af66fc99e Initial load
duke
parents:
diff changeset
1698 monitor = ObjectSynchronizer::inflate(Self, obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1699 // Load displaced header and check it has hash code
a61af66fc99e Initial load
duke
parents:
diff changeset
1700 mark = monitor->header();
a61af66fc99e Initial load
duke
parents:
diff changeset
1701 assert (mark->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1702 hash = mark->hash();
a61af66fc99e Initial load
duke
parents:
diff changeset
1703 if (hash == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1704 hash = get_next_hash(Self, obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1705 temp = mark->copy_set_hash(hash); // merge hash code into header
a61af66fc99e Initial load
duke
parents:
diff changeset
1706 assert (temp->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1707 test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
a61af66fc99e Initial load
duke
parents:
diff changeset
1708 if (test != mark) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1709 // The only update to the header in the monitor (outside GC)
a61af66fc99e Initial load
duke
parents:
diff changeset
1710 // is install the hash code. If someone add new usage of
a61af66fc99e Initial load
duke
parents:
diff changeset
1711 // displaced header, please update this code
a61af66fc99e Initial load
duke
parents:
diff changeset
1712 hash = test->hash();
a61af66fc99e Initial load
duke
parents:
diff changeset
1713 assert (test->is_neutral(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1714 assert (hash != 0, "Trivial unexpected object/monitor header usage.");
a61af66fc99e Initial load
duke
parents:
diff changeset
1715 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1716 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1717 // We finally get the hash
a61af66fc99e Initial load
duke
parents:
diff changeset
1718 return hash;
a61af66fc99e Initial load
duke
parents:
diff changeset
1719 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1720
a61af66fc99e Initial load
duke
parents:
diff changeset
1721 // Deprecated -- use FastHashCode() instead.
a61af66fc99e Initial load
duke
parents:
diff changeset
1722
a61af66fc99e Initial load
duke
parents:
diff changeset
1723 intptr_t ObjectSynchronizer::identity_hash_value_for(Handle obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1724 return FastHashCode (Thread::current(), obj()) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1725 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1726
a61af66fc99e Initial load
duke
parents:
diff changeset
1727 bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* thread,
a61af66fc99e Initial load
duke
parents:
diff changeset
1728 Handle h_obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1729 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1730 BiasedLocking::revoke_and_rebias(h_obj, false, thread);
a61af66fc99e Initial load
duke
parents:
diff changeset
1731 assert(!h_obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1732 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1733
a61af66fc99e Initial load
duke
parents:
diff changeset
1734 assert(thread == JavaThread::current(), "Can only be called on current thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
1735 oop obj = h_obj();
a61af66fc99e Initial load
duke
parents:
diff changeset
1736
a61af66fc99e Initial load
duke
parents:
diff changeset
1737 markOop mark = ReadStableMark (obj) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1738
a61af66fc99e Initial load
duke
parents:
diff changeset
1739 // Uncontended case, header points to stack
a61af66fc99e Initial load
duke
parents:
diff changeset
1740 if (mark->has_locker()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1741 return thread->is_lock_owned((address)mark->locker());
a61af66fc99e Initial load
duke
parents:
diff changeset
1742 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1743 // Contended case, header points to ObjectMonitor (tagged pointer)
a61af66fc99e Initial load
duke
parents:
diff changeset
1744 if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1745 ObjectMonitor* monitor = mark->monitor();
a61af66fc99e Initial load
duke
parents:
diff changeset
1746 return monitor->is_entered(thread) != 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1747 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1748 // Unlocked case, header in place
a61af66fc99e Initial load
duke
parents:
diff changeset
1749 assert(mark->is_neutral(), "sanity check");
a61af66fc99e Initial load
duke
parents:
diff changeset
1750 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
1751 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1752
a61af66fc99e Initial load
duke
parents:
diff changeset
1753 // Be aware of this method could revoke bias of the lock object.
a61af66fc99e Initial load
duke
parents:
diff changeset
1754 // This method querys the ownership of the lock handle specified by 'h_obj'.
a61af66fc99e Initial load
duke
parents:
diff changeset
1755 // If the current thread owns the lock, it returns owner_self. If no
a61af66fc99e Initial load
duke
parents:
diff changeset
1756 // thread owns the lock, it returns owner_none. Otherwise, it will return
a61af66fc99e Initial load
duke
parents:
diff changeset
1757 // ower_other.
a61af66fc99e Initial load
duke
parents:
diff changeset
1758 ObjectSynchronizer::LockOwnership ObjectSynchronizer::query_lock_ownership
a61af66fc99e Initial load
duke
parents:
diff changeset
1759 (JavaThread *self, Handle h_obj) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1760 // The caller must beware this method can revoke bias, and
a61af66fc99e Initial load
duke
parents:
diff changeset
1761 // revocation can result in a safepoint.
a61af66fc99e Initial load
duke
parents:
diff changeset
1762 assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1763 assert (self->thread_state() != _thread_blocked , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1764
a61af66fc99e Initial load
duke
parents:
diff changeset
1765 // Possible mark states: neutral, biased, stack-locked, inflated
a61af66fc99e Initial load
duke
parents:
diff changeset
1766
a61af66fc99e Initial load
duke
parents:
diff changeset
1767 if (UseBiasedLocking && h_obj()->mark()->has_bias_pattern()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1768 // CASE: biased
a61af66fc99e Initial load
duke
parents:
diff changeset
1769 BiasedLocking::revoke_and_rebias(h_obj, false, self);
a61af66fc99e Initial load
duke
parents:
diff changeset
1770 assert(!h_obj->mark()->has_bias_pattern(),
a61af66fc99e Initial load
duke
parents:
diff changeset
1771 "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1772 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1773
a61af66fc99e Initial load
duke
parents:
diff changeset
1774 assert(self == JavaThread::current(), "Can only be called on current thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
1775 oop obj = h_obj();
a61af66fc99e Initial load
duke
parents:
diff changeset
1776 markOop mark = ReadStableMark (obj) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1777
a61af66fc99e Initial load
duke
parents:
diff changeset
1778 // CASE: stack-locked. Mark points to a BasicLock on the owner's stack.
a61af66fc99e Initial load
duke
parents:
diff changeset
1779 if (mark->has_locker()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1780 return self->is_lock_owned((address)mark->locker()) ?
a61af66fc99e Initial load
duke
parents:
diff changeset
1781 owner_self : owner_other;
a61af66fc99e Initial load
duke
parents:
diff changeset
1782 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1783
a61af66fc99e Initial load
duke
parents:
diff changeset
1784 // CASE: inflated. Mark (tagged pointer) points to an objectMonitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
1785 // The Object:ObjectMonitor relationship is stable as long as we're
a61af66fc99e Initial load
duke
parents:
diff changeset
1786 // not at a safepoint.
a61af66fc99e Initial load
duke
parents:
diff changeset
1787 if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1788 void * owner = mark->monitor()->_owner ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1789 if (owner == NULL) return owner_none ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1790 return (owner == self ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1791 self->is_lock_owned((address)owner)) ? owner_self : owner_other;
a61af66fc99e Initial load
duke
parents:
diff changeset
1792 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1793
a61af66fc99e Initial load
duke
parents:
diff changeset
1794 // CASE: neutral
a61af66fc99e Initial load
duke
parents:
diff changeset
1795 assert(mark->is_neutral(), "sanity check");
a61af66fc99e Initial load
duke
parents:
diff changeset
1796 return owner_none ; // it's unlocked
a61af66fc99e Initial load
duke
parents:
diff changeset
1797 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1798
a61af66fc99e Initial load
duke
parents:
diff changeset
1799 // FIXME: jvmti should call this
a61af66fc99e Initial load
duke
parents:
diff changeset
1800 JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1801 if (UseBiasedLocking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1802 if (SafepointSynchronize::is_at_safepoint()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1803 BiasedLocking::revoke_at_safepoint(h_obj);
a61af66fc99e Initial load
duke
parents:
diff changeset
1804 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1805 BiasedLocking::revoke_and_rebias(h_obj, false, JavaThread::current());
a61af66fc99e Initial load
duke
parents:
diff changeset
1806 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1807 assert(!h_obj->mark()->has_bias_pattern(), "biases should be revoked by now");
a61af66fc99e Initial load
duke
parents:
diff changeset
1808 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1809
a61af66fc99e Initial load
duke
parents:
diff changeset
1810 oop obj = h_obj();
a61af66fc99e Initial load
duke
parents:
diff changeset
1811 address owner = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
1812
a61af66fc99e Initial load
duke
parents:
diff changeset
1813 markOop mark = ReadStableMark (obj) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1814
a61af66fc99e Initial load
duke
parents:
diff changeset
1815 // Uncontended case, header points to stack
a61af66fc99e Initial load
duke
parents:
diff changeset
1816 if (mark->has_locker()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1817 owner = (address) mark->locker();
a61af66fc99e Initial load
duke
parents:
diff changeset
1818 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1819
a61af66fc99e Initial load
duke
parents:
diff changeset
1820 // Contended case, header points to ObjectMonitor (tagged pointer)
a61af66fc99e Initial load
duke
parents:
diff changeset
1821 if (mark->has_monitor()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1822 ObjectMonitor* monitor = mark->monitor();
a61af66fc99e Initial load
duke
parents:
diff changeset
1823 assert(monitor != NULL, "monitor should be non-null");
a61af66fc99e Initial load
duke
parents:
diff changeset
1824 owner = (address) monitor->owner();
a61af66fc99e Initial load
duke
parents:
diff changeset
1825 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1826
a61af66fc99e Initial load
duke
parents:
diff changeset
1827 if (owner != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1828 return Threads::owning_thread_from_monitor_owner(owner, doLock);
a61af66fc99e Initial load
duke
parents:
diff changeset
1829 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1830
a61af66fc99e Initial load
duke
parents:
diff changeset
1831 // Unlocked case, header in place
a61af66fc99e Initial load
duke
parents:
diff changeset
1832 // Cannot have assertion since this object may have been
a61af66fc99e Initial load
duke
parents:
diff changeset
1833 // locked by another thread when reaching here.
a61af66fc99e Initial load
duke
parents:
diff changeset
1834 // assert(mark->is_neutral(), "sanity check");
a61af66fc99e Initial load
duke
parents:
diff changeset
1835
a61af66fc99e Initial load
duke
parents:
diff changeset
1836 return NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
1837 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1838
a61af66fc99e Initial load
duke
parents:
diff changeset
1839 // Iterate through monitor cache and attempt to release thread's monitors
a61af66fc99e Initial load
duke
parents:
diff changeset
1840 // Gives up on a particular monitor if an exception occurs, but continues
a61af66fc99e Initial load
duke
parents:
diff changeset
1841 // the overall iteration, swallowing the exception.
a61af66fc99e Initial load
duke
parents:
diff changeset
1842 class ReleaseJavaMonitorsClosure: public MonitorClosure {
a61af66fc99e Initial load
duke
parents:
diff changeset
1843 private:
a61af66fc99e Initial load
duke
parents:
diff changeset
1844 TRAPS;
a61af66fc99e Initial load
duke
parents:
diff changeset
1845
a61af66fc99e Initial load
duke
parents:
diff changeset
1846 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
1847 ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
a61af66fc99e Initial load
duke
parents:
diff changeset
1848 void do_monitor(ObjectMonitor* mid) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1849 if (mid->owner() == THREAD) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1850 (void)mid->complete_exit(CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
1851 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1852 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1853 };
a61af66fc99e Initial load
duke
parents:
diff changeset
1854
a61af66fc99e Initial load
duke
parents:
diff changeset
1855 // Release all inflated monitors owned by THREAD. Lightweight monitors are
a61af66fc99e Initial load
duke
parents:
diff changeset
1856 // ignored. This is meant to be called during JNI thread detach which assumes
a61af66fc99e Initial load
duke
parents:
diff changeset
1857 // all remaining monitors are heavyweight. All exceptions are swallowed.
a61af66fc99e Initial load
duke
parents:
diff changeset
1858 // Scanning the extant monitor list can be time consuming.
a61af66fc99e Initial load
duke
parents:
diff changeset
1859 // A simple optimization is to add a per-thread flag that indicates a thread
a61af66fc99e Initial load
duke
parents:
diff changeset
1860 // called jni_monitorenter() during its lifetime.
a61af66fc99e Initial load
duke
parents:
diff changeset
1861 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1862 // Instead of No_Savepoint_Verifier it might be cheaper to
a61af66fc99e Initial load
duke
parents:
diff changeset
1863 // use an idiom of the form:
a61af66fc99e Initial load
duke
parents:
diff changeset
1864 // auto int tmp = SafepointSynchronize::_safepoint_counter ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1865 // <code that must not run at safepoint>
a61af66fc99e Initial load
duke
parents:
diff changeset
1866 // guarantee (((tmp ^ _safepoint_counter) | (tmp & 1)) == 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1867 // Since the tests are extremely cheap we could leave them enabled
a61af66fc99e Initial load
duke
parents:
diff changeset
1868 // for normal product builds.
a61af66fc99e Initial load
duke
parents:
diff changeset
1869
a61af66fc99e Initial load
duke
parents:
diff changeset
1870 void ObjectSynchronizer::release_monitors_owned_by_thread(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1871 assert(THREAD == JavaThread::current(), "must be current Java thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
1872 No_Safepoint_Verifier nsv ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1873 ReleaseJavaMonitorsClosure rjmc(THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
1874 Thread::muxAcquire(&ListLock, "release_monitors_owned_by_thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
1875 ObjectSynchronizer::monitors_iterate(&rjmc);
a61af66fc99e Initial load
duke
parents:
diff changeset
1876 Thread::muxRelease(&ListLock);
a61af66fc99e Initial load
duke
parents:
diff changeset
1877 THREAD->clear_pending_exception();
a61af66fc99e Initial load
duke
parents:
diff changeset
1878 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1879
a61af66fc99e Initial load
duke
parents:
diff changeset
1880 // Visitors ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1881
a61af66fc99e Initial load
duke
parents:
diff changeset
1882 void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1883 ObjectMonitor* block = gBlockList;
a61af66fc99e Initial load
duke
parents:
diff changeset
1884 ObjectMonitor* mid;
a61af66fc99e Initial load
duke
parents:
diff changeset
1885 while (block) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1886 assert(block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
1887 for (int i = _BLOCKSIZE - 1; i > 0; i--) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1888 mid = block + i;
a61af66fc99e Initial load
duke
parents:
diff changeset
1889 oop object = (oop) mid->object();
a61af66fc99e Initial load
duke
parents:
diff changeset
1890 if (object != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1891 closure->do_monitor(mid);
a61af66fc99e Initial load
duke
parents:
diff changeset
1892 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1893 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1894 block = (ObjectMonitor*) block->FreeNext;
a61af66fc99e Initial load
duke
parents:
diff changeset
1895 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1896 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1897
a61af66fc99e Initial load
duke
parents:
diff changeset
1898 void ObjectSynchronizer::oops_do(OopClosure* f) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1899 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
a61af66fc99e Initial load
duke
parents:
diff changeset
1900 for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1901 assert(block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
1902 for (int i = 1; i < _BLOCKSIZE; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1903 ObjectMonitor* mid = &block[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
1904 if (mid->object() != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1905 f->do_oop((oop*)mid->object_addr());
a61af66fc99e Initial load
duke
parents:
diff changeset
1906 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1907 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1908 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1909 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1910
a61af66fc99e Initial load
duke
parents:
diff changeset
1911 // Deflate_idle_monitors() is called at all safepoints, immediately
a61af66fc99e Initial load
duke
parents:
diff changeset
1912 // after all mutators are stopped, but before any objects have moved.
a61af66fc99e Initial load
duke
parents:
diff changeset
1913 // It traverses the list of known monitors, deflating where possible.
a61af66fc99e Initial load
duke
parents:
diff changeset
1914 // The scavenged monitor are returned to the monitor free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
1915 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1916 // Beware that we scavenge at *every* stop-the-world point.
a61af66fc99e Initial load
duke
parents:
diff changeset
1917 // Having a large number of monitors in-circulation negatively
a61af66fc99e Initial load
duke
parents:
diff changeset
1918 // impacts the performance of some applications (e.g., PointBase).
a61af66fc99e Initial load
duke
parents:
diff changeset
1919 // Broadly, we want to minimize the # of monitors in circulation.
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1920 //
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1921 // We have added a flag, MonitorInUseLists, which creates a list
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1922 // of active monitors for each thread. deflate_idle_monitors()
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1923 // only scans the per-thread inuse lists. omAlloc() puts all
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1924 // assigned monitors on the per-thread list. deflate_idle_monitors()
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1925 // returns the non-busy monitors to the global free list.
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1926 // When a thread dies, omFlush() adds the list of active monitors for
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1927 // that thread to a global gOmInUseList acquiring the
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1928 // global list lock. deflate_idle_monitors() acquires the global
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1929 // list lock to scan for non-busy monitors to the global free list.
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1930 // An alternative could have used a single global inuse list. The
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1931 // downside would have been the additional cost of acquiring the global list lock
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1932 // for every omAlloc().
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1933 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1934 // Perversely, the heap size -- and thus the STW safepoint rate --
a61af66fc99e Initial load
duke
parents:
diff changeset
1935 // typically drives the scavenge rate. Large heaps can mean infrequent GC,
a61af66fc99e Initial load
duke
parents:
diff changeset
1936 // which in turn can mean large(r) numbers of objectmonitors in circulation.
a61af66fc99e Initial load
duke
parents:
diff changeset
1937 // This is an unfortunate aspect of this design.
a61af66fc99e Initial load
duke
parents:
diff changeset
1938 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1939 // Another refinement would be to refrain from calling deflate_idle_monitors()
a61af66fc99e Initial load
duke
parents:
diff changeset
1940 // except at stop-the-world points associated with garbage collections.
a61af66fc99e Initial load
duke
parents:
diff changeset
1941 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1942 // An even better solution would be to deflate on-the-fly, aggressively,
a61af66fc99e Initial load
duke
parents:
diff changeset
1943 // at monitorexit-time as is done in EVM's metalock or Relaxed Locks.
a61af66fc99e Initial load
duke
parents:
diff changeset
1944
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1945
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1946 // Deflate a single monitor if not in use
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1947 // Return true if deflated, false if in use
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1948 bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj,
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1949 ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1950 bool deflated;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1951 // Normal case ... The monitor is associated with obj.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1952 guarantee (obj->mark() == markOopDesc::encode(mid), "invariant") ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1953 guarantee (mid == obj->mark()->monitor(), "invariant");
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1954 guarantee (mid->header()->is_neutral(), "invariant");
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1955
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1956 if (mid->is_busy()) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1957 if (ClearResponsibleAtSTW) mid->_Responsible = NULL ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1958 deflated = false;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1959 } else {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1960 // Deflate the monitor if it is no longer being used
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1961 // It's idle - scavenge and return to the global free list
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1962 // plain old deflation ...
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1963 TEVENT (deflate_idle_monitors - scavenge1) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1964 if (TraceMonitorInflation) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1965 if (obj->is_instance()) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1966 ResourceMark rm;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1967 tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1968 (intptr_t) obj, (intptr_t) obj->mark(), Klass::cast(obj->klass())->external_name());
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1969 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1970 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1971
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1972 // Restore the header back to obj
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1973 obj->release_set_mark(mid->header());
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1974 mid->clear();
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1975
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1976 assert (mid->object() == NULL, "invariant") ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1977
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1978 // Move the object to the working free list defined by FreeHead,FreeTail.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1979 if (*FreeHeadp == NULL) *FreeHeadp = mid;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1980 if (*FreeTailp != NULL) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1981 ObjectMonitor * prevtail = *FreeTailp;
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1982 assert(prevtail->FreeNext == NULL, "cleaned up deflated?"); // TODO KK
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1983 prevtail->FreeNext = mid;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1984 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1985 *FreeTailp = mid;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1986 deflated = true;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1987 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1988 return deflated;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1989 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
1990
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1991 // Caller acquires ListLock
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1992 int ObjectSynchronizer::walk_monitor_list(ObjectMonitor** listheadp,
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1993 ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1994 ObjectMonitor* mid;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1995 ObjectMonitor* next;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1996 ObjectMonitor* curmidinuse = NULL;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1997 int deflatedcount = 0;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1998
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
1999 for (mid = *listheadp; mid != NULL; ) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2000 oop obj = (oop) mid->object();
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2001 bool deflated = false;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2002 if (obj != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2003 deflated = deflate_monitor(mid, obj, FreeHeadp, FreeTailp);
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2004 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2005 if (deflated) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2006 // extract from per-thread in-use-list
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2007 if (mid == *listheadp) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2008 *listheadp = mid->FreeNext;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2009 } else if (curmidinuse != NULL) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2010 curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2011 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2012 next = mid->FreeNext;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2013 mid->FreeNext = NULL; // This mid is current tail in the FreeHead list
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2014 mid = next;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2015 deflatedcount++;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2016 } else {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2017 curmidinuse = mid;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2018 mid = mid->FreeNext;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2019 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2020 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2021 return deflatedcount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2022 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2023
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2024 void ObjectSynchronizer::deflate_idle_monitors() {
a61af66fc99e Initial load
duke
parents:
diff changeset
2025 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
a61af66fc99e Initial load
duke
parents:
diff changeset
2026 int nInuse = 0 ; // currently associated with objects
a61af66fc99e Initial load
duke
parents:
diff changeset
2027 int nInCirculation = 0 ; // extant
a61af66fc99e Initial load
duke
parents:
diff changeset
2028 int nScavenged = 0 ; // reclaimed
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2029 bool deflated = false;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2030
a61af66fc99e Initial load
duke
parents:
diff changeset
2031 ObjectMonitor * FreeHead = NULL ; // Local SLL of scavenged monitors
a61af66fc99e Initial load
duke
parents:
diff changeset
2032 ObjectMonitor * FreeTail = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2033
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2034 TEVENT (deflate_idle_monitors) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2035 // Prevent omFlush from changing mids in Thread dtor's during deflation
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2036 // And in case the vm thread is acquiring a lock during a safepoint
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2037 // See e.g. 6320749
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2038 Thread::muxAcquire (&ListLock, "scavenge - return") ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2039
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2040 if (MonitorInUseLists) {
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2041 int inUse = 0;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2042 for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) {
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2043 nInCirculation+= cur->omInUseCount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2044 int deflatedcount = walk_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail);
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2045 cur->omInUseCount-= deflatedcount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2046 // verifyInUse(cur);
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2047 nScavenged += deflatedcount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2048 nInuse += cur->omInUseCount;
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2049 }
1640
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2050
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2051 // For moribund threads, scan gOmInUseList
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2052 if (gOmInUseList) {
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2053 nInCirculation += gOmInUseCount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2054 int deflatedcount = walk_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail);
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2055 gOmInUseCount-= deflatedcount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2056 nScavenged += deflatedcount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2057 nInuse += gOmInUseCount;
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2058 }
bfc89697cccb 6964164: MonitorInUseLists leak of contended objects
acorn
parents: 1589
diff changeset
2059
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2060 } else for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) {
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2061 // Iterate over all extant monitors - Scavenge all idle monitors.
a61af66fc99e Initial load
duke
parents:
diff changeset
2062 assert(block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
2063 nInCirculation += _BLOCKSIZE ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2064 for (int i = 1 ; i < _BLOCKSIZE; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2065 ObjectMonitor* mid = &block[i];
a61af66fc99e Initial load
duke
parents:
diff changeset
2066 oop obj = (oop) mid->object();
a61af66fc99e Initial load
duke
parents:
diff changeset
2067
a61af66fc99e Initial load
duke
parents:
diff changeset
2068 if (obj == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2069 // The monitor is not associated with an object.
a61af66fc99e Initial load
duke
parents:
diff changeset
2070 // The monitor should either be a thread-specific private
a61af66fc99e Initial load
duke
parents:
diff changeset
2071 // free list or the global free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
2072 // obj == NULL IMPLIES mid->is_busy() == 0
a61af66fc99e Initial load
duke
parents:
diff changeset
2073 guarantee (!mid->is_busy(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2074 continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2075 }
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2076 deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail);
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2077
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2078 if (deflated) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2079 mid->FreeNext = NULL ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2080 nScavenged ++ ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2081 } else {
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2082 nInuse ++;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2083 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2084 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2085 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2086
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2087 MonitorFreeCount += nScavenged;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2088
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2089 // Consider: audit gFreeList to ensure that MonitorFreeCount and list agree.
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2090
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2091 if (Knob_Verbose) {
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2092 ::printf ("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n",
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2093 nInCirculation, nInuse, nScavenged, ForceMonitorScavenge,
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2094 MonitorPopulation, MonitorFreeCount) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2095 ::fflush(stdout) ;
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2096 }
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2097
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2098 ForceMonitorScavenge = 0; // Reset
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2099
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2100 // Move the scavenged monitors back to the global free list.
a61af66fc99e Initial load
duke
parents:
diff changeset
2101 if (FreeHead != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2102 guarantee (FreeTail != NULL && nScavenged > 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2103 assert (FreeTail->FreeNext == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2104 // constant-time list splice - prepend scavenged segment to gFreeList
a61af66fc99e Initial load
duke
parents:
diff changeset
2105 FreeTail->FreeNext = gFreeList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2106 gFreeList = FreeHead ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2107 }
1587
b96a3e44582f 6852873: Reduce safepoint cleanup time
acorn
parents: 702
diff changeset
2108 Thread::muxRelease (&ListLock) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
2109
a61af66fc99e Initial load
duke
parents:
diff changeset
2110 if (_sync_Deflations != NULL) _sync_Deflations->inc(nScavenged) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2111 if (_sync_MonExtant != NULL) _sync_MonExtant ->set_value(nInCirculation);
a61af66fc99e Initial load
duke
parents:
diff changeset
2112
a61af66fc99e Initial load
duke
parents:
diff changeset
2113 // TODO: Add objectMonitor leak detection.
a61af66fc99e Initial load
duke
parents:
diff changeset
2114 // Audit/inventory the objectMonitors -- make sure they're all accounted for.
a61af66fc99e Initial load
duke
parents:
diff changeset
2115 GVars.stwRandom = os::random() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2116 GVars.stwCycle ++ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2117 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2118
a61af66fc99e Initial load
duke
parents:
diff changeset
2119 // A macro is used below because there may already be a pending
a61af66fc99e Initial load
duke
parents:
diff changeset
2120 // exception which should not abort the execution of the routines
a61af66fc99e Initial load
duke
parents:
diff changeset
2121 // which use this (which is why we don't put this into check_slow and
a61af66fc99e Initial load
duke
parents:
diff changeset
2122 // call it with a CHECK argument).
a61af66fc99e Initial load
duke
parents:
diff changeset
2123
a61af66fc99e Initial load
duke
parents:
diff changeset
2124 #define CHECK_OWNER() \
a61af66fc99e Initial load
duke
parents:
diff changeset
2125 do { \
a61af66fc99e Initial load
duke
parents:
diff changeset
2126 if (THREAD != _owner) { \
a61af66fc99e Initial load
duke
parents:
diff changeset
2127 if (THREAD->is_lock_owned((address) _owner)) { \
a61af66fc99e Initial load
duke
parents:
diff changeset
2128 _owner = THREAD ; /* Convert from basiclock addr to Thread addr */ \
a61af66fc99e Initial load
duke
parents:
diff changeset
2129 _recursions = 0; \
a61af66fc99e Initial load
duke
parents:
diff changeset
2130 OwnerIsThread = 1 ; \
a61af66fc99e Initial load
duke
parents:
diff changeset
2131 } else { \
a61af66fc99e Initial load
duke
parents:
diff changeset
2132 TEVENT (Throw IMSX) ; \
a61af66fc99e Initial load
duke
parents:
diff changeset
2133 THROW(vmSymbols::java_lang_IllegalMonitorStateException()); \
a61af66fc99e Initial load
duke
parents:
diff changeset
2134 } \
a61af66fc99e Initial load
duke
parents:
diff changeset
2135 } \
a61af66fc99e Initial load
duke
parents:
diff changeset
2136 } while (false)
a61af66fc99e Initial load
duke
parents:
diff changeset
2137
a61af66fc99e Initial load
duke
parents:
diff changeset
2138 // TODO-FIXME: eliminate ObjectWaiters. Replace this visitor/enumerator
a61af66fc99e Initial load
duke
parents:
diff changeset
2139 // interface with a simple FirstWaitingThread(), NextWaitingThread() interface.
a61af66fc99e Initial load
duke
parents:
diff changeset
2140
a61af66fc99e Initial load
duke
parents:
diff changeset
2141 ObjectWaiter* ObjectMonitor::first_waiter() {
a61af66fc99e Initial load
duke
parents:
diff changeset
2142 return _WaitSet;
a61af66fc99e Initial load
duke
parents:
diff changeset
2143 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2144
a61af66fc99e Initial load
duke
parents:
diff changeset
2145 ObjectWaiter* ObjectMonitor::next_waiter(ObjectWaiter* o) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2146 return o->_next;
a61af66fc99e Initial load
duke
parents:
diff changeset
2147 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2148
a61af66fc99e Initial load
duke
parents:
diff changeset
2149 Thread* ObjectMonitor::thread_of_waiter(ObjectWaiter* o) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2150 return o->_thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
2151 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2152
a61af66fc99e Initial load
duke
parents:
diff changeset
2153 // initialize the monitor, exception the semaphore, all other fields
a61af66fc99e Initial load
duke
parents:
diff changeset
2154 // are simple integers or pointers
a61af66fc99e Initial load
duke
parents:
diff changeset
2155 ObjectMonitor::ObjectMonitor() {
a61af66fc99e Initial load
duke
parents:
diff changeset
2156 _header = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2157 _count = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
2158 _waiters = 0,
a61af66fc99e Initial load
duke
parents:
diff changeset
2159 _recursions = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
2160 _object = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2161 _owner = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2162 _WaitSet = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2163 _WaitSetLock = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2164 _Responsible = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2165 _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2166 _cxq = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2167 FreeNext = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2168 _EntryList = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2169 _SpinFreq = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2170 _SpinClock = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2171 OwnerIsThread = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2172 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2173
a61af66fc99e Initial load
duke
parents:
diff changeset
2174 ObjectMonitor::~ObjectMonitor() {
a61af66fc99e Initial load
duke
parents:
diff changeset
2175 // TODO: Add asserts ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2176 // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
a61af66fc99e Initial load
duke
parents:
diff changeset
2177 // _count == 0 _EntryList == NULL etc
a61af66fc99e Initial load
duke
parents:
diff changeset
2178 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2179
a61af66fc99e Initial load
duke
parents:
diff changeset
2180 intptr_t ObjectMonitor::is_busy() const {
a61af66fc99e Initial load
duke
parents:
diff changeset
2181 // TODO-FIXME: merge _count and _waiters.
a61af66fc99e Initial load
duke
parents:
diff changeset
2182 // TODO-FIXME: assert _owner == null implies _recursions = 0
a61af66fc99e Initial load
duke
parents:
diff changeset
2183 // TODO-FIXME: assert _WaitSet != null implies _count > 0
a61af66fc99e Initial load
duke
parents:
diff changeset
2184 return _count|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList ) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2185 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2186
a61af66fc99e Initial load
duke
parents:
diff changeset
2187 void ObjectMonitor::Recycle () {
a61af66fc99e Initial load
duke
parents:
diff changeset
2188 // TODO: add stronger asserts ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2189 // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
a61af66fc99e Initial load
duke
parents:
diff changeset
2190 // _count == 0 EntryList == NULL
a61af66fc99e Initial load
duke
parents:
diff changeset
2191 // _recursions == 0 _WaitSet == NULL
a61af66fc99e Initial load
duke
parents:
diff changeset
2192 // TODO: assert (is_busy()|_recursions) == 0
a61af66fc99e Initial load
duke
parents:
diff changeset
2193 _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2194 _EntryList = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2195 _cxq = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2196 _WaitSet = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2197 _recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2198 _SpinFreq = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2199 _SpinClock = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2200 OwnerIsThread = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2201 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2202
a61af66fc99e Initial load
duke
parents:
diff changeset
2203 // WaitSet management ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2204
a61af66fc99e Initial load
duke
parents:
diff changeset
2205 inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2206 assert(node != NULL, "should not dequeue NULL node");
a61af66fc99e Initial load
duke
parents:
diff changeset
2207 assert(node->_prev == NULL, "node already in list");
a61af66fc99e Initial load
duke
parents:
diff changeset
2208 assert(node->_next == NULL, "node already in list");
a61af66fc99e Initial load
duke
parents:
diff changeset
2209 // put node at end of queue (circular doubly linked list)
a61af66fc99e Initial load
duke
parents:
diff changeset
2210 if (_WaitSet == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2211 _WaitSet = node;
a61af66fc99e Initial load
duke
parents:
diff changeset
2212 node->_prev = node;
a61af66fc99e Initial load
duke
parents:
diff changeset
2213 node->_next = node;
a61af66fc99e Initial load
duke
parents:
diff changeset
2214 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
2215 ObjectWaiter* head = _WaitSet ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2216 ObjectWaiter* tail = head->_prev;
a61af66fc99e Initial load
duke
parents:
diff changeset
2217 assert(tail->_next == head, "invariant check");
a61af66fc99e Initial load
duke
parents:
diff changeset
2218 tail->_next = node;
a61af66fc99e Initial load
duke
parents:
diff changeset
2219 head->_prev = node;
a61af66fc99e Initial load
duke
parents:
diff changeset
2220 node->_next = head;
a61af66fc99e Initial load
duke
parents:
diff changeset
2221 node->_prev = tail;
a61af66fc99e Initial load
duke
parents:
diff changeset
2222 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2223 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2224
a61af66fc99e Initial load
duke
parents:
diff changeset
2225 inline ObjectWaiter* ObjectMonitor::DequeueWaiter() {
a61af66fc99e Initial load
duke
parents:
diff changeset
2226 // dequeue the very first waiter
a61af66fc99e Initial load
duke
parents:
diff changeset
2227 ObjectWaiter* waiter = _WaitSet;
a61af66fc99e Initial load
duke
parents:
diff changeset
2228 if (waiter) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2229 DequeueSpecificWaiter(waiter);
a61af66fc99e Initial load
duke
parents:
diff changeset
2230 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2231 return waiter;
a61af66fc99e Initial load
duke
parents:
diff changeset
2232 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2233
a61af66fc99e Initial load
duke
parents:
diff changeset
2234 inline void ObjectMonitor::DequeueSpecificWaiter(ObjectWaiter* node) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2235 assert(node != NULL, "should not dequeue NULL node");
a61af66fc99e Initial load
duke
parents:
diff changeset
2236 assert(node->_prev != NULL, "node already removed from list");
a61af66fc99e Initial load
duke
parents:
diff changeset
2237 assert(node->_next != NULL, "node already removed from list");
a61af66fc99e Initial load
duke
parents:
diff changeset
2238 // when the waiter has woken up because of interrupt,
a61af66fc99e Initial load
duke
parents:
diff changeset
2239 // timeout or other spurious wake-up, dequeue the
a61af66fc99e Initial load
duke
parents:
diff changeset
2240 // waiter from waiting list
a61af66fc99e Initial load
duke
parents:
diff changeset
2241 ObjectWaiter* next = node->_next;
a61af66fc99e Initial load
duke
parents:
diff changeset
2242 if (next == node) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2243 assert(node->_prev == node, "invariant check");
a61af66fc99e Initial load
duke
parents:
diff changeset
2244 _WaitSet = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2245 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
2246 ObjectWaiter* prev = node->_prev;
a61af66fc99e Initial load
duke
parents:
diff changeset
2247 assert(prev->_next == node, "invariant check");
a61af66fc99e Initial load
duke
parents:
diff changeset
2248 assert(next->_prev == node, "invariant check");
a61af66fc99e Initial load
duke
parents:
diff changeset
2249 next->_prev = prev;
a61af66fc99e Initial load
duke
parents:
diff changeset
2250 prev->_next = next;
a61af66fc99e Initial load
duke
parents:
diff changeset
2251 if (_WaitSet == node) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2252 _WaitSet = next;
a61af66fc99e Initial load
duke
parents:
diff changeset
2253 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2254 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2255 node->_next = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2256 node->_prev = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
2257 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2258
a61af66fc99e Initial load
duke
parents:
diff changeset
2259 static char * kvGet (char * kvList, const char * Key) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2260 if (kvList == NULL) return NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2261 size_t n = strlen (Key) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2262 char * Search ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2263 for (Search = kvList ; *Search ; Search += strlen(Search) + 1) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2264 if (strncmp (Search, Key, n) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2265 if (Search[n] == '=') return Search + n + 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2266 if (Search[n] == 0) return (char *) "1" ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2267 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2268 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2269 return NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2270 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2271
a61af66fc99e Initial load
duke
parents:
diff changeset
2272 static int kvGetInt (char * kvList, const char * Key, int Default) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2273 char * v = kvGet (kvList, Key) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2274 int rslt = v ? ::strtol (v, NULL, 0) : Default ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2275 if (Knob_ReportSettings && v != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2276 ::printf (" SyncKnob: %s %d(%d)\n", Key, rslt, Default) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2277 ::fflush (stdout) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2278 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2279 return rslt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2280 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2281
a61af66fc99e Initial load
duke
parents:
diff changeset
2282 // By convention we unlink a contending thread from EntryList|cxq immediately
a61af66fc99e Initial load
duke
parents:
diff changeset
2283 // after the thread acquires the lock in ::enter(). Equally, we could defer
a61af66fc99e Initial load
duke
parents:
diff changeset
2284 // unlinking the thread until ::exit()-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
2285
a61af66fc99e Initial load
duke
parents:
diff changeset
2286 void ObjectMonitor::UnlinkAfterAcquire (Thread * Self, ObjectWaiter * SelfNode)
a61af66fc99e Initial load
duke
parents:
diff changeset
2287 {
a61af66fc99e Initial load
duke
parents:
diff changeset
2288 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2289 assert (SelfNode->_thread == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2290
a61af66fc99e Initial load
duke
parents:
diff changeset
2291 if (SelfNode->TState == ObjectWaiter::TS_ENTER) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2292 // Normal case: remove Self from the DLL EntryList .
a61af66fc99e Initial load
duke
parents:
diff changeset
2293 // This is a constant-time operation.
a61af66fc99e Initial load
duke
parents:
diff changeset
2294 ObjectWaiter * nxt = SelfNode->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2295 ObjectWaiter * prv = SelfNode->_prev ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2296 if (nxt != NULL) nxt->_prev = prv ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2297 if (prv != NULL) prv->_next = nxt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2298 if (SelfNode == _EntryList ) _EntryList = nxt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2299 assert (nxt == NULL || nxt->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2300 assert (prv == NULL || prv->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2301 TEVENT (Unlink from EntryList) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2302 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
2303 guarantee (SelfNode->TState == ObjectWaiter::TS_CXQ, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2304 // Inopportune interleaving -- Self is still on the cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
2305 // This usually means the enqueue of self raced an exiting thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
2306 // Normally we'll find Self near the front of the cxq, so
a61af66fc99e Initial load
duke
parents:
diff changeset
2307 // dequeueing is typically fast. If needbe we can accelerate
a61af66fc99e Initial load
duke
parents:
diff changeset
2308 // this with some MCS/CHL-like bidirectional list hints and advisory
a61af66fc99e Initial load
duke
parents:
diff changeset
2309 // back-links so dequeueing from the interior will normally operate
a61af66fc99e Initial load
duke
parents:
diff changeset
2310 // in constant-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
2311 // Dequeue Self from either the head (with CAS) or from the interior
a61af66fc99e Initial load
duke
parents:
diff changeset
2312 // with a linear-time scan and normal non-atomic memory operations.
a61af66fc99e Initial load
duke
parents:
diff changeset
2313 // CONSIDER: if Self is on the cxq then simply drain cxq into EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
2314 // and then unlink Self from EntryList. We have to drain eventually,
a61af66fc99e Initial load
duke
parents:
diff changeset
2315 // so it might as well be now.
a61af66fc99e Initial load
duke
parents:
diff changeset
2316
a61af66fc99e Initial load
duke
parents:
diff changeset
2317 ObjectWaiter * v = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2318 assert (v != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2319 if (v != SelfNode || Atomic::cmpxchg_ptr (SelfNode->_next, &_cxq, v) != v) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2320 // The CAS above can fail from interference IFF a "RAT" arrived.
a61af66fc99e Initial load
duke
parents:
diff changeset
2321 // In that case Self must be in the interior and can no longer be
a61af66fc99e Initial load
duke
parents:
diff changeset
2322 // at the head of cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
2323 if (v == SelfNode) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2324 assert (_cxq != v, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2325 v = _cxq ; // CAS above failed - start scan at head of list
a61af66fc99e Initial load
duke
parents:
diff changeset
2326 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2327 ObjectWaiter * p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2328 ObjectWaiter * q = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2329 for (p = v ; p != NULL && p != SelfNode; p = p->_next) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2330 q = p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2331 assert (p->TState == ObjectWaiter::TS_CXQ, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2332 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2333 assert (v != SelfNode, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2334 assert (p == SelfNode, "Node not found on cxq") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2335 assert (p != _cxq, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2336 assert (q != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2337 assert (q->_next == p, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2338 q->_next = p->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2339 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2340 TEVENT (Unlink from cxq) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2341 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2342
a61af66fc99e Initial load
duke
parents:
diff changeset
2343 // Diagnostic hygiene ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2344 SelfNode->_prev = (ObjectWaiter *) 0xBAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2345 SelfNode->_next = (ObjectWaiter *) 0xBAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2346 SelfNode->TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2347 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2348
a61af66fc99e Initial load
duke
parents:
diff changeset
2349 // Caveat: TryLock() is not necessarily serializing if it returns failure.
a61af66fc99e Initial load
duke
parents:
diff changeset
2350 // Callers must compensate as needed.
a61af66fc99e Initial load
duke
parents:
diff changeset
2351
a61af66fc99e Initial load
duke
parents:
diff changeset
2352 int ObjectMonitor::TryLock (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2353 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2354 void * own = _owner ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2355 if (own != NULL) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2356 if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2357 // Either guarantee _recursions == 0 or set _recursions = 0.
a61af66fc99e Initial load
duke
parents:
diff changeset
2358 assert (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2359 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2360 // CONSIDER: set or assert that OwnerIsThread == 1
a61af66fc99e Initial load
duke
parents:
diff changeset
2361 return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2362 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2363 // The lock had been free momentarily, but we lost the race to the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
2364 // Interference -- the CAS failed.
a61af66fc99e Initial load
duke
parents:
diff changeset
2365 // We can either return -1 or retry.
a61af66fc99e Initial load
duke
parents:
diff changeset
2366 // Retry doesn't make as much sense because the lock was just acquired.
a61af66fc99e Initial load
duke
parents:
diff changeset
2367 if (true) return -1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2368 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2369 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2370
a61af66fc99e Initial load
duke
parents:
diff changeset
2371 // NotRunnable() -- informed spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
2372 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2373 // Don't bother spinning if the owner is not eligible to drop the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
2374 // Peek at the owner's schedctl.sc_state and Thread._thread_values and
a61af66fc99e Initial load
duke
parents:
diff changeset
2375 // spin only if the owner thread is _thread_in_Java or _thread_in_vm.
a61af66fc99e Initial load
duke
parents:
diff changeset
2376 // The thread must be runnable in order to drop the lock in timely fashion.
a61af66fc99e Initial load
duke
parents:
diff changeset
2377 // If the _owner is not runnable then spinning will not likely be
a61af66fc99e Initial load
duke
parents:
diff changeset
2378 // successful (profitable).
a61af66fc99e Initial load
duke
parents:
diff changeset
2379 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2380 // Beware -- the thread referenced by _owner could have died
a61af66fc99e Initial load
duke
parents:
diff changeset
2381 // so a simply fetch from _owner->_thread_state might trap.
a61af66fc99e Initial load
duke
parents:
diff changeset
2382 // Instead, we use SafeFetchXX() to safely LD _owner->_thread_state.
a61af66fc99e Initial load
duke
parents:
diff changeset
2383 // Because of the lifecycle issues the schedctl and _thread_state values
a61af66fc99e Initial load
duke
parents:
diff changeset
2384 // observed by NotRunnable() might be garbage. NotRunnable must
a61af66fc99e Initial load
duke
parents:
diff changeset
2385 // tolerate this and consider the observed _thread_state value
a61af66fc99e Initial load
duke
parents:
diff changeset
2386 // as advisory.
a61af66fc99e Initial load
duke
parents:
diff changeset
2387 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2388 // Beware too, that _owner is sometimes a BasicLock address and sometimes
a61af66fc99e Initial load
duke
parents:
diff changeset
2389 // a thread pointer. We differentiate the two cases with OwnerIsThread.
a61af66fc99e Initial load
duke
parents:
diff changeset
2390 // Alternately, we might tag the type (thread pointer vs basiclock pointer)
a61af66fc99e Initial load
duke
parents:
diff changeset
2391 // with the LSB of _owner. Another option would be to probablistically probe
a61af66fc99e Initial load
duke
parents:
diff changeset
2392 // the putative _owner->TypeTag value.
a61af66fc99e Initial load
duke
parents:
diff changeset
2393 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2394 // Checking _thread_state isn't perfect. Even if the thread is
a61af66fc99e Initial load
duke
parents:
diff changeset
2395 // in_java it might be blocked on a page-fault or have been preempted
a61af66fc99e Initial load
duke
parents:
diff changeset
2396 // and sitting on a ready/dispatch queue. _thread state in conjunction
a61af66fc99e Initial load
duke
parents:
diff changeset
2397 // with schedctl.sc_state gives us a good picture of what the
a61af66fc99e Initial load
duke
parents:
diff changeset
2398 // thread is doing, however.
a61af66fc99e Initial load
duke
parents:
diff changeset
2399 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2400 // TODO: check schedctl.sc_state.
a61af66fc99e Initial load
duke
parents:
diff changeset
2401 // We'll need to use SafeFetch32() to read from the schedctl block.
a61af66fc99e Initial load
duke
parents:
diff changeset
2402 // See RFE #5004247 and http://sac.sfbay.sun.com/Archives/CaseLog/arc/PSARC/2005/351/
a61af66fc99e Initial load
duke
parents:
diff changeset
2403 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2404 // The return value from NotRunnable() is *advisory* -- the
a61af66fc99e Initial load
duke
parents:
diff changeset
2405 // result is based on sampling and is not necessarily coherent.
a61af66fc99e Initial load
duke
parents:
diff changeset
2406 // The caller must tolerate false-negative and false-positive errors.
a61af66fc99e Initial load
duke
parents:
diff changeset
2407 // Spinning, in general, is probabilistic anyway.
a61af66fc99e Initial load
duke
parents:
diff changeset
2408
a61af66fc99e Initial load
duke
parents:
diff changeset
2409
a61af66fc99e Initial load
duke
parents:
diff changeset
2410 int ObjectMonitor::NotRunnable (Thread * Self, Thread * ox) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2411 // Check either OwnerIsThread or ox->TypeTag == 2BAD.
a61af66fc99e Initial load
duke
parents:
diff changeset
2412 if (!OwnerIsThread) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2413
a61af66fc99e Initial load
duke
parents:
diff changeset
2414 if (ox == NULL) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2415
a61af66fc99e Initial load
duke
parents:
diff changeset
2416 // Avoid transitive spinning ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2417 // Say T1 spins or blocks trying to acquire L. T1._Stalled is set to L.
a61af66fc99e Initial load
duke
parents:
diff changeset
2418 // Immediately after T1 acquires L it's possible that T2, also
a61af66fc99e Initial load
duke
parents:
diff changeset
2419 // spinning on L, will see L.Owner=T1 and T1._Stalled=L.
a61af66fc99e Initial load
duke
parents:
diff changeset
2420 // This occurs transiently after T1 acquired L but before
a61af66fc99e Initial load
duke
parents:
diff changeset
2421 // T1 managed to clear T1.Stalled. T2 does not need to abort
a61af66fc99e Initial load
duke
parents:
diff changeset
2422 // its spin in this circumstance.
a61af66fc99e Initial load
duke
parents:
diff changeset
2423 intptr_t BlockedOn = SafeFetchN ((intptr_t *) &ox->_Stalled, intptr_t(1)) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2424
a61af66fc99e Initial load
duke
parents:
diff changeset
2425 if (BlockedOn == 1) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2426 if (BlockedOn != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2427 return BlockedOn != intptr_t(this) && _owner == ox ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2428 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2429
a61af66fc99e Initial load
duke
parents:
diff changeset
2430 assert (sizeof(((JavaThread *)ox)->_thread_state == sizeof(int)), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2431 int jst = SafeFetch32 ((int *) &((JavaThread *) ox)->_thread_state, -1) ; ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2432 // consider also: jst != _thread_in_Java -- but that's overspecific.
a61af66fc99e Initial load
duke
parents:
diff changeset
2433 return jst == _thread_blocked || jst == _thread_in_native ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2434 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2435
a61af66fc99e Initial load
duke
parents:
diff changeset
2436
a61af66fc99e Initial load
duke
parents:
diff changeset
2437 // Adaptive spin-then-block - rational spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
2438 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2439 // Note that we spin "globally" on _owner with a classic SMP-polite TATAS
a61af66fc99e Initial load
duke
parents:
diff changeset
2440 // algorithm. On high order SMP systems it would be better to start with
a61af66fc99e Initial load
duke
parents:
diff changeset
2441 // a brief global spin and then revert to spinning locally. In the spirit of MCS/CLH,
a61af66fc99e Initial load
duke
parents:
diff changeset
2442 // a contending thread could enqueue itself on the cxq and then spin locally
a61af66fc99e Initial load
duke
parents:
diff changeset
2443 // on a thread-specific variable such as its ParkEvent._Event flag.
a61af66fc99e Initial load
duke
parents:
diff changeset
2444 // That's left as an exercise for the reader. Note that global spinning is
a61af66fc99e Initial load
duke
parents:
diff changeset
2445 // not problematic on Niagara, as the L2$ serves the interconnect and has both
a61af66fc99e Initial load
duke
parents:
diff changeset
2446 // low latency and massive bandwidth.
a61af66fc99e Initial load
duke
parents:
diff changeset
2447 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2448 // Broadly, we can fix the spin frequency -- that is, the % of contended lock
a61af66fc99e Initial load
duke
parents:
diff changeset
2449 // acquisition attempts where we opt to spin -- at 100% and vary the spin count
a61af66fc99e Initial load
duke
parents:
diff changeset
2450 // (duration) or we can fix the count at approximately the duration of
a61af66fc99e Initial load
duke
parents:
diff changeset
2451 // a context switch and vary the frequency. Of course we could also
a61af66fc99e Initial load
duke
parents:
diff changeset
2452 // vary both satisfying K == Frequency * Duration, where K is adaptive by monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
2453 // See http://j2se.east/~dice/PERSIST/040824-AdaptiveSpinning.html.
a61af66fc99e Initial load
duke
parents:
diff changeset
2454 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2455 // This implementation varies the duration "D", where D varies with
a61af66fc99e Initial load
duke
parents:
diff changeset
2456 // the success rate of recent spin attempts. (D is capped at approximately
a61af66fc99e Initial load
duke
parents:
diff changeset
2457 // length of a round-trip context switch). The success rate for recent
a61af66fc99e Initial load
duke
parents:
diff changeset
2458 // spin attempts is a good predictor of the success rate of future spin
a61af66fc99e Initial load
duke
parents:
diff changeset
2459 // attempts. The mechanism adapts automatically to varying critical
a61af66fc99e Initial load
duke
parents:
diff changeset
2460 // section length (lock modality), system load and degree of parallelism.
a61af66fc99e Initial load
duke
parents:
diff changeset
2461 // D is maintained per-monitor in _SpinDuration and is initialized
a61af66fc99e Initial load
duke
parents:
diff changeset
2462 // optimistically. Spin frequency is fixed at 100%.
a61af66fc99e Initial load
duke
parents:
diff changeset
2463 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2464 // Note that _SpinDuration is volatile, but we update it without locks
a61af66fc99e Initial load
duke
parents:
diff changeset
2465 // or atomics. The code is designed so that _SpinDuration stays within
a61af66fc99e Initial load
duke
parents:
diff changeset
2466 // a reasonable range even in the presence of races. The arithmetic
a61af66fc99e Initial load
duke
parents:
diff changeset
2467 // operations on _SpinDuration are closed over the domain of legal values,
a61af66fc99e Initial load
duke
parents:
diff changeset
2468 // so at worst a race will install and older but still legal value.
a61af66fc99e Initial load
duke
parents:
diff changeset
2469 // At the very worst this introduces some apparent non-determinism.
a61af66fc99e Initial load
duke
parents:
diff changeset
2470 // We might spin when we shouldn't or vice-versa, but since the spin
a61af66fc99e Initial load
duke
parents:
diff changeset
2471 // count are relatively short, even in the worst case, the effect is harmless.
a61af66fc99e Initial load
duke
parents:
diff changeset
2472 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2473 // Care must be taken that a low "D" value does not become an
a61af66fc99e Initial load
duke
parents:
diff changeset
2474 // an absorbing state. Transient spinning failures -- when spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
2475 // is overall profitable -- should not cause the system to converge
a61af66fc99e Initial load
duke
parents:
diff changeset
2476 // on low "D" values. We want spinning to be stable and predictable
a61af66fc99e Initial load
duke
parents:
diff changeset
2477 // and fairly responsive to change and at the same time we don't want
a61af66fc99e Initial load
duke
parents:
diff changeset
2478 // it to oscillate, become metastable, be "too" non-deterministic,
a61af66fc99e Initial load
duke
parents:
diff changeset
2479 // or converge on or enter undesirable stable absorbing states.
a61af66fc99e Initial load
duke
parents:
diff changeset
2480 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2481 // We implement a feedback-based control system -- using past behavior
a61af66fc99e Initial load
duke
parents:
diff changeset
2482 // to predict future behavior. We face two issues: (a) if the
a61af66fc99e Initial load
duke
parents:
diff changeset
2483 // input signal is random then the spin predictor won't provide optimal
a61af66fc99e Initial load
duke
parents:
diff changeset
2484 // results, and (b) if the signal frequency is too high then the control
a61af66fc99e Initial load
duke
parents:
diff changeset
2485 // system, which has some natural response lag, will "chase" the signal.
a61af66fc99e Initial load
duke
parents:
diff changeset
2486 // (b) can arise from multimodal lock hold times. Transient preemption
a61af66fc99e Initial load
duke
parents:
diff changeset
2487 // can also result in apparent bimodal lock hold times.
a61af66fc99e Initial load
duke
parents:
diff changeset
2488 // Although sub-optimal, neither condition is particularly harmful, as
a61af66fc99e Initial load
duke
parents:
diff changeset
2489 // in the worst-case we'll spin when we shouldn't or vice-versa.
a61af66fc99e Initial load
duke
parents:
diff changeset
2490 // The maximum spin duration is rather short so the failure modes aren't bad.
a61af66fc99e Initial load
duke
parents:
diff changeset
2491 // To be conservative, I've tuned the gain in system to bias toward
a61af66fc99e Initial load
duke
parents:
diff changeset
2492 // _not spinning. Relatedly, the system can sometimes enter a mode where it
a61af66fc99e Initial load
duke
parents:
diff changeset
2493 // "rings" or oscillates between spinning and not spinning. This happens
a61af66fc99e Initial load
duke
parents:
diff changeset
2494 // when spinning is just on the cusp of profitability, however, so the
a61af66fc99e Initial load
duke
parents:
diff changeset
2495 // situation is not dire. The state is benign -- there's no need to add
a61af66fc99e Initial load
duke
parents:
diff changeset
2496 // hysteresis control to damp the transition rate between spinning and
a61af66fc99e Initial load
duke
parents:
diff changeset
2497 // not spinning.
a61af66fc99e Initial load
duke
parents:
diff changeset
2498 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2499 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
a61af66fc99e Initial load
duke
parents:
diff changeset
2500 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2501 // Spin-then-block strategies ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2502 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2503 // Thoughts on ways to improve spinning :
a61af66fc99e Initial load
duke
parents:
diff changeset
2504 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2505 // * Periodically call {psr_}getloadavg() while spinning, and
a61af66fc99e Initial load
duke
parents:
diff changeset
2506 // permit unbounded spinning if the load average is <
a61af66fc99e Initial load
duke
parents:
diff changeset
2507 // the number of processors. Beware, however, that getloadavg()
a61af66fc99e Initial load
duke
parents:
diff changeset
2508 // is exceptionally fast on solaris (about 1/10 the cost of a full
a61af66fc99e Initial load
duke
parents:
diff changeset
2509 // spin cycle, but quite expensive on linux. Beware also, that
a61af66fc99e Initial load
duke
parents:
diff changeset
2510 // multiple JVMs could "ring" or oscillate in a feedback loop.
a61af66fc99e Initial load
duke
parents:
diff changeset
2511 // Sufficient damping would solve that problem.
a61af66fc99e Initial load
duke
parents:
diff changeset
2512 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2513 // * We currently use spin loops with iteration counters to approximate
a61af66fc99e Initial load
duke
parents:
diff changeset
2514 // spinning for some interval. Given the availability of high-precision
a61af66fc99e Initial load
duke
parents:
diff changeset
2515 // time sources such as gethrtime(), %TICK, %STICK, RDTSC, etc., we should
a61af66fc99e Initial load
duke
parents:
diff changeset
2516 // someday reimplement the spin loops to duration-based instead of iteration-based.
a61af66fc99e Initial load
duke
parents:
diff changeset
2517 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2518 // * Don't spin if there are more than N = (CPUs/2) threads
a61af66fc99e Initial load
duke
parents:
diff changeset
2519 // currently spinning on the monitor (or globally).
a61af66fc99e Initial load
duke
parents:
diff changeset
2520 // That is, limit the number of concurrent spinners.
a61af66fc99e Initial load
duke
parents:
diff changeset
2521 // We might also limit the # of spinners in the JVM, globally.
a61af66fc99e Initial load
duke
parents:
diff changeset
2522 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2523 // * If a spinning thread observes _owner change hands it should
a61af66fc99e Initial load
duke
parents:
diff changeset
2524 // abort the spin (and park immediately) or at least debit
a61af66fc99e Initial load
duke
parents:
diff changeset
2525 // the spin counter by a large "penalty".
a61af66fc99e Initial load
duke
parents:
diff changeset
2526 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2527 // * Classically, the spin count is either K*(CPUs-1) or is a
a61af66fc99e Initial load
duke
parents:
diff changeset
2528 // simple constant that approximates the length of a context switch.
a61af66fc99e Initial load
duke
parents:
diff changeset
2529 // We currently use a value -- computed by a special utility -- that
a61af66fc99e Initial load
duke
parents:
diff changeset
2530 // approximates round-trip context switch times.
a61af66fc99e Initial load
duke
parents:
diff changeset
2531 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2532 // * Normally schedctl_start()/_stop() is used to advise the kernel
a61af66fc99e Initial load
duke
parents:
diff changeset
2533 // to avoid preempting threads that are running in short, bounded
a61af66fc99e Initial load
duke
parents:
diff changeset
2534 // critical sections. We could use the schedctl hooks in an inverted
a61af66fc99e Initial load
duke
parents:
diff changeset
2535 // sense -- spinners would set the nopreempt flag, but poll the preempt
a61af66fc99e Initial load
duke
parents:
diff changeset
2536 // pending flag. If a spinner observed a pending preemption it'd immediately
a61af66fc99e Initial load
duke
parents:
diff changeset
2537 // abort the spin and park. As such, the schedctl service acts as
a61af66fc99e Initial load
duke
parents:
diff changeset
2538 // a preemption warning mechanism.
a61af66fc99e Initial load
duke
parents:
diff changeset
2539 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2540 // * In lieu of spinning, if the system is running below saturation
a61af66fc99e Initial load
duke
parents:
diff changeset
2541 // (that is, loadavg() << #cpus), we can instead suppress futile
a61af66fc99e Initial load
duke
parents:
diff changeset
2542 // wakeup throttling, or even wake more than one successor at exit-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
2543 // The net effect is largely equivalent to spinning. In both cases,
a61af66fc99e Initial load
duke
parents:
diff changeset
2544 // contending threads go ONPROC and opportunistically attempt to acquire
a61af66fc99e Initial load
duke
parents:
diff changeset
2545 // the lock, decreasing lock handover latency at the expense of wasted
a61af66fc99e Initial load
duke
parents:
diff changeset
2546 // cycles and context switching.
a61af66fc99e Initial load
duke
parents:
diff changeset
2547 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2548 // * We might to spin less after we've parked as the thread will
a61af66fc99e Initial load
duke
parents:
diff changeset
2549 // have less $ and TLB affinity with the processor.
a61af66fc99e Initial load
duke
parents:
diff changeset
2550 // Likewise, we might spin less if we come ONPROC on a different
a61af66fc99e Initial load
duke
parents:
diff changeset
2551 // processor or after a long period (>> rechose_interval).
a61af66fc99e Initial load
duke
parents:
diff changeset
2552 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2553 // * A table-driven state machine similar to Solaris' dispadmin scheduling
a61af66fc99e Initial load
duke
parents:
diff changeset
2554 // tables might be a better design. Instead of encoding information in
a61af66fc99e Initial load
duke
parents:
diff changeset
2555 // _SpinDuration, _SpinFreq and _SpinClock we'd just use explicit,
a61af66fc99e Initial load
duke
parents:
diff changeset
2556 // discrete states. Success or failure during a spin would drive
a61af66fc99e Initial load
duke
parents:
diff changeset
2557 // state transitions, and each state node would contain a spin count.
a61af66fc99e Initial load
duke
parents:
diff changeset
2558 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2559 // * If the processor is operating in a mode intended to conserve power
a61af66fc99e Initial load
duke
parents:
diff changeset
2560 // (such as Intel's SpeedStep) or to reduce thermal output (thermal
a61af66fc99e Initial load
duke
parents:
diff changeset
2561 // step-down mode) then the Java synchronization subsystem should
a61af66fc99e Initial load
duke
parents:
diff changeset
2562 // forgo spinning.
a61af66fc99e Initial load
duke
parents:
diff changeset
2563 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2564 // * The minimum spin duration should be approximately the worst-case
a61af66fc99e Initial load
duke
parents:
diff changeset
2565 // store propagation latency on the platform. That is, the time
a61af66fc99e Initial load
duke
parents:
diff changeset
2566 // it takes a store on CPU A to become visible on CPU B, where A and
a61af66fc99e Initial load
duke
parents:
diff changeset
2567 // B are "distant".
a61af66fc99e Initial load
duke
parents:
diff changeset
2568 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2569 // * We might want to factor a thread's priority in the spin policy.
a61af66fc99e Initial load
duke
parents:
diff changeset
2570 // Threads with a higher priority might spin for slightly longer.
a61af66fc99e Initial load
duke
parents:
diff changeset
2571 // Similarly, if we use back-off in the TATAS loop, lower priority
a61af66fc99e Initial load
duke
parents:
diff changeset
2572 // threads might back-off longer. We don't currently use a
a61af66fc99e Initial load
duke
parents:
diff changeset
2573 // thread's priority when placing it on the entry queue. We may
a61af66fc99e Initial load
duke
parents:
diff changeset
2574 // want to consider doing so in future releases.
a61af66fc99e Initial load
duke
parents:
diff changeset
2575 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2576 // * We might transiently drop a thread's scheduling priority while it spins.
a61af66fc99e Initial load
duke
parents:
diff changeset
2577 // SCHED_BATCH on linux and FX scheduling class at priority=0 on Solaris
a61af66fc99e Initial load
duke
parents:
diff changeset
2578 // would suffice. We could even consider letting the thread spin indefinitely at
a61af66fc99e Initial load
duke
parents:
diff changeset
2579 // a depressed or "idle" priority. This brings up fairness issues, however --
a61af66fc99e Initial load
duke
parents:
diff changeset
2580 // in a saturated system a thread would with a reduced priority could languish
a61af66fc99e Initial load
duke
parents:
diff changeset
2581 // for extended periods on the ready queue.
a61af66fc99e Initial load
duke
parents:
diff changeset
2582 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2583 // * While spinning try to use the otherwise wasted time to help the VM make
a61af66fc99e Initial load
duke
parents:
diff changeset
2584 // progress:
a61af66fc99e Initial load
duke
parents:
diff changeset
2585 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2586 // -- YieldTo() the owner, if the owner is OFFPROC but ready
a61af66fc99e Initial load
duke
parents:
diff changeset
2587 // Done our remaining quantum directly to the ready thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
2588 // This helps "push" the lock owner through the critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
2589 // It also tends to improve affinity/locality as the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
2590 // "migrates" less frequently between CPUs.
a61af66fc99e Initial load
duke
parents:
diff changeset
2591 // -- Walk our own stack in anticipation of blocking. Memoize the roots.
a61af66fc99e Initial load
duke
parents:
diff changeset
2592 // -- Perform strand checking for other thread. Unpark potential strandees.
a61af66fc99e Initial load
duke
parents:
diff changeset
2593 // -- Help GC: trace or mark -- this would need to be a bounded unit of work.
a61af66fc99e Initial load
duke
parents:
diff changeset
2594 // Unfortunately this will pollute our $ and TLBs. Recall that we
a61af66fc99e Initial load
duke
parents:
diff changeset
2595 // spin to avoid context switching -- context switching has an
a61af66fc99e Initial load
duke
parents:
diff changeset
2596 // immediate cost in latency, a disruptive cost to other strands on a CMT
a61af66fc99e Initial load
duke
parents:
diff changeset
2597 // processor, and an amortized cost because of the D$ and TLB cache
a61af66fc99e Initial load
duke
parents:
diff changeset
2598 // reload transient when the thread comes back ONPROC and repopulates
a61af66fc99e Initial load
duke
parents:
diff changeset
2599 // $s and TLBs.
a61af66fc99e Initial load
duke
parents:
diff changeset
2600 // -- call getloadavg() to see if the system is saturated. It'd probably
a61af66fc99e Initial load
duke
parents:
diff changeset
2601 // make sense to call getloadavg() half way through the spin.
a61af66fc99e Initial load
duke
parents:
diff changeset
2602 // If the system isn't at full capacity the we'd simply reset
a61af66fc99e Initial load
duke
parents:
diff changeset
2603 // the spin counter to and extend the spin attempt.
a61af66fc99e Initial load
duke
parents:
diff changeset
2604 // -- Doug points out that we should use the same "helping" policy
a61af66fc99e Initial load
duke
parents:
diff changeset
2605 // in thread.yield().
a61af66fc99e Initial load
duke
parents:
diff changeset
2606 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2607 // * Try MONITOR-MWAIT on systems that support those instructions.
a61af66fc99e Initial load
duke
parents:
diff changeset
2608 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2609 // * The spin statistics that drive spin decisions & frequency are
a61af66fc99e Initial load
duke
parents:
diff changeset
2610 // maintained in the objectmonitor structure so if we deflate and reinflate
a61af66fc99e Initial load
duke
parents:
diff changeset
2611 // we lose spin state. In practice this is not usually a concern
a61af66fc99e Initial load
duke
parents:
diff changeset
2612 // as the default spin state after inflation is aggressive (optimistic)
a61af66fc99e Initial load
duke
parents:
diff changeset
2613 // and tends toward spinning. So in the worst case for a lock where
a61af66fc99e Initial load
duke
parents:
diff changeset
2614 // spinning is not profitable we may spin unnecessarily for a brief
a61af66fc99e Initial load
duke
parents:
diff changeset
2615 // period. But then again, if a lock is contended it'll tend not to deflate
a61af66fc99e Initial load
duke
parents:
diff changeset
2616 // in the first place.
a61af66fc99e Initial load
duke
parents:
diff changeset
2617
a61af66fc99e Initial load
duke
parents:
diff changeset
2618
a61af66fc99e Initial load
duke
parents:
diff changeset
2619 intptr_t ObjectMonitor::SpinCallbackArgument = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2620 int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2621
a61af66fc99e Initial load
duke
parents:
diff changeset
2622 // Spinning: Fixed frequency (100%), vary duration
a61af66fc99e Initial load
duke
parents:
diff changeset
2623
a61af66fc99e Initial load
duke
parents:
diff changeset
2624 int ObjectMonitor::TrySpin_VaryDuration (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2625
a61af66fc99e Initial load
duke
parents:
diff changeset
2626 // Dumb, brutal spin. Good for comparative measurements against adaptive spinning.
a61af66fc99e Initial load
duke
parents:
diff changeset
2627 int ctr = Knob_FixedSpin ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2628 if (ctr != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2629 while (--ctr >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2630 if (TryLock (Self) > 0) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2631 SpinPause () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2632 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2633 return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2634 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2635
a61af66fc99e Initial load
duke
parents:
diff changeset
2636 for (ctr = Knob_PreSpin + 1; --ctr >= 0 ; ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2637 if (TryLock(Self) > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2638 // Increase _SpinDuration ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2639 // Note that we don't clamp SpinDuration precisely at SpinLimit.
a61af66fc99e Initial load
duke
parents:
diff changeset
2640 // Raising _SpurDuration to the poverty line is key.
a61af66fc99e Initial load
duke
parents:
diff changeset
2641 int x = _SpinDuration ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2642 if (x < Knob_SpinLimit) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2643 if (x < Knob_Poverty) x = Knob_Poverty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2644 _SpinDuration = x + Knob_BonusB ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2645 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2646 return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2647 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2648 SpinPause () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2649 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2650
a61af66fc99e Initial load
duke
parents:
diff changeset
2651 // Admission control - verify preconditions for spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
2652 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2653 // We always spin a little bit, just to prevent _SpinDuration == 0 from
a61af66fc99e Initial load
duke
parents:
diff changeset
2654 // becoming an absorbing state. Put another way, we spin briefly to
a61af66fc99e Initial load
duke
parents:
diff changeset
2655 // sample, just in case the system load, parallelism, contention, or lock
a61af66fc99e Initial load
duke
parents:
diff changeset
2656 // modality changed.
a61af66fc99e Initial load
duke
parents:
diff changeset
2657 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2658 // Consider the following alternative:
a61af66fc99e Initial load
duke
parents:
diff changeset
2659 // Periodically set _SpinDuration = _SpinLimit and try a long/full
a61af66fc99e Initial load
duke
parents:
diff changeset
2660 // spin attempt. "Periodically" might mean after a tally of
a61af66fc99e Initial load
duke
parents:
diff changeset
2661 // the # of failed spin attempts (or iterations) reaches some threshold.
a61af66fc99e Initial load
duke
parents:
diff changeset
2662 // This takes us into the realm of 1-out-of-N spinning, where we
a61af66fc99e Initial load
duke
parents:
diff changeset
2663 // hold the duration constant but vary the frequency.
a61af66fc99e Initial load
duke
parents:
diff changeset
2664
a61af66fc99e Initial load
duke
parents:
diff changeset
2665 ctr = _SpinDuration ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2666 if (ctr < Knob_SpinBase) ctr = Knob_SpinBase ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2667 if (ctr <= 0) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2668
a61af66fc99e Initial load
duke
parents:
diff changeset
2669 if (Knob_SuccRestrict && _succ != NULL) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2670 if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2671 TEVENT (Spin abort - notrunnable [TOP]);
a61af66fc99e Initial load
duke
parents:
diff changeset
2672 return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2673 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2674
a61af66fc99e Initial load
duke
parents:
diff changeset
2675 int MaxSpin = Knob_MaxSpinners ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2676 if (MaxSpin >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2677 if (_Spinner > MaxSpin) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2678 TEVENT (Spin abort -- too many spinners) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2679 return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2680 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2681 // Slighty racy, but benign ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2682 Adjust (&_Spinner, 1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2683 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2684
a61af66fc99e Initial load
duke
parents:
diff changeset
2685 // We're good to spin ... spin ingress.
a61af66fc99e Initial load
duke
parents:
diff changeset
2686 // CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
a61af66fc99e Initial load
duke
parents:
diff changeset
2687 // when preparing to LD...CAS _owner, etc and the CAS is likely
a61af66fc99e Initial load
duke
parents:
diff changeset
2688 // to succeed.
a61af66fc99e Initial load
duke
parents:
diff changeset
2689 int hits = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2690 int msk = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2691 int caspty = Knob_CASPenalty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2692 int oxpty = Knob_OXPenalty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2693 int sss = Knob_SpinSetSucc ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2694 if (sss && _succ == NULL ) _succ = Self ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2695 Thread * prv = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2696
a61af66fc99e Initial load
duke
parents:
diff changeset
2697 // There are three ways to exit the following loop:
a61af66fc99e Initial load
duke
parents:
diff changeset
2698 // 1. A successful spin where this thread has acquired the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
2699 // 2. Spin failure with prejudice
a61af66fc99e Initial load
duke
parents:
diff changeset
2700 // 3. Spin failure without prejudice
a61af66fc99e Initial load
duke
parents:
diff changeset
2701
a61af66fc99e Initial load
duke
parents:
diff changeset
2702 while (--ctr >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2703
a61af66fc99e Initial load
duke
parents:
diff changeset
2704 // Periodic polling -- Check for pending GC
a61af66fc99e Initial load
duke
parents:
diff changeset
2705 // Threads may spin while they're unsafe.
a61af66fc99e Initial load
duke
parents:
diff changeset
2706 // We don't want spinning threads to delay the JVM from reaching
a61af66fc99e Initial load
duke
parents:
diff changeset
2707 // a stop-the-world safepoint or to steal cycles from GC.
a61af66fc99e Initial load
duke
parents:
diff changeset
2708 // If we detect a pending safepoint we abort in order that
a61af66fc99e Initial load
duke
parents:
diff changeset
2709 // (a) this thread, if unsafe, doesn't delay the safepoint, and (b)
a61af66fc99e Initial load
duke
parents:
diff changeset
2710 // this thread, if safe, doesn't steal cycles from GC.
a61af66fc99e Initial load
duke
parents:
diff changeset
2711 // This is in keeping with the "no loitering in runtime" rule.
a61af66fc99e Initial load
duke
parents:
diff changeset
2712 // We periodically check to see if there's a safepoint pending.
a61af66fc99e Initial load
duke
parents:
diff changeset
2713 if ((ctr & 0xFF) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2714 if (SafepointSynchronize::do_call_back()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2715 TEVENT (Spin: safepoint) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2716 goto Abort ; // abrupt spin egress
a61af66fc99e Initial load
duke
parents:
diff changeset
2717 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2718 if (Knob_UsePause & 1) SpinPause () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2719
a61af66fc99e Initial load
duke
parents:
diff changeset
2720 int (*scb)(intptr_t,int) = SpinCallbackFunction ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2721 if (hits > 50 && scb != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2722 int abend = (*scb)(SpinCallbackArgument, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2723 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2724 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2725
a61af66fc99e Initial load
duke
parents:
diff changeset
2726 if (Knob_UsePause & 2) SpinPause() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2727
a61af66fc99e Initial load
duke
parents:
diff changeset
2728 // Exponential back-off ... Stay off the bus to reduce coherency traffic.
a61af66fc99e Initial load
duke
parents:
diff changeset
2729 // This is useful on classic SMP systems, but is of less utility on
a61af66fc99e Initial load
duke
parents:
diff changeset
2730 // N1-style CMT platforms.
a61af66fc99e Initial load
duke
parents:
diff changeset
2731 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2732 // Trade-off: lock acquisition latency vs coherency bandwidth.
a61af66fc99e Initial load
duke
parents:
diff changeset
2733 // Lock hold times are typically short. A histogram
a61af66fc99e Initial load
duke
parents:
diff changeset
2734 // of successful spin attempts shows that we usually acquire
a61af66fc99e Initial load
duke
parents:
diff changeset
2735 // the lock early in the spin. That suggests we want to
a61af66fc99e Initial load
duke
parents:
diff changeset
2736 // sample _owner frequently in the early phase of the spin,
a61af66fc99e Initial load
duke
parents:
diff changeset
2737 // but then back-off and sample less frequently as the spin
a61af66fc99e Initial load
duke
parents:
diff changeset
2738 // progresses. The back-off makes a good citizen on SMP big
a61af66fc99e Initial load
duke
parents:
diff changeset
2739 // SMP systems. Oversampling _owner can consume excessive
a61af66fc99e Initial load
duke
parents:
diff changeset
2740 // coherency bandwidth. Relatedly, if we _oversample _owner we
a61af66fc99e Initial load
duke
parents:
diff changeset
2741 // can inadvertently interfere with the the ST m->owner=null.
a61af66fc99e Initial load
duke
parents:
diff changeset
2742 // executed by the lock owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
2743 if (ctr & msk) continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2744 ++hits ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2745 if ((hits & 0xF) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2746 // The 0xF, above, corresponds to the exponent.
a61af66fc99e Initial load
duke
parents:
diff changeset
2747 // Consider: (msk+1)|msk
a61af66fc99e Initial load
duke
parents:
diff changeset
2748 msk = ((msk << 2)|3) & BackOffMask ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2749 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2750
a61af66fc99e Initial load
duke
parents:
diff changeset
2751 // Probe _owner with TATAS
a61af66fc99e Initial load
duke
parents:
diff changeset
2752 // If this thread observes the monitor transition or flicker
a61af66fc99e Initial load
duke
parents:
diff changeset
2753 // from locked to unlocked to locked, then the odds that this
a61af66fc99e Initial load
duke
parents:
diff changeset
2754 // thread will acquire the lock in this spin attempt go down
a61af66fc99e Initial load
duke
parents:
diff changeset
2755 // considerably. The same argument applies if the CAS fails
a61af66fc99e Initial load
duke
parents:
diff changeset
2756 // or if we observe _owner change from one non-null value to
a61af66fc99e Initial load
duke
parents:
diff changeset
2757 // another non-null value. In such cases we might abort
a61af66fc99e Initial load
duke
parents:
diff changeset
2758 // the spin without prejudice or apply a "penalty" to the
a61af66fc99e Initial load
duke
parents:
diff changeset
2759 // spin count-down variable "ctr", reducing it by 100, say.
a61af66fc99e Initial load
duke
parents:
diff changeset
2760
a61af66fc99e Initial load
duke
parents:
diff changeset
2761 Thread * ox = (Thread *) _owner ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2762 if (ox == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2763 ox = (Thread *) Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2764 if (ox == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2765 // The CAS succeeded -- this thread acquired ownership
a61af66fc99e Initial load
duke
parents:
diff changeset
2766 // Take care of some bookkeeping to exit spin state.
a61af66fc99e Initial load
duke
parents:
diff changeset
2767 if (sss && _succ == Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2768 _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2769 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2770 if (MaxSpin > 0) Adjust (&_Spinner, -1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2771
a61af66fc99e Initial load
duke
parents:
diff changeset
2772 // Increase _SpinDuration :
a61af66fc99e Initial load
duke
parents:
diff changeset
2773 // The spin was successful (profitable) so we tend toward
a61af66fc99e Initial load
duke
parents:
diff changeset
2774 // longer spin attempts in the future.
a61af66fc99e Initial load
duke
parents:
diff changeset
2775 // CONSIDER: factor "ctr" into the _SpinDuration adjustment.
a61af66fc99e Initial load
duke
parents:
diff changeset
2776 // If we acquired the lock early in the spin cycle it
a61af66fc99e Initial load
duke
parents:
diff changeset
2777 // makes sense to increase _SpinDuration proportionally.
a61af66fc99e Initial load
duke
parents:
diff changeset
2778 // Note that we don't clamp SpinDuration precisely at SpinLimit.
a61af66fc99e Initial load
duke
parents:
diff changeset
2779 int x = _SpinDuration ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2780 if (x < Knob_SpinLimit) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2781 if (x < Knob_Poverty) x = Knob_Poverty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2782 _SpinDuration = x + Knob_Bonus ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2783 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2784 return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2785 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2786
a61af66fc99e Initial load
duke
parents:
diff changeset
2787 // The CAS failed ... we can take any of the following actions:
a61af66fc99e Initial load
duke
parents:
diff changeset
2788 // * penalize: ctr -= Knob_CASPenalty
a61af66fc99e Initial load
duke
parents:
diff changeset
2789 // * exit spin with prejudice -- goto Abort;
a61af66fc99e Initial load
duke
parents:
diff changeset
2790 // * exit spin without prejudice.
a61af66fc99e Initial load
duke
parents:
diff changeset
2791 // * Since CAS is high-latency, retry again immediately.
a61af66fc99e Initial load
duke
parents:
diff changeset
2792 prv = ox ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2793 TEVENT (Spin: cas failed) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2794 if (caspty == -2) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2795 if (caspty == -1) goto Abort ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2796 ctr -= caspty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2797 continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2798 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2799
a61af66fc99e Initial load
duke
parents:
diff changeset
2800 // Did lock ownership change hands ?
a61af66fc99e Initial load
duke
parents:
diff changeset
2801 if (ox != prv && prv != NULL ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2802 TEVENT (spin: Owner changed)
a61af66fc99e Initial load
duke
parents:
diff changeset
2803 if (oxpty == -2) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2804 if (oxpty == -1) goto Abort ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2805 ctr -= oxpty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2806 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2807 prv = ox ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2808
a61af66fc99e Initial load
duke
parents:
diff changeset
2809 // Abort the spin if the owner is not executing.
a61af66fc99e Initial load
duke
parents:
diff changeset
2810 // The owner must be executing in order to drop the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
2811 // Spinning while the owner is OFFPROC is idiocy.
a61af66fc99e Initial load
duke
parents:
diff changeset
2812 // Consider: ctr -= RunnablePenalty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2813 if (Knob_OState && NotRunnable (Self, ox)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2814 TEVENT (Spin abort - notrunnable);
a61af66fc99e Initial load
duke
parents:
diff changeset
2815 goto Abort ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2816 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2817 if (sss && _succ == NULL ) _succ = Self ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2818 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2819
a61af66fc99e Initial load
duke
parents:
diff changeset
2820 // Spin failed with prejudice -- reduce _SpinDuration.
a61af66fc99e Initial load
duke
parents:
diff changeset
2821 // TODO: Use an AIMD-like policy to adjust _SpinDuration.
a61af66fc99e Initial load
duke
parents:
diff changeset
2822 // AIMD is globally stable.
a61af66fc99e Initial load
duke
parents:
diff changeset
2823 TEVENT (Spin failure) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2824 {
a61af66fc99e Initial load
duke
parents:
diff changeset
2825 int x = _SpinDuration ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2826 if (x > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2827 // Consider an AIMD scheme like: x -= (x >> 3) + 100
a61af66fc99e Initial load
duke
parents:
diff changeset
2828 // This is globally sample and tends to damp the response.
a61af66fc99e Initial load
duke
parents:
diff changeset
2829 x -= Knob_Penalty ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2830 if (x < 0) x = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2831 _SpinDuration = x ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2832 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2833 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2834
a61af66fc99e Initial load
duke
parents:
diff changeset
2835 Abort:
a61af66fc99e Initial load
duke
parents:
diff changeset
2836 if (MaxSpin >= 0) Adjust (&_Spinner, -1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2837 if (sss && _succ == Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2838 _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2839 // Invariant: after setting succ=null a contending thread
a61af66fc99e Initial load
duke
parents:
diff changeset
2840 // must recheck-retry _owner before parking. This usually happens
a61af66fc99e Initial load
duke
parents:
diff changeset
2841 // in the normal usage of TrySpin(), but it's safest
a61af66fc99e Initial load
duke
parents:
diff changeset
2842 // to make TrySpin() as foolproof as possible.
a61af66fc99e Initial load
duke
parents:
diff changeset
2843 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2844 if (TryLock(Self) > 0) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2845 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2846 return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2847 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2848
a61af66fc99e Initial load
duke
parents:
diff changeset
2849 #define TrySpin TrySpin_VaryDuration
a61af66fc99e Initial load
duke
parents:
diff changeset
2850
a61af66fc99e Initial load
duke
parents:
diff changeset
2851 static void DeferredInitialize () {
a61af66fc99e Initial load
duke
parents:
diff changeset
2852 if (InitDone > 0) return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2853 if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2854 while (InitDone != 1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2855 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2856 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2857
a61af66fc99e Initial load
duke
parents:
diff changeset
2858 // One-shot global initialization ...
a61af66fc99e Initial load
duke
parents:
diff changeset
2859 // The initialization is idempotent, so we don't need locks.
a61af66fc99e Initial load
duke
parents:
diff changeset
2860 // In the future consider doing this via os::init_2().
a61af66fc99e Initial load
duke
parents:
diff changeset
2861 // SyncKnobs consist of <Key>=<Value> pairs in the style
a61af66fc99e Initial load
duke
parents:
diff changeset
2862 // of environment variables. Start by converting ':' to NUL.
a61af66fc99e Initial load
duke
parents:
diff changeset
2863
a61af66fc99e Initial load
duke
parents:
diff changeset
2864 if (SyncKnobs == NULL) SyncKnobs = "" ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2865
a61af66fc99e Initial load
duke
parents:
diff changeset
2866 size_t sz = strlen (SyncKnobs) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2867 char * knobs = (char *) malloc (sz + 2) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2868 if (knobs == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2869 vm_exit_out_of_memory (sz + 2, "Parse SyncKnobs") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2870 guarantee (0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2871 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2872 strcpy (knobs, SyncKnobs) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2873 knobs[sz+1] = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2874 for (char * p = knobs ; *p ; p++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2875 if (*p == ':') *p = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2876 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2877
a61af66fc99e Initial load
duke
parents:
diff changeset
2878 #define SETKNOB(x) { Knob_##x = kvGetInt (knobs, #x, Knob_##x); }
a61af66fc99e Initial load
duke
parents:
diff changeset
2879 SETKNOB(ReportSettings) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2880 SETKNOB(Verbose) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2881 SETKNOB(FixedSpin) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2882 SETKNOB(SpinLimit) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2883 SETKNOB(SpinBase) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2884 SETKNOB(SpinBackOff);
a61af66fc99e Initial load
duke
parents:
diff changeset
2885 SETKNOB(CASPenalty) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2886 SETKNOB(OXPenalty) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2887 SETKNOB(LogSpins) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2888 SETKNOB(SpinSetSucc) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2889 SETKNOB(SuccEnabled) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2890 SETKNOB(SuccRestrict) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2891 SETKNOB(Penalty) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2892 SETKNOB(Bonus) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2893 SETKNOB(BonusB) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2894 SETKNOB(Poverty) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2895 SETKNOB(SpinAfterFutile) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2896 SETKNOB(UsePause) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2897 SETKNOB(SpinEarly) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2898 SETKNOB(OState) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2899 SETKNOB(MaxSpinners) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2900 SETKNOB(PreSpin) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2901 SETKNOB(ExitPolicy) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2902 SETKNOB(QMode);
a61af66fc99e Initial load
duke
parents:
diff changeset
2903 SETKNOB(ResetEvent) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2904 SETKNOB(MoveNotifyee) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2905 SETKNOB(FastHSSEC) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2906 #undef SETKNOB
a61af66fc99e Initial load
duke
parents:
diff changeset
2907
a61af66fc99e Initial load
duke
parents:
diff changeset
2908 if (os::is_MP()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2909 BackOffMask = (1 << Knob_SpinBackOff) - 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2910 if (Knob_ReportSettings) ::printf ("BackOffMask=%X\n", BackOffMask) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2911 // CONSIDER: BackOffMask = ROUNDUP_NEXT_POWER2 (ncpus-1)
a61af66fc99e Initial load
duke
parents:
diff changeset
2912 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
2913 Knob_SpinLimit = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2914 Knob_SpinBase = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2915 Knob_PreSpin = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2916 Knob_FixedSpin = -1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2917 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2918
a61af66fc99e Initial load
duke
parents:
diff changeset
2919 if (Knob_LogSpins == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
2920 ObjectSynchronizer::_sync_FailedSpins = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2921 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2922
a61af66fc99e Initial load
duke
parents:
diff changeset
2923 free (knobs) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2924 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2925 InitDone = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
2926 }
a61af66fc99e Initial load
duke
parents:
diff changeset
2927
a61af66fc99e Initial load
duke
parents:
diff changeset
2928 // Theory of operations -- Monitors lists, thread residency, etc:
a61af66fc99e Initial load
duke
parents:
diff changeset
2929 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2930 // * A thread acquires ownership of a monitor by successfully
a61af66fc99e Initial load
duke
parents:
diff changeset
2931 // CAS()ing the _owner field from null to non-null.
a61af66fc99e Initial load
duke
parents:
diff changeset
2932 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2933 // * Invariant: A thread appears on at most one monitor list --
a61af66fc99e Initial load
duke
parents:
diff changeset
2934 // cxq, EntryList or WaitSet -- at any one time.
a61af66fc99e Initial load
duke
parents:
diff changeset
2935 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2936 // * Contending threads "push" themselves onto the cxq with CAS
a61af66fc99e Initial load
duke
parents:
diff changeset
2937 // and then spin/park.
a61af66fc99e Initial load
duke
parents:
diff changeset
2938 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2939 // * After a contending thread eventually acquires the lock it must
a61af66fc99e Initial load
duke
parents:
diff changeset
2940 // dequeue itself from either the EntryList or the cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
2941 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2942 // * The exiting thread identifies and unparks an "heir presumptive"
a61af66fc99e Initial load
duke
parents:
diff changeset
2943 // tentative successor thread on the EntryList. Critically, the
a61af66fc99e Initial load
duke
parents:
diff changeset
2944 // exiting thread doesn't unlink the successor thread from the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
2945 // After having been unparked, the wakee will recontend for ownership of
a61af66fc99e Initial load
duke
parents:
diff changeset
2946 // the monitor. The successor (wakee) will either acquire the lock or
a61af66fc99e Initial load
duke
parents:
diff changeset
2947 // re-park itself.
a61af66fc99e Initial load
duke
parents:
diff changeset
2948 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2949 // Succession is provided for by a policy of competitive handoff.
a61af66fc99e Initial load
duke
parents:
diff changeset
2950 // The exiting thread does _not_ grant or pass ownership to the
a61af66fc99e Initial load
duke
parents:
diff changeset
2951 // successor thread. (This is also referred to as "handoff" succession").
a61af66fc99e Initial load
duke
parents:
diff changeset
2952 // Instead the exiting thread releases ownership and possibly wakes
a61af66fc99e Initial load
duke
parents:
diff changeset
2953 // a successor, so the successor can (re)compete for ownership of the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
2954 // If the EntryList is empty but the cxq is populated the exiting
a61af66fc99e Initial load
duke
parents:
diff changeset
2955 // thread will drain the cxq into the EntryList. It does so by
a61af66fc99e Initial load
duke
parents:
diff changeset
2956 // by detaching the cxq (installing null with CAS) and folding
a61af66fc99e Initial load
duke
parents:
diff changeset
2957 // the threads from the cxq into the EntryList. The EntryList is
a61af66fc99e Initial load
duke
parents:
diff changeset
2958 // doubly linked, while the cxq is singly linked because of the
a61af66fc99e Initial load
duke
parents:
diff changeset
2959 // CAS-based "push" used to enqueue recently arrived threads (RATs).
a61af66fc99e Initial load
duke
parents:
diff changeset
2960 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2961 // * Concurrency invariants:
a61af66fc99e Initial load
duke
parents:
diff changeset
2962 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2963 // -- only the monitor owner may access or mutate the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
2964 // The mutex property of the monitor itself protects the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
2965 // from concurrent interference.
a61af66fc99e Initial load
duke
parents:
diff changeset
2966 // -- Only the monitor owner may detach the cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
2967 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2968 // * The monitor entry list operations avoid locks, but strictly speaking
a61af66fc99e Initial load
duke
parents:
diff changeset
2969 // they're not lock-free. Enter is lock-free, exit is not.
a61af66fc99e Initial load
duke
parents:
diff changeset
2970 // See http://j2se.east/~dice/PERSIST/040825-LockFreeQueues.html
a61af66fc99e Initial load
duke
parents:
diff changeset
2971 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2972 // * The cxq can have multiple concurrent "pushers" but only one concurrent
a61af66fc99e Initial load
duke
parents:
diff changeset
2973 // detaching thread. This mechanism is immune from the ABA corruption.
a61af66fc99e Initial load
duke
parents:
diff changeset
2974 // More precisely, the CAS-based "push" onto cxq is ABA-oblivious.
a61af66fc99e Initial load
duke
parents:
diff changeset
2975 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2976 // * Taken together, the cxq and the EntryList constitute or form a
a61af66fc99e Initial load
duke
parents:
diff changeset
2977 // single logical queue of threads stalled trying to acquire the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
2978 // We use two distinct lists to improve the odds of a constant-time
a61af66fc99e Initial load
duke
parents:
diff changeset
2979 // dequeue operation after acquisition (in the ::enter() epilog) and
a61af66fc99e Initial load
duke
parents:
diff changeset
2980 // to reduce heat on the list ends. (c.f. Michael Scott's "2Q" algorithm).
a61af66fc99e Initial load
duke
parents:
diff changeset
2981 // A key desideratum is to minimize queue & monitor metadata manipulation
a61af66fc99e Initial load
duke
parents:
diff changeset
2982 // that occurs while holding the monitor lock -- that is, we want to
a61af66fc99e Initial load
duke
parents:
diff changeset
2983 // minimize monitor lock holds times. Note that even a small amount of
a61af66fc99e Initial load
duke
parents:
diff changeset
2984 // fixed spinning will greatly reduce the # of enqueue-dequeue operations
a61af66fc99e Initial load
duke
parents:
diff changeset
2985 // on EntryList|cxq. That is, spinning relieves contention on the "inner"
a61af66fc99e Initial load
duke
parents:
diff changeset
2986 // locks and monitor metadata.
a61af66fc99e Initial load
duke
parents:
diff changeset
2987 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2988 // Cxq points to the the set of Recently Arrived Threads attempting entry.
a61af66fc99e Initial load
duke
parents:
diff changeset
2989 // Because we push threads onto _cxq with CAS, the RATs must take the form of
a61af66fc99e Initial load
duke
parents:
diff changeset
2990 // a singly-linked LIFO. We drain _cxq into EntryList at unlock-time when
a61af66fc99e Initial load
duke
parents:
diff changeset
2991 // the unlocking thread notices that EntryList is null but _cxq is != null.
a61af66fc99e Initial load
duke
parents:
diff changeset
2992 //
a61af66fc99e Initial load
duke
parents:
diff changeset
2993 // The EntryList is ordered by the prevailing queue discipline and
a61af66fc99e Initial load
duke
parents:
diff changeset
2994 // can be organized in any convenient fashion, such as a doubly-linked list or
a61af66fc99e Initial load
duke
parents:
diff changeset
2995 // a circular doubly-linked list. Critically, we want insert and delete operations
a61af66fc99e Initial load
duke
parents:
diff changeset
2996 // to operate in constant-time. If we need a priority queue then something akin
a61af66fc99e Initial load
duke
parents:
diff changeset
2997 // to Solaris' sleepq would work nicely. Viz.,
a61af66fc99e Initial load
duke
parents:
diff changeset
2998 // http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c.
a61af66fc99e Initial load
duke
parents:
diff changeset
2999 // Queue discipline is enforced at ::exit() time, when the unlocking thread
a61af66fc99e Initial load
duke
parents:
diff changeset
3000 // drains the cxq into the EntryList, and orders or reorders the threads on the
a61af66fc99e Initial load
duke
parents:
diff changeset
3001 // EntryList accordingly.
a61af66fc99e Initial load
duke
parents:
diff changeset
3002 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3003 // Barring "lock barging", this mechanism provides fair cyclic ordering,
a61af66fc99e Initial load
duke
parents:
diff changeset
3004 // somewhat similar to an elevator-scan.
a61af66fc99e Initial load
duke
parents:
diff changeset
3005 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3006 // * The monitor synchronization subsystem avoids the use of native
a61af66fc99e Initial load
duke
parents:
diff changeset
3007 // synchronization primitives except for the narrow platform-specific
a61af66fc99e Initial load
duke
parents:
diff changeset
3008 // park-unpark abstraction. See the comments in os_solaris.cpp regarding
a61af66fc99e Initial load
duke
parents:
diff changeset
3009 // the semantics of park-unpark. Put another way, this monitor implementation
a61af66fc99e Initial load
duke
parents:
diff changeset
3010 // depends only on atomic operations and park-unpark. The monitor subsystem
a61af66fc99e Initial load
duke
parents:
diff changeset
3011 // manages all RUNNING->BLOCKED and BLOCKED->READY transitions while the
a61af66fc99e Initial load
duke
parents:
diff changeset
3012 // underlying OS manages the READY<->RUN transitions.
a61af66fc99e Initial load
duke
parents:
diff changeset
3013 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3014 // * Waiting threads reside on the WaitSet list -- wait() puts
a61af66fc99e Initial load
duke
parents:
diff changeset
3015 // the caller onto the WaitSet.
a61af66fc99e Initial load
duke
parents:
diff changeset
3016 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3017 // * notify() or notifyAll() simply transfers threads from the WaitSet to
a61af66fc99e Initial load
duke
parents:
diff changeset
3018 // either the EntryList or cxq. Subsequent exit() operations will
a61af66fc99e Initial load
duke
parents:
diff changeset
3019 // unpark the notifyee. Unparking a notifee in notify() is inefficient -
a61af66fc99e Initial load
duke
parents:
diff changeset
3020 // it's likely the notifyee would simply impale itself on the lock held
a61af66fc99e Initial load
duke
parents:
diff changeset
3021 // by the notifier.
a61af66fc99e Initial load
duke
parents:
diff changeset
3022 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3023 // * An interesting alternative is to encode cxq as (List,LockByte) where
a61af66fc99e Initial load
duke
parents:
diff changeset
3024 // the LockByte is 0 iff the monitor is owned. _owner is simply an auxiliary
a61af66fc99e Initial load
duke
parents:
diff changeset
3025 // variable, like _recursions, in the scheme. The threads or Events that form
a61af66fc99e Initial load
duke
parents:
diff changeset
3026 // the list would have to be aligned in 256-byte addresses. A thread would
a61af66fc99e Initial load
duke
parents:
diff changeset
3027 // try to acquire the lock or enqueue itself with CAS, but exiting threads
a61af66fc99e Initial load
duke
parents:
diff changeset
3028 // could use a 1-0 protocol and simply STB to set the LockByte to 0.
a61af66fc99e Initial load
duke
parents:
diff changeset
3029 // Note that is is *not* word-tearing, but it does presume that full-word
a61af66fc99e Initial load
duke
parents:
diff changeset
3030 // CAS operations are coherent with intermix with STB operations. That's true
a61af66fc99e Initial load
duke
parents:
diff changeset
3031 // on most common processors.
a61af66fc99e Initial load
duke
parents:
diff changeset
3032 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3033 // * See also http://blogs.sun.com/dave
a61af66fc99e Initial load
duke
parents:
diff changeset
3034
a61af66fc99e Initial load
duke
parents:
diff changeset
3035
a61af66fc99e Initial load
duke
parents:
diff changeset
3036 void ATTR ObjectMonitor::EnterI (TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3037 Thread * Self = THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3038 assert (Self->is_Java_thread(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3039 assert (((JavaThread *) Self)->thread_state() == _thread_blocked , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3040
a61af66fc99e Initial load
duke
parents:
diff changeset
3041 // Try the lock - TATAS
a61af66fc99e Initial load
duke
parents:
diff changeset
3042 if (TryLock (Self) > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3043 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3044 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3045 assert (_Responsible != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3046 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3047 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3048
a61af66fc99e Initial load
duke
parents:
diff changeset
3049 DeferredInitialize () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3050
a61af66fc99e Initial load
duke
parents:
diff changeset
3051 // We try one round of spinning *before* enqueueing Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
3052 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3053 // If the _owner is ready but OFFPROC we could use a YieldTo()
a61af66fc99e Initial load
duke
parents:
diff changeset
3054 // operation to donate the remainder of this thread's quantum
a61af66fc99e Initial load
duke
parents:
diff changeset
3055 // to the owner. This has subtle but beneficial affinity
a61af66fc99e Initial load
duke
parents:
diff changeset
3056 // effects.
a61af66fc99e Initial load
duke
parents:
diff changeset
3057
a61af66fc99e Initial load
duke
parents:
diff changeset
3058 if (TrySpin (Self) > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3059 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3060 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3061 assert (_Responsible != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3062 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3063 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3064
a61af66fc99e Initial load
duke
parents:
diff changeset
3065 // The Spin failed -- Enqueue and park the thread ...
a61af66fc99e Initial load
duke
parents:
diff changeset
3066 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3067 assert (_owner != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3068 assert (_Responsible != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3069
a61af66fc99e Initial load
duke
parents:
diff changeset
3070 // Enqueue "Self" on ObjectMonitor's _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3071 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3072 // Node acts as a proxy for Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
3073 // As an aside, if were to ever rewrite the synchronization code mostly
a61af66fc99e Initial load
duke
parents:
diff changeset
3074 // in Java, WaitNodes, ObjectMonitors, and Events would become 1st-class
a61af66fc99e Initial load
duke
parents:
diff changeset
3075 // Java objects. This would avoid awkward lifecycle and liveness issues,
a61af66fc99e Initial load
duke
parents:
diff changeset
3076 // as well as eliminate a subset of ABA issues.
a61af66fc99e Initial load
duke
parents:
diff changeset
3077 // TODO: eliminate ObjectWaiter and enqueue either Threads or Events.
a61af66fc99e Initial load
duke
parents:
diff changeset
3078 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3079
a61af66fc99e Initial load
duke
parents:
diff changeset
3080 ObjectWaiter node(Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3081 Self->_ParkEvent->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3082 node._prev = (ObjectWaiter *) 0xBAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3083 node.TState = ObjectWaiter::TS_CXQ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3084
a61af66fc99e Initial load
duke
parents:
diff changeset
3085 // Push "Self" onto the front of the _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3086 // Once on cxq/EntryList, Self stays on-queue until it acquires the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3087 // Note that spinning tends to reduce the rate at which threads
a61af66fc99e Initial load
duke
parents:
diff changeset
3088 // enqueue and dequeue on EntryList|cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3089 ObjectWaiter * nxt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3090 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3091 node._next = nxt = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3092 if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3093
a61af66fc99e Initial load
duke
parents:
diff changeset
3094 // Interference - the CAS failed because _cxq changed. Just retry.
a61af66fc99e Initial load
duke
parents:
diff changeset
3095 // As an optional optimization we retry the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3096 if (TryLock (Self) > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3097 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3098 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3099 assert (_Responsible != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3100 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3101 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3102 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3103
a61af66fc99e Initial load
duke
parents:
diff changeset
3104 // Check for cxq|EntryList edge transition to non-null. This indicates
a61af66fc99e Initial load
duke
parents:
diff changeset
3105 // the onset of contention. While contention persists exiting threads
a61af66fc99e Initial load
duke
parents:
diff changeset
3106 // will use a ST:MEMBAR:LD 1-1 exit protocol. When contention abates exit
a61af66fc99e Initial load
duke
parents:
diff changeset
3107 // operations revert to the faster 1-0 mode. This enter operation may interleave
a61af66fc99e Initial load
duke
parents:
diff changeset
3108 // (race) a concurrent 1-0 exit operation, resulting in stranding, so we
a61af66fc99e Initial load
duke
parents:
diff changeset
3109 // arrange for one of the contending thread to use a timed park() operations
a61af66fc99e Initial load
duke
parents:
diff changeset
3110 // to detect and recover from the race. (Stranding is form of progress failure
a61af66fc99e Initial load
duke
parents:
diff changeset
3111 // where the monitor is unlocked but all the contending threads remain parked).
a61af66fc99e Initial load
duke
parents:
diff changeset
3112 // That is, at least one of the contended threads will periodically poll _owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
3113 // One of the contending threads will become the designated "Responsible" thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
3114 // The Responsible thread uses a timed park instead of a normal indefinite park
a61af66fc99e Initial load
duke
parents:
diff changeset
3115 // operation -- it periodically wakes and checks for and recovers from potential
a61af66fc99e Initial load
duke
parents:
diff changeset
3116 // strandings admitted by 1-0 exit operations. We need at most one Responsible
a61af66fc99e Initial load
duke
parents:
diff changeset
3117 // thread per-monitor at any given moment. Only threads on cxq|EntryList may
a61af66fc99e Initial load
duke
parents:
diff changeset
3118 // be responsible for a monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3119 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3120 // Currently, one of the contended threads takes on the added role of "Responsible".
a61af66fc99e Initial load
duke
parents:
diff changeset
3121 // A viable alternative would be to use a dedicated "stranding checker" thread
a61af66fc99e Initial load
duke
parents:
diff changeset
3122 // that periodically iterated over all the threads (or active monitors) and unparked
a61af66fc99e Initial load
duke
parents:
diff changeset
3123 // successors where there was risk of stranding. This would help eliminate the
a61af66fc99e Initial load
duke
parents:
diff changeset
3124 // timer scalability issues we see on some platforms as we'd only have one thread
a61af66fc99e Initial load
duke
parents:
diff changeset
3125 // -- the checker -- parked on a timer.
a61af66fc99e Initial load
duke
parents:
diff changeset
3126
a61af66fc99e Initial load
duke
parents:
diff changeset
3127 if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3128 // Try to assume the role of responsible thread for the monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3129 // CONSIDER: ST vs CAS vs { if (Responsible==null) Responsible=Self }
a61af66fc99e Initial load
duke
parents:
diff changeset
3130 Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3131 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3132
a61af66fc99e Initial load
duke
parents:
diff changeset
3133 // The lock have been released while this thread was occupied queueing
a61af66fc99e Initial load
duke
parents:
diff changeset
3134 // itself onto _cxq. To close the race and avoid "stranding" and
a61af66fc99e Initial load
duke
parents:
diff changeset
3135 // progress-liveness failure we must resample-retry _owner before parking.
a61af66fc99e Initial load
duke
parents:
diff changeset
3136 // Note the Dekker/Lamport duality: ST cxq; MEMBAR; LD Owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
3137 // In this case the ST-MEMBAR is accomplished with CAS().
a61af66fc99e Initial load
duke
parents:
diff changeset
3138 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3139 // TODO: Defer all thread state transitions until park-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
3140 // Since state transitions are heavy and inefficient we'd like
a61af66fc99e Initial load
duke
parents:
diff changeset
3141 // to defer the state transitions until absolutely necessary,
a61af66fc99e Initial load
duke
parents:
diff changeset
3142 // and in doing so avoid some transitions ...
a61af66fc99e Initial load
duke
parents:
diff changeset
3143
a61af66fc99e Initial load
duke
parents:
diff changeset
3144 TEVENT (Inflated enter - Contention) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3145 int nWakeups = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3146 int RecheckInterval = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3147
a61af66fc99e Initial load
duke
parents:
diff changeset
3148 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3149
a61af66fc99e Initial load
duke
parents:
diff changeset
3150 if (TryLock (Self) > 0) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3151 assert (_owner != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3152
a61af66fc99e Initial load
duke
parents:
diff changeset
3153 if ((SyncFlags & 2) && _Responsible == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3154 Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3155 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3156
a61af66fc99e Initial load
duke
parents:
diff changeset
3157 // park self
a61af66fc99e Initial load
duke
parents:
diff changeset
3158 if (_Responsible == Self || (SyncFlags & 1)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3159 TEVENT (Inflated enter - park TIMED) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3160 Self->_ParkEvent->park ((jlong) RecheckInterval) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3161 // Increase the RecheckInterval, but clamp the value.
a61af66fc99e Initial load
duke
parents:
diff changeset
3162 RecheckInterval *= 8 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3163 if (RecheckInterval > 1000) RecheckInterval = 1000 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3164 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3165 TEVENT (Inflated enter - park UNTIMED) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3166 Self->_ParkEvent->park() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3167 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3168
a61af66fc99e Initial load
duke
parents:
diff changeset
3169 if (TryLock(Self) > 0) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3170
a61af66fc99e Initial load
duke
parents:
diff changeset
3171 // The lock is still contested.
a61af66fc99e Initial load
duke
parents:
diff changeset
3172 // Keep a tally of the # of futile wakeups.
a61af66fc99e Initial load
duke
parents:
diff changeset
3173 // Note that the counter is not protected by a lock or updated by atomics.
a61af66fc99e Initial load
duke
parents:
diff changeset
3174 // That is by design - we trade "lossy" counters which are exposed to
a61af66fc99e Initial load
duke
parents:
diff changeset
3175 // races during updates for a lower probe effect.
a61af66fc99e Initial load
duke
parents:
diff changeset
3176 TEVENT (Inflated enter - Futile wakeup) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3177 if (ObjectSynchronizer::_sync_FutileWakeups != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3178 ObjectSynchronizer::_sync_FutileWakeups->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3179 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3180 ++ nWakeups ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3181
a61af66fc99e Initial load
duke
parents:
diff changeset
3182 // Assuming this is not a spurious wakeup we'll normally find _succ == Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
3183 // We can defer clearing _succ until after the spin completes
a61af66fc99e Initial load
duke
parents:
diff changeset
3184 // TrySpin() must tolerate being called with _succ == Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
3185 // Try yet another round of adaptive spinning.
a61af66fc99e Initial load
duke
parents:
diff changeset
3186 if ((Knob_SpinAfterFutile & 1) && TrySpin (Self) > 0) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3187
a61af66fc99e Initial load
duke
parents:
diff changeset
3188 // We can find that we were unpark()ed and redesignated _succ while
a61af66fc99e Initial load
duke
parents:
diff changeset
3189 // we were spinning. That's harmless. If we iterate and call park(),
a61af66fc99e Initial load
duke
parents:
diff changeset
3190 // park() will consume the event and return immediately and we'll
a61af66fc99e Initial load
duke
parents:
diff changeset
3191 // just spin again. This pattern can repeat, leaving _succ to simply
a61af66fc99e Initial load
duke
parents:
diff changeset
3192 // spin on a CPU. Enable Knob_ResetEvent to clear pending unparks().
a61af66fc99e Initial load
duke
parents:
diff changeset
3193 // Alternately, we can sample fired() here, and if set, forgo spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
3194 // in the next iteration.
a61af66fc99e Initial load
duke
parents:
diff changeset
3195
a61af66fc99e Initial load
duke
parents:
diff changeset
3196 if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3197 Self->_ParkEvent->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3198 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3199 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3200 if (_succ == Self) _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3201
a61af66fc99e Initial load
duke
parents:
diff changeset
3202 // Invariant: after clearing _succ a thread *must* retry _owner before parking.
a61af66fc99e Initial load
duke
parents:
diff changeset
3203 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3204 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3205
a61af66fc99e Initial load
duke
parents:
diff changeset
3206 // Egress :
a61af66fc99e Initial load
duke
parents:
diff changeset
3207 // Self has acquired the lock -- Unlink Self from the cxq or EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3208 // Normally we'll find Self on the EntryList .
a61af66fc99e Initial load
duke
parents:
diff changeset
3209 // From the perspective of the lock owner (this thread), the
a61af66fc99e Initial load
duke
parents:
diff changeset
3210 // EntryList is stable and cxq is prepend-only.
a61af66fc99e Initial load
duke
parents:
diff changeset
3211 // The head of cxq is volatile but the interior is stable.
a61af66fc99e Initial load
duke
parents:
diff changeset
3212 // In addition, Self.TState is stable.
a61af66fc99e Initial load
duke
parents:
diff changeset
3213
a61af66fc99e Initial load
duke
parents:
diff changeset
3214 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3215 assert (object() != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3216 // I'd like to write:
a61af66fc99e Initial load
duke
parents:
diff changeset
3217 // guarantee (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3218 // but as we're at a safepoint that's not safe.
a61af66fc99e Initial load
duke
parents:
diff changeset
3219
a61af66fc99e Initial load
duke
parents:
diff changeset
3220 UnlinkAfterAcquire (Self, &node) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3221 if (_succ == Self) _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3222
a61af66fc99e Initial load
duke
parents:
diff changeset
3223 assert (_succ != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3224 if (_Responsible == Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3225 _Responsible = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3226 // Dekker pivot-point.
a61af66fc99e Initial load
duke
parents:
diff changeset
3227 // Consider OrderAccess::storeload() here
a61af66fc99e Initial load
duke
parents:
diff changeset
3228
a61af66fc99e Initial load
duke
parents:
diff changeset
3229 // We may leave threads on cxq|EntryList without a designated
a61af66fc99e Initial load
duke
parents:
diff changeset
3230 // "Responsible" thread. This is benign. When this thread subsequently
a61af66fc99e Initial load
duke
parents:
diff changeset
3231 // exits the monitor it can "see" such preexisting "old" threads --
a61af66fc99e Initial load
duke
parents:
diff changeset
3232 // threads that arrived on the cxq|EntryList before the fence, above --
a61af66fc99e Initial load
duke
parents:
diff changeset
3233 // by LDing cxq|EntryList. Newly arrived threads -- that is, threads
a61af66fc99e Initial load
duke
parents:
diff changeset
3234 // that arrive on cxq after the ST:MEMBAR, above -- will set Responsible
a61af66fc99e Initial load
duke
parents:
diff changeset
3235 // non-null and elect a new "Responsible" timer thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
3236 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3237 // This thread executes:
a61af66fc99e Initial load
duke
parents:
diff changeset
3238 // ST Responsible=null; MEMBAR (in enter epilog - here)
a61af66fc99e Initial load
duke
parents:
diff changeset
3239 // LD cxq|EntryList (in subsequent exit)
a61af66fc99e Initial load
duke
parents:
diff changeset
3240 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3241 // Entering threads in the slow/contended path execute:
a61af66fc99e Initial load
duke
parents:
diff changeset
3242 // ST cxq=nonnull; MEMBAR; LD Responsible (in enter prolog)
a61af66fc99e Initial load
duke
parents:
diff changeset
3243 // The (ST cxq; MEMBAR) is accomplished with CAS().
a61af66fc99e Initial load
duke
parents:
diff changeset
3244 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3245 // The MEMBAR, above, prevents the LD of cxq|EntryList in the subsequent
a61af66fc99e Initial load
duke
parents:
diff changeset
3246 // exit operation from floating above the ST Responsible=null.
a61af66fc99e Initial load
duke
parents:
diff changeset
3247 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3248 // In *practice* however, EnterI() is always followed by some atomic
a61af66fc99e Initial load
duke
parents:
diff changeset
3249 // operation such as the decrement of _count in ::enter(). Those atomics
a61af66fc99e Initial load
duke
parents:
diff changeset
3250 // obviate the need for the explicit MEMBAR, above.
a61af66fc99e Initial load
duke
parents:
diff changeset
3251 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3252
a61af66fc99e Initial load
duke
parents:
diff changeset
3253 // We've acquired ownership with CAS().
a61af66fc99e Initial load
duke
parents:
diff changeset
3254 // CAS is serializing -- it has MEMBAR/FENCE-equivalent semantics.
a61af66fc99e Initial load
duke
parents:
diff changeset
3255 // But since the CAS() this thread may have also stored into _succ,
a61af66fc99e Initial load
duke
parents:
diff changeset
3256 // EntryList, cxq or Responsible. These meta-data updates must be
a61af66fc99e Initial load
duke
parents:
diff changeset
3257 // visible __before this thread subsequently drops the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3258 // Consider what could occur if we didn't enforce this constraint --
a61af66fc99e Initial load
duke
parents:
diff changeset
3259 // STs to monitor meta-data and user-data could reorder with (become
a61af66fc99e Initial load
duke
parents:
diff changeset
3260 // visible after) the ST in exit that drops ownership of the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3261 // Some other thread could then acquire the lock, but observe inconsistent
a61af66fc99e Initial load
duke
parents:
diff changeset
3262 // or old monitor meta-data and heap data. That violates the JMM.
a61af66fc99e Initial load
duke
parents:
diff changeset
3263 // To that end, the 1-0 exit() operation must have at least STST|LDST
a61af66fc99e Initial load
duke
parents:
diff changeset
3264 // "release" barrier semantics. Specifically, there must be at least a
a61af66fc99e Initial load
duke
parents:
diff changeset
3265 // STST|LDST barrier in exit() before the ST of null into _owner that drops
a61af66fc99e Initial load
duke
parents:
diff changeset
3266 // the lock. The barrier ensures that changes to monitor meta-data and data
a61af66fc99e Initial load
duke
parents:
diff changeset
3267 // protected by the lock will be visible before we release the lock, and
a61af66fc99e Initial load
duke
parents:
diff changeset
3268 // therefore before some other thread (CPU) has a chance to acquire the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3269 // See also: http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
a61af66fc99e Initial load
duke
parents:
diff changeset
3270 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3271 // Critically, any prior STs to _succ or EntryList must be visible before
a61af66fc99e Initial load
duke
parents:
diff changeset
3272 // the ST of null into _owner in the *subsequent* (following) corresponding
a61af66fc99e Initial load
duke
parents:
diff changeset
3273 // monitorexit. Recall too, that in 1-0 mode monitorexit does not necessarily
a61af66fc99e Initial load
duke
parents:
diff changeset
3274 // execute a serializing instruction.
a61af66fc99e Initial load
duke
parents:
diff changeset
3275
a61af66fc99e Initial load
duke
parents:
diff changeset
3276 if (SyncFlags & 8) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3277 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3278 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3279 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3280 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3281
a61af66fc99e Initial load
duke
parents:
diff changeset
3282 // ExitSuspendEquivalent:
a61af66fc99e Initial load
duke
parents:
diff changeset
3283 // A faster alternate to handle_special_suspend_equivalent_condition()
a61af66fc99e Initial load
duke
parents:
diff changeset
3284 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3285 // handle_special_suspend_equivalent_condition() unconditionally
a61af66fc99e Initial load
duke
parents:
diff changeset
3286 // acquires the SR_lock. On some platforms uncontended MutexLocker()
a61af66fc99e Initial load
duke
parents:
diff changeset
3287 // operations have high latency. Note that in ::enter() we call HSSEC
a61af66fc99e Initial load
duke
parents:
diff changeset
3288 // while holding the monitor, so we effectively lengthen the critical sections.
a61af66fc99e Initial load
duke
parents:
diff changeset
3289 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3290 // There are a number of possible solutions:
a61af66fc99e Initial load
duke
parents:
diff changeset
3291 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3292 // A. To ameliorate the problem we might also defer state transitions
a61af66fc99e Initial load
duke
parents:
diff changeset
3293 // to as late as possible -- just prior to parking.
a61af66fc99e Initial load
duke
parents:
diff changeset
3294 // Given that, we'd call HSSEC after having returned from park(),
a61af66fc99e Initial load
duke
parents:
diff changeset
3295 // but before attempting to acquire the monitor. This is only a
a61af66fc99e Initial load
duke
parents:
diff changeset
3296 // partial solution. It avoids calling HSSEC while holding the
a61af66fc99e Initial load
duke
parents:
diff changeset
3297 // monitor (good), but it still increases successor reacquisition latency --
a61af66fc99e Initial load
duke
parents:
diff changeset
3298 // the interval between unparking a successor and the time the successor
a61af66fc99e Initial load
duke
parents:
diff changeset
3299 // resumes and retries the lock. See ReenterI(), which defers state transitions.
a61af66fc99e Initial load
duke
parents:
diff changeset
3300 // If we use this technique we can also avoid EnterI()-exit() loop
a61af66fc99e Initial load
duke
parents:
diff changeset
3301 // in ::enter() where we iteratively drop the lock and then attempt
a61af66fc99e Initial load
duke
parents:
diff changeset
3302 // to reacquire it after suspending.
a61af66fc99e Initial load
duke
parents:
diff changeset
3303 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3304 // B. In the future we might fold all the suspend bits into a
a61af66fc99e Initial load
duke
parents:
diff changeset
3305 // composite per-thread suspend flag and then update it with CAS().
a61af66fc99e Initial load
duke
parents:
diff changeset
3306 // Alternately, a Dekker-like mechanism with multiple variables
a61af66fc99e Initial load
duke
parents:
diff changeset
3307 // would suffice:
a61af66fc99e Initial load
duke
parents:
diff changeset
3308 // ST Self->_suspend_equivalent = false
a61af66fc99e Initial load
duke
parents:
diff changeset
3309 // MEMBAR
a61af66fc99e Initial load
duke
parents:
diff changeset
3310 // LD Self_>_suspend_flags
a61af66fc99e Initial load
duke
parents:
diff changeset
3311 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3312
a61af66fc99e Initial load
duke
parents:
diff changeset
3313
a61af66fc99e Initial load
duke
parents:
diff changeset
3314 bool ObjectMonitor::ExitSuspendEquivalent (JavaThread * jSelf) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3315 int Mode = Knob_FastHSSEC ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3316 if (Mode && !jSelf->is_external_suspend()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3317 assert (jSelf->is_suspend_equivalent(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3318 jSelf->clear_suspend_equivalent() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3319 if (2 == Mode) OrderAccess::storeload() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3320 if (!jSelf->is_external_suspend()) return false ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3321 // We raced a suspension -- fall thru into the slow path
a61af66fc99e Initial load
duke
parents:
diff changeset
3322 TEVENT (ExitSuspendEquivalent - raced) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3323 jSelf->set_suspend_equivalent() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3324 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3325 return jSelf->handle_special_suspend_equivalent_condition() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3326 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3327
a61af66fc99e Initial load
duke
parents:
diff changeset
3328
a61af66fc99e Initial load
duke
parents:
diff changeset
3329 // ReenterI() is a specialized inline form of the latter half of the
a61af66fc99e Initial load
duke
parents:
diff changeset
3330 // contended slow-path from EnterI(). We use ReenterI() only for
a61af66fc99e Initial load
duke
parents:
diff changeset
3331 // monitor reentry in wait().
a61af66fc99e Initial load
duke
parents:
diff changeset
3332 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3333 // In the future we should reconcile EnterI() and ReenterI(), adding
a61af66fc99e Initial load
duke
parents:
diff changeset
3334 // Knob_Reset and Knob_SpinAfterFutile support and restructuring the
a61af66fc99e Initial load
duke
parents:
diff changeset
3335 // loop accordingly.
a61af66fc99e Initial load
duke
parents:
diff changeset
3336
a61af66fc99e Initial load
duke
parents:
diff changeset
3337 void ATTR ObjectMonitor::ReenterI (Thread * Self, ObjectWaiter * SelfNode) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3338 assert (Self != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3339 assert (SelfNode != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3340 assert (SelfNode->_thread == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3341 assert (_waiters > 0 , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3342 assert (((oop)(object()))->mark() == markOopDesc::encode(this) , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3343 assert (((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3344 JavaThread * jt = (JavaThread *) Self ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3345
a61af66fc99e Initial load
duke
parents:
diff changeset
3346 int nWakeups = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3347 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3348 ObjectWaiter::TStates v = SelfNode->TState ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3349 guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3350 assert (_owner != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3351
a61af66fc99e Initial load
duke
parents:
diff changeset
3352 if (TryLock (Self) > 0) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3353 if (TrySpin (Self) > 0) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3354
a61af66fc99e Initial load
duke
parents:
diff changeset
3355 TEVENT (Wait Reentry - parking) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3356
a61af66fc99e Initial load
duke
parents:
diff changeset
3357 // State transition wrappers around park() ...
a61af66fc99e Initial load
duke
parents:
diff changeset
3358 // ReenterI() wisely defers state transitions until
a61af66fc99e Initial load
duke
parents:
diff changeset
3359 // it's clear we must park the thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
3360 {
a61af66fc99e Initial load
duke
parents:
diff changeset
3361 OSThreadContendState osts(Self->osthread());
a61af66fc99e Initial load
duke
parents:
diff changeset
3362 ThreadBlockInVM tbivm(jt);
a61af66fc99e Initial load
duke
parents:
diff changeset
3363
a61af66fc99e Initial load
duke
parents:
diff changeset
3364 // cleared by handle_special_suspend_equivalent_condition()
a61af66fc99e Initial load
duke
parents:
diff changeset
3365 // or java_suspend_self()
a61af66fc99e Initial load
duke
parents:
diff changeset
3366 jt->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
3367 if (SyncFlags & 1) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3368 Self->_ParkEvent->park ((jlong)1000) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3369 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3370 Self->_ParkEvent->park () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3371 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3372
a61af66fc99e Initial load
duke
parents:
diff changeset
3373 // were we externally suspended while we were waiting?
a61af66fc99e Initial load
duke
parents:
diff changeset
3374 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3375 if (!ExitSuspendEquivalent (jt)) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3376 if (_succ == Self) { _succ = NULL; OrderAccess::fence(); }
a61af66fc99e Initial load
duke
parents:
diff changeset
3377 jt->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
3378 jt->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
3379 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3380 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3381
a61af66fc99e Initial load
duke
parents:
diff changeset
3382 // Try again, but just so we distinguish between futile wakeups and
a61af66fc99e Initial load
duke
parents:
diff changeset
3383 // successful wakeups. The following test isn't algorithmically
a61af66fc99e Initial load
duke
parents:
diff changeset
3384 // necessary, but it helps us maintain sensible statistics.
a61af66fc99e Initial load
duke
parents:
diff changeset
3385 if (TryLock(Self) > 0) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3386
a61af66fc99e Initial load
duke
parents:
diff changeset
3387 // The lock is still contested.
a61af66fc99e Initial load
duke
parents:
diff changeset
3388 // Keep a tally of the # of futile wakeups.
a61af66fc99e Initial load
duke
parents:
diff changeset
3389 // Note that the counter is not protected by a lock or updated by atomics.
a61af66fc99e Initial load
duke
parents:
diff changeset
3390 // That is by design - we trade "lossy" counters which are exposed to
a61af66fc99e Initial load
duke
parents:
diff changeset
3391 // races during updates for a lower probe effect.
a61af66fc99e Initial load
duke
parents:
diff changeset
3392 TEVENT (Wait Reentry - futile wakeup) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3393 ++ nWakeups ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3394
a61af66fc99e Initial load
duke
parents:
diff changeset
3395 // Assuming this is not a spurious wakeup we'll normally
a61af66fc99e Initial load
duke
parents:
diff changeset
3396 // find that _succ == Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
3397 if (_succ == Self) _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3398
a61af66fc99e Initial load
duke
parents:
diff changeset
3399 // Invariant: after clearing _succ a contending thread
a61af66fc99e Initial load
duke
parents:
diff changeset
3400 // *must* retry _owner before parking.
a61af66fc99e Initial load
duke
parents:
diff changeset
3401 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3402
a61af66fc99e Initial load
duke
parents:
diff changeset
3403 if (ObjectSynchronizer::_sync_FutileWakeups != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3404 ObjectSynchronizer::_sync_FutileWakeups->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3405 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3406 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3407
a61af66fc99e Initial load
duke
parents:
diff changeset
3408 // Self has acquired the lock -- Unlink Self from the cxq or EntryList .
a61af66fc99e Initial load
duke
parents:
diff changeset
3409 // Normally we'll find Self on the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3410 // Unlinking from the EntryList is constant-time and atomic-free.
a61af66fc99e Initial load
duke
parents:
diff changeset
3411 // From the perspective of the lock owner (this thread), the
a61af66fc99e Initial load
duke
parents:
diff changeset
3412 // EntryList is stable and cxq is prepend-only.
a61af66fc99e Initial load
duke
parents:
diff changeset
3413 // The head of cxq is volatile but the interior is stable.
a61af66fc99e Initial load
duke
parents:
diff changeset
3414 // In addition, Self.TState is stable.
a61af66fc99e Initial load
duke
parents:
diff changeset
3415
a61af66fc99e Initial load
duke
parents:
diff changeset
3416 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3417 assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3418 UnlinkAfterAcquire (Self, SelfNode) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3419 if (_succ == Self) _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3420 assert (_succ != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3421 SelfNode->TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3422 OrderAccess::fence() ; // see comments at the end of EnterI()
a61af66fc99e Initial load
duke
parents:
diff changeset
3423 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3424
a61af66fc99e Initial load
duke
parents:
diff changeset
3425 bool ObjectMonitor::try_enter(Thread* THREAD) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3426 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3427 if (THREAD->is_lock_owned ((address)_owner)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3428 assert(_recursions == 0, "internal state error");
a61af66fc99e Initial load
duke
parents:
diff changeset
3429 _owner = THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3430 _recursions = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3431 OwnerIsThread = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3432 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
3433 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3434 if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3435 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
3436 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3437 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
3438 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3439 _recursions++;
a61af66fc99e Initial load
duke
parents:
diff changeset
3440 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
3441 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3442 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3443
a61af66fc99e Initial load
duke
parents:
diff changeset
3444 void ATTR ObjectMonitor::enter(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3445 // The following code is ordered to check the most common cases first
a61af66fc99e Initial load
duke
parents:
diff changeset
3446 // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
a61af66fc99e Initial load
duke
parents:
diff changeset
3447 Thread * const Self = THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3448 void * cur ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3449
a61af66fc99e Initial load
duke
parents:
diff changeset
3450 cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3451 if (cur == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3452 // Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
a61af66fc99e Initial load
duke
parents:
diff changeset
3453 assert (_recursions == 0 , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3454 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3455 // CONSIDER: set or assert OwnerIsThread == 1
a61af66fc99e Initial load
duke
parents:
diff changeset
3456 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3457 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3458
a61af66fc99e Initial load
duke
parents:
diff changeset
3459 if (cur == Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3460 // TODO-FIXME: check for integer overflow! BUGID 6557169.
a61af66fc99e Initial load
duke
parents:
diff changeset
3461 _recursions ++ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3462 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3463 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3464
a61af66fc99e Initial load
duke
parents:
diff changeset
3465 if (Self->is_lock_owned ((address)cur)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3466 assert (_recursions == 0, "internal state error");
a61af66fc99e Initial load
duke
parents:
diff changeset
3467 _recursions = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3468 // Commute owner from a thread-specific on-stack BasicLockObject address to
a61af66fc99e Initial load
duke
parents:
diff changeset
3469 // a full-fledged "Thread *".
a61af66fc99e Initial load
duke
parents:
diff changeset
3470 _owner = Self ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3471 OwnerIsThread = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3472 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3473 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3474
a61af66fc99e Initial load
duke
parents:
diff changeset
3475 // We've encountered genuine contention.
a61af66fc99e Initial load
duke
parents:
diff changeset
3476 assert (Self->_Stalled == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3477 Self->_Stalled = intptr_t(this) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3478
a61af66fc99e Initial load
duke
parents:
diff changeset
3479 // Try one round of spinning *before* enqueueing Self
a61af66fc99e Initial load
duke
parents:
diff changeset
3480 // and before going through the awkward and expensive state
a61af66fc99e Initial load
duke
parents:
diff changeset
3481 // transitions. The following spin is strictly optional ...
a61af66fc99e Initial load
duke
parents:
diff changeset
3482 // Note that if we acquire the monitor from an initial spin
a61af66fc99e Initial load
duke
parents:
diff changeset
3483 // we forgo posting JVMTI events and firing DTRACE probes.
a61af66fc99e Initial load
duke
parents:
diff changeset
3484 if (Knob_SpinEarly && TrySpin (Self) > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3485 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3486 assert (_recursions == 0 , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3487 assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3488 Self->_Stalled = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3489 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3490 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3491
a61af66fc99e Initial load
duke
parents:
diff changeset
3492 assert (_owner != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3493 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3494 assert (Self->is_Java_thread() , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3495 JavaThread * jt = (JavaThread *) Self ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3496 assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3497 assert (jt->thread_state() != _thread_blocked , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3498 assert (this->object() != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3499 assert (_count >= 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3500
a61af66fc99e Initial load
duke
parents:
diff changeset
3501 // Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
a61af66fc99e Initial load
duke
parents:
diff changeset
3502 // Ensure the object-monitor relationship remains stable while there's contention.
a61af66fc99e Initial load
duke
parents:
diff changeset
3503 Atomic::inc_ptr(&_count);
a61af66fc99e Initial load
duke
parents:
diff changeset
3504
a61af66fc99e Initial load
duke
parents:
diff changeset
3505 { // Change java thread status to indicate blocked on monitor enter.
a61af66fc99e Initial load
duke
parents:
diff changeset
3506 JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
a61af66fc99e Initial load
duke
parents:
diff changeset
3507
a61af66fc99e Initial load
duke
parents:
diff changeset
3508 DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
a61af66fc99e Initial load
duke
parents:
diff changeset
3509 if (JvmtiExport::should_post_monitor_contended_enter()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3510 JvmtiExport::post_monitor_contended_enter(jt, this);
a61af66fc99e Initial load
duke
parents:
diff changeset
3511 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3512
a61af66fc99e Initial load
duke
parents:
diff changeset
3513 OSThreadContendState osts(Self->osthread());
a61af66fc99e Initial load
duke
parents:
diff changeset
3514 ThreadBlockInVM tbivm(jt);
a61af66fc99e Initial load
duke
parents:
diff changeset
3515
a61af66fc99e Initial load
duke
parents:
diff changeset
3516 Self->set_current_pending_monitor(this);
a61af66fc99e Initial load
duke
parents:
diff changeset
3517
a61af66fc99e Initial load
duke
parents:
diff changeset
3518 // TODO-FIXME: change the following for(;;) loop to straight-line code.
a61af66fc99e Initial load
duke
parents:
diff changeset
3519 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3520 jt->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
3521 // cleared by handle_special_suspend_equivalent_condition()
a61af66fc99e Initial load
duke
parents:
diff changeset
3522 // or java_suspend_self()
a61af66fc99e Initial load
duke
parents:
diff changeset
3523
a61af66fc99e Initial load
duke
parents:
diff changeset
3524 EnterI (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3525
a61af66fc99e Initial load
duke
parents:
diff changeset
3526 if (!ExitSuspendEquivalent(jt)) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3527
a61af66fc99e Initial load
duke
parents:
diff changeset
3528 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3529 // We have acquired the contended monitor, but while we were
a61af66fc99e Initial load
duke
parents:
diff changeset
3530 // waiting another thread suspended us. We don't want to enter
a61af66fc99e Initial load
duke
parents:
diff changeset
3531 // the monitor while suspended because that would surprise the
a61af66fc99e Initial load
duke
parents:
diff changeset
3532 // thread that suspended us.
a61af66fc99e Initial load
duke
parents:
diff changeset
3533 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3534 _recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3535 _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3536 exit (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3537
a61af66fc99e Initial load
duke
parents:
diff changeset
3538 jt->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
3539 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3540 Self->set_current_pending_monitor(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
3541 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3542
a61af66fc99e Initial load
duke
parents:
diff changeset
3543 Atomic::dec_ptr(&_count);
a61af66fc99e Initial load
duke
parents:
diff changeset
3544 assert (_count >= 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3545 Self->_Stalled = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3546
a61af66fc99e Initial load
duke
parents:
diff changeset
3547 // Must either set _recursions = 0 or ASSERT _recursions == 0.
a61af66fc99e Initial load
duke
parents:
diff changeset
3548 assert (_recursions == 0 , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3549 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3550 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3551 assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3552
a61af66fc99e Initial load
duke
parents:
diff changeset
3553 // The thread -- now the owner -- is back in vm mode.
a61af66fc99e Initial load
duke
parents:
diff changeset
3554 // Report the glorious news via TI,DTrace and jvmstat.
a61af66fc99e Initial load
duke
parents:
diff changeset
3555 // The probe effect is non-trivial. All the reportage occurs
a61af66fc99e Initial load
duke
parents:
diff changeset
3556 // while we hold the monitor, increasing the length of the critical
a61af66fc99e Initial load
duke
parents:
diff changeset
3557 // section. Amdahl's parallel speedup law comes vividly into play.
a61af66fc99e Initial load
duke
parents:
diff changeset
3558 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3559 // Another option might be to aggregate the events (thread local or
a61af66fc99e Initial load
duke
parents:
diff changeset
3560 // per-monitor aggregation) and defer reporting until a more opportune
a61af66fc99e Initial load
duke
parents:
diff changeset
3561 // time -- such as next time some thread encounters contention but has
a61af66fc99e Initial load
duke
parents:
diff changeset
3562 // yet to acquire the lock. While spinning that thread could
a61af66fc99e Initial load
duke
parents:
diff changeset
3563 // spinning we could increment JVMStat counters, etc.
a61af66fc99e Initial load
duke
parents:
diff changeset
3564
a61af66fc99e Initial load
duke
parents:
diff changeset
3565 DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
a61af66fc99e Initial load
duke
parents:
diff changeset
3566 if (JvmtiExport::should_post_monitor_contended_entered()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3567 JvmtiExport::post_monitor_contended_entered(jt, this);
a61af66fc99e Initial load
duke
parents:
diff changeset
3568 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3569 if (ObjectSynchronizer::_sync_ContendedLockAttempts != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3570 ObjectSynchronizer::_sync_ContendedLockAttempts->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3571 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3572 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3573
a61af66fc99e Initial load
duke
parents:
diff changeset
3574 void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3575 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3576
a61af66fc99e Initial load
duke
parents:
diff changeset
3577 // Exit protocol:
a61af66fc99e Initial load
duke
parents:
diff changeset
3578 // 1. ST _succ = wakee
a61af66fc99e Initial load
duke
parents:
diff changeset
3579 // 2. membar #loadstore|#storestore;
a61af66fc99e Initial load
duke
parents:
diff changeset
3580 // 2. ST _owner = NULL
a61af66fc99e Initial load
duke
parents:
diff changeset
3581 // 3. unpark(wakee)
a61af66fc99e Initial load
duke
parents:
diff changeset
3582
a61af66fc99e Initial load
duke
parents:
diff changeset
3583 _succ = Knob_SuccEnabled ? Wakee->_thread : NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3584 ParkEvent * Trigger = Wakee->_event ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3585
a61af66fc99e Initial load
duke
parents:
diff changeset
3586 // Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
a61af66fc99e Initial load
duke
parents:
diff changeset
3587 // The thread associated with Wakee may have grabbed the lock and "Wakee" may be
a61af66fc99e Initial load
duke
parents:
diff changeset
3588 // out-of-scope (non-extant).
a61af66fc99e Initial load
duke
parents:
diff changeset
3589 Wakee = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3590
a61af66fc99e Initial load
duke
parents:
diff changeset
3591 // Drop the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
3592 OrderAccess::release_store_ptr (&_owner, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3593 OrderAccess::fence() ; // ST _owner vs LD in unpark()
a61af66fc99e Initial load
duke
parents:
diff changeset
3594
a61af66fc99e Initial load
duke
parents:
diff changeset
3595 // TODO-FIXME:
a61af66fc99e Initial load
duke
parents:
diff changeset
3596 // If there's a safepoint pending the best policy would be to
a61af66fc99e Initial load
duke
parents:
diff changeset
3597 // get _this thread to a safepoint and only wake the successor
a61af66fc99e Initial load
duke
parents:
diff changeset
3598 // after the safepoint completed. monitorexit uses a "leaf"
a61af66fc99e Initial load
duke
parents:
diff changeset
3599 // state transition, however, so this thread can't become
a61af66fc99e Initial load
duke
parents:
diff changeset
3600 // safe at this point in time. (Its stack isn't walkable).
a61af66fc99e Initial load
duke
parents:
diff changeset
3601 // The next best thing is to defer waking the successor by
a61af66fc99e Initial load
duke
parents:
diff changeset
3602 // adding to a list of thread to be unparked after at the
a61af66fc99e Initial load
duke
parents:
diff changeset
3603 // end of the forthcoming STW).
a61af66fc99e Initial load
duke
parents:
diff changeset
3604 if (SafepointSynchronize::do_call_back()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3605 TEVENT (unpark before SAFEPOINT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3606 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3607
a61af66fc99e Initial load
duke
parents:
diff changeset
3608 // Possible optimizations ...
a61af66fc99e Initial load
duke
parents:
diff changeset
3609 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3610 // * Consider: set Wakee->UnparkTime = timeNow()
a61af66fc99e Initial load
duke
parents:
diff changeset
3611 // When the thread wakes up it'll compute (timeNow() - Self->UnparkTime()).
a61af66fc99e Initial load
duke
parents:
diff changeset
3612 // By measuring recent ONPROC latency we can approximate the
a61af66fc99e Initial load
duke
parents:
diff changeset
3613 // system load. In turn, we can feed that information back
a61af66fc99e Initial load
duke
parents:
diff changeset
3614 // into the spinning & succession policies.
a61af66fc99e Initial load
duke
parents:
diff changeset
3615 // (ONPROC latency correlates strongly with load).
a61af66fc99e Initial load
duke
parents:
diff changeset
3616 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3617 // * Pull affinity:
a61af66fc99e Initial load
duke
parents:
diff changeset
3618 // If the wakee is cold then transiently setting it's affinity
a61af66fc99e Initial load
duke
parents:
diff changeset
3619 // to the current CPU is a good idea.
a61af66fc99e Initial load
duke
parents:
diff changeset
3620 // See http://j2se.east/~dice/PERSIST/050624-PullAffinity.txt
478
a7fac4381b50 6639341: sometimes contended-exit event comes after contended-entered on another thread
blacklion
parents: 0
diff changeset
3621 DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
0
a61af66fc99e Initial load
duke
parents:
diff changeset
3622 Trigger->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3623
a61af66fc99e Initial load
duke
parents:
diff changeset
3624 // Maintain stats and report events to JVMTI
a61af66fc99e Initial load
duke
parents:
diff changeset
3625 if (ObjectSynchronizer::_sync_Parks != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3626 ObjectSynchronizer::_sync_Parks->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3627 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3628 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3629
a61af66fc99e Initial load
duke
parents:
diff changeset
3630
a61af66fc99e Initial load
duke
parents:
diff changeset
3631 // exit()
a61af66fc99e Initial load
duke
parents:
diff changeset
3632 // ~~~~~~
a61af66fc99e Initial load
duke
parents:
diff changeset
3633 // Note that the collector can't reclaim the objectMonitor or deflate
a61af66fc99e Initial load
duke
parents:
diff changeset
3634 // the object out from underneath the thread calling ::exit() as the
a61af66fc99e Initial load
duke
parents:
diff changeset
3635 // thread calling ::exit() never transitions to a stable state.
a61af66fc99e Initial load
duke
parents:
diff changeset
3636 // This inhibits GC, which in turn inhibits asynchronous (and
a61af66fc99e Initial load
duke
parents:
diff changeset
3637 // inopportune) reclamation of "this".
a61af66fc99e Initial load
duke
parents:
diff changeset
3638 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3639 // We'd like to assert that: (THREAD->thread_state() != _thread_blocked) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3640 // There's one exception to the claim above, however. EnterI() can call
a61af66fc99e Initial load
duke
parents:
diff changeset
3641 // exit() to drop a lock if the acquirer has been externally suspended.
a61af66fc99e Initial load
duke
parents:
diff changeset
3642 // In that case exit() is called with _thread_state as _thread_blocked,
a61af66fc99e Initial load
duke
parents:
diff changeset
3643 // but the monitor's _count field is > 0, which inhibits reclamation.
a61af66fc99e Initial load
duke
parents:
diff changeset
3644 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3645 // 1-0 exit
a61af66fc99e Initial load
duke
parents:
diff changeset
3646 // ~~~~~~~~
a61af66fc99e Initial load
duke
parents:
diff changeset
3647 // ::exit() uses a canonical 1-1 idiom with a MEMBAR although some of
a61af66fc99e Initial load
duke
parents:
diff changeset
3648 // the fast-path operators have been optimized so the common ::exit()
a61af66fc99e Initial load
duke
parents:
diff changeset
3649 // operation is 1-0. See i486.ad fast_unlock(), for instance.
a61af66fc99e Initial load
duke
parents:
diff changeset
3650 // The code emitted by fast_unlock() elides the usual MEMBAR. This
a61af66fc99e Initial load
duke
parents:
diff changeset
3651 // greatly improves latency -- MEMBAR and CAS having considerable local
a61af66fc99e Initial load
duke
parents:
diff changeset
3652 // latency on modern processors -- but at the cost of "stranding". Absent the
a61af66fc99e Initial load
duke
parents:
diff changeset
3653 // MEMBAR, a thread in fast_unlock() can race a thread in the slow
a61af66fc99e Initial load
duke
parents:
diff changeset
3654 // ::enter() path, resulting in the entering thread being stranding
a61af66fc99e Initial load
duke
parents:
diff changeset
3655 // and a progress-liveness failure. Stranding is extremely rare.
a61af66fc99e Initial load
duke
parents:
diff changeset
3656 // We use timers (timed park operations) & periodic polling to detect
a61af66fc99e Initial load
duke
parents:
diff changeset
3657 // and recover from stranding. Potentially stranded threads periodically
a61af66fc99e Initial load
duke
parents:
diff changeset
3658 // wake up and poll the lock. See the usage of the _Responsible variable.
a61af66fc99e Initial load
duke
parents:
diff changeset
3659 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3660 // The CAS() in enter provides for safety and exclusion, while the CAS or
a61af66fc99e Initial load
duke
parents:
diff changeset
3661 // MEMBAR in exit provides for progress and avoids stranding. 1-0 locking
a61af66fc99e Initial load
duke
parents:
diff changeset
3662 // eliminates the CAS/MEMBAR from the exist path, but it admits stranding.
a61af66fc99e Initial load
duke
parents:
diff changeset
3663 // We detect and recover from stranding with timers.
a61af66fc99e Initial load
duke
parents:
diff changeset
3664 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3665 // If a thread transiently strands it'll park until (a) another
a61af66fc99e Initial load
duke
parents:
diff changeset
3666 // thread acquires the lock and then drops the lock, at which time the
a61af66fc99e Initial load
duke
parents:
diff changeset
3667 // exiting thread will notice and unpark the stranded thread, or, (b)
a61af66fc99e Initial load
duke
parents:
diff changeset
3668 // the timer expires. If the lock is high traffic then the stranding latency
a61af66fc99e Initial load
duke
parents:
diff changeset
3669 // will be low due to (a). If the lock is low traffic then the odds of
a61af66fc99e Initial load
duke
parents:
diff changeset
3670 // stranding are lower, although the worst-case stranding latency
a61af66fc99e Initial load
duke
parents:
diff changeset
3671 // is longer. Critically, we don't want to put excessive load in the
a61af66fc99e Initial load
duke
parents:
diff changeset
3672 // platform's timer subsystem. We want to minimize both the timer injection
a61af66fc99e Initial load
duke
parents:
diff changeset
3673 // rate (timers created/sec) as well as the number of timers active at
a61af66fc99e Initial load
duke
parents:
diff changeset
3674 // any one time. (more precisely, we want to minimize timer-seconds, which is
a61af66fc99e Initial load
duke
parents:
diff changeset
3675 // the integral of the # of active timers at any instant over time).
a61af66fc99e Initial load
duke
parents:
diff changeset
3676 // Both impinge on OS scalability. Given that, at most one thread parked on
a61af66fc99e Initial load
duke
parents:
diff changeset
3677 // a monitor will use a timer.
a61af66fc99e Initial load
duke
parents:
diff changeset
3678
a61af66fc99e Initial load
duke
parents:
diff changeset
3679 void ATTR ObjectMonitor::exit(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3680 Thread * Self = THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3681 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3682 if (THREAD->is_lock_owned((address) _owner)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3683 // Transmute _owner from a BasicLock pointer to a Thread address.
a61af66fc99e Initial load
duke
parents:
diff changeset
3684 // We don't need to hold _mutex for this transition.
a61af66fc99e Initial load
duke
parents:
diff changeset
3685 // Non-null to Non-null is safe as long as all readers can
a61af66fc99e Initial load
duke
parents:
diff changeset
3686 // tolerate either flavor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3687 assert (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3688 _owner = THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3689 _recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3690 OwnerIsThread = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3691 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3692 // NOTE: we need to handle unbalanced monitor enter/exit
a61af66fc99e Initial load
duke
parents:
diff changeset
3693 // in native code by throwing an exception.
a61af66fc99e Initial load
duke
parents:
diff changeset
3694 // TODO: Throw an IllegalMonitorStateException ?
a61af66fc99e Initial load
duke
parents:
diff changeset
3695 TEVENT (Exit - Throw IMSX) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3696 assert(false, "Non-balanced monitor enter/exit!");
a61af66fc99e Initial load
duke
parents:
diff changeset
3697 if (false) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3698 THROW(vmSymbols::java_lang_IllegalMonitorStateException());
a61af66fc99e Initial load
duke
parents:
diff changeset
3699 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3700 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
3701 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3702 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3703
a61af66fc99e Initial load
duke
parents:
diff changeset
3704 if (_recursions != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3705 _recursions--; // this is simple recursive enter
a61af66fc99e Initial load
duke
parents:
diff changeset
3706 TEVENT (Inflated exit - recursive) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3707 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3708 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3709
a61af66fc99e Initial load
duke
parents:
diff changeset
3710 // Invariant: after setting Responsible=null an thread must execute
a61af66fc99e Initial load
duke
parents:
diff changeset
3711 // a MEMBAR or other serializing instruction before fetching EntryList|cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3712 if ((SyncFlags & 4) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3713 _Responsible = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3714 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3715
a61af66fc99e Initial load
duke
parents:
diff changeset
3716 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3717 assert (THREAD == _owner, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3718
a61af66fc99e Initial load
duke
parents:
diff changeset
3719 // Fast-path monitor exit:
a61af66fc99e Initial load
duke
parents:
diff changeset
3720 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3721 // Observe the Dekker/Lamport duality:
a61af66fc99e Initial load
duke
parents:
diff changeset
3722 // A thread in ::exit() executes:
a61af66fc99e Initial load
duke
parents:
diff changeset
3723 // ST Owner=null; MEMBAR; LD EntryList|cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3724 // A thread in the contended ::enter() path executes the complementary:
a61af66fc99e Initial load
duke
parents:
diff changeset
3725 // ST EntryList|cxq = nonnull; MEMBAR; LD Owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
3726 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3727 // Note that there's a benign race in the exit path. We can drop the
a61af66fc99e Initial load
duke
parents:
diff changeset
3728 // lock, another thread can reacquire the lock immediately, and we can
a61af66fc99e Initial load
duke
parents:
diff changeset
3729 // then wake a thread unnecessarily (yet another flavor of futile wakeup).
a61af66fc99e Initial load
duke
parents:
diff changeset
3730 // This is benign, and we've structured the code so the windows are short
a61af66fc99e Initial load
duke
parents:
diff changeset
3731 // and the frequency of such futile wakeups is low.
a61af66fc99e Initial load
duke
parents:
diff changeset
3732 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3733 // We could eliminate the race by encoding both the "LOCKED" state and
a61af66fc99e Initial load
duke
parents:
diff changeset
3734 // the queue head in a single word. Exit would then use either CAS to
a61af66fc99e Initial load
duke
parents:
diff changeset
3735 // clear the LOCKED bit/byte. This precludes the desirable 1-0 optimization,
a61af66fc99e Initial load
duke
parents:
diff changeset
3736 // however.
a61af66fc99e Initial load
duke
parents:
diff changeset
3737 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3738 // Possible fast-path ::exit() optimization:
a61af66fc99e Initial load
duke
parents:
diff changeset
3739 // The current fast-path exit implementation fetches both cxq and EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3740 // See also i486.ad fast_unlock(). Testing has shown that two LDs
a61af66fc99e Initial load
duke
parents:
diff changeset
3741 // isn't measurably slower than a single LD on any platforms.
a61af66fc99e Initial load
duke
parents:
diff changeset
3742 // Still, we could reduce the 2 LDs to one or zero by one of the following:
a61af66fc99e Initial load
duke
parents:
diff changeset
3743 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3744 // - Use _count instead of cxq|EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3745 // We intend to eliminate _count, however, when we switch
a61af66fc99e Initial load
duke
parents:
diff changeset
3746 // to on-the-fly deflation in ::exit() as is used in
a61af66fc99e Initial load
duke
parents:
diff changeset
3747 // Metalocks and RelaxedLocks.
a61af66fc99e Initial load
duke
parents:
diff changeset
3748 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3749 // - Establish the invariant that cxq == null implies EntryList == null.
a61af66fc99e Initial load
duke
parents:
diff changeset
3750 // set cxq == EMPTY (1) to encode the state where cxq is empty
a61af66fc99e Initial load
duke
parents:
diff changeset
3751 // by EntryList != null. EMPTY is a distinguished value.
a61af66fc99e Initial load
duke
parents:
diff changeset
3752 // The fast-path exit() would fetch cxq but not EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3753 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3754 // - Encode succ as follows:
a61af66fc99e Initial load
duke
parents:
diff changeset
3755 // succ = t : Thread t is the successor -- t is ready or is spinning.
a61af66fc99e Initial load
duke
parents:
diff changeset
3756 // Exiting thread does not need to wake a successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3757 // succ = 0 : No successor required -> (EntryList|cxq) == null
a61af66fc99e Initial load
duke
parents:
diff changeset
3758 // Exiting thread does not need to wake a successor
a61af66fc99e Initial load
duke
parents:
diff changeset
3759 // succ = 1 : Successor required -> (EntryList|cxq) != null and
a61af66fc99e Initial load
duke
parents:
diff changeset
3760 // logically succ == null.
a61af66fc99e Initial load
duke
parents:
diff changeset
3761 // Exiting thread must wake a successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3762 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3763 // The 1-1 fast-exit path would appear as :
a61af66fc99e Initial load
duke
parents:
diff changeset
3764 // _owner = null ; membar ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3765 // if (_succ == 1 && CAS (&_owner, null, Self) == null) goto SlowPath
a61af66fc99e Initial load
duke
parents:
diff changeset
3766 // goto FastPathDone ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3767 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3768 // and the 1-0 fast-exit path would appear as:
a61af66fc99e Initial load
duke
parents:
diff changeset
3769 // if (_succ == 1) goto SlowPath
a61af66fc99e Initial load
duke
parents:
diff changeset
3770 // Owner = null ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3771 // goto FastPathDone
a61af66fc99e Initial load
duke
parents:
diff changeset
3772 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3773 // - Encode the LSB of _owner as 1 to indicate that exit()
a61af66fc99e Initial load
duke
parents:
diff changeset
3774 // must use the slow-path and make a successor ready.
a61af66fc99e Initial load
duke
parents:
diff changeset
3775 // (_owner & 1) == 0 IFF succ != null || (EntryList|cxq) == null
a61af66fc99e Initial load
duke
parents:
diff changeset
3776 // (_owner & 1) == 0 IFF succ == null && (EntryList|cxq) != null (obviously)
a61af66fc99e Initial load
duke
parents:
diff changeset
3777 // The 1-0 fast exit path would read:
a61af66fc99e Initial load
duke
parents:
diff changeset
3778 // if (_owner != Self) goto SlowPath
a61af66fc99e Initial load
duke
parents:
diff changeset
3779 // _owner = null
a61af66fc99e Initial load
duke
parents:
diff changeset
3780 // goto FastPathDone
a61af66fc99e Initial load
duke
parents:
diff changeset
3781
a61af66fc99e Initial load
duke
parents:
diff changeset
3782 if (Knob_ExitPolicy == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3783 // release semantics: prior loads and stores from within the critical section
a61af66fc99e Initial load
duke
parents:
diff changeset
3784 // must not float (reorder) past the following store that drops the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3785 // On SPARC that requires MEMBAR #loadstore|#storestore.
a61af66fc99e Initial load
duke
parents:
diff changeset
3786 // But of course in TSO #loadstore|#storestore is not required.
a61af66fc99e Initial load
duke
parents:
diff changeset
3787 // I'd like to write one of the following:
a61af66fc99e Initial load
duke
parents:
diff changeset
3788 // A. OrderAccess::release() ; _owner = NULL
a61af66fc99e Initial load
duke
parents:
diff changeset
3789 // B. OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
3790 // Unfortunately OrderAccess::release() and OrderAccess::loadstore() both
a61af66fc99e Initial load
duke
parents:
diff changeset
3791 // store into a _dummy variable. That store is not needed, but can result
a61af66fc99e Initial load
duke
parents:
diff changeset
3792 // in massive wasteful coherency traffic on classic SMP systems.
a61af66fc99e Initial load
duke
parents:
diff changeset
3793 // Instead, I use release_store(), which is implemented as just a simple
a61af66fc99e Initial load
duke
parents:
diff changeset
3794 // ST on x64, x86 and SPARC.
a61af66fc99e Initial load
duke
parents:
diff changeset
3795 OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
3796 OrderAccess::storeload() ; // See if we need to wake a successor
a61af66fc99e Initial load
duke
parents:
diff changeset
3797 if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3798 TEVENT (Inflated exit - simple egress) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3799 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3800 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3801 TEVENT (Inflated exit - complex egress) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3802
a61af66fc99e Initial load
duke
parents:
diff changeset
3803 // Normally the exiting thread is responsible for ensuring succession,
a61af66fc99e Initial load
duke
parents:
diff changeset
3804 // but if other successors are ready or other entering threads are spinning
a61af66fc99e Initial load
duke
parents:
diff changeset
3805 // then this thread can simply store NULL into _owner and exit without
a61af66fc99e Initial load
duke
parents:
diff changeset
3806 // waking a successor. The existence of spinners or ready successors
a61af66fc99e Initial load
duke
parents:
diff changeset
3807 // guarantees proper succession (liveness). Responsibility passes to the
a61af66fc99e Initial load
duke
parents:
diff changeset
3808 // ready or running successors. The exiting thread delegates the duty.
a61af66fc99e Initial load
duke
parents:
diff changeset
3809 // More precisely, if a successor already exists this thread is absolved
a61af66fc99e Initial load
duke
parents:
diff changeset
3810 // of the responsibility of waking (unparking) one.
a61af66fc99e Initial load
duke
parents:
diff changeset
3811 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3812 // The _succ variable is critical to reducing futile wakeup frequency.
a61af66fc99e Initial load
duke
parents:
diff changeset
3813 // _succ identifies the "heir presumptive" thread that has been made
a61af66fc99e Initial load
duke
parents:
diff changeset
3814 // ready (unparked) but that has not yet run. We need only one such
a61af66fc99e Initial load
duke
parents:
diff changeset
3815 // successor thread to guarantee progress.
a61af66fc99e Initial load
duke
parents:
diff changeset
3816 // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
a61af66fc99e Initial load
duke
parents:
diff changeset
3817 // section 3.3 "Futile Wakeup Throttling" for details.
a61af66fc99e Initial load
duke
parents:
diff changeset
3818 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3819 // Note that spinners in Enter() also set _succ non-null.
a61af66fc99e Initial load
duke
parents:
diff changeset
3820 // In the current implementation spinners opportunistically set
a61af66fc99e Initial load
duke
parents:
diff changeset
3821 // _succ so that exiting threads might avoid waking a successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3822 // Another less appealing alternative would be for the exiting thread
a61af66fc99e Initial load
duke
parents:
diff changeset
3823 // to drop the lock and then spin briefly to see if a spinner managed
a61af66fc99e Initial load
duke
parents:
diff changeset
3824 // to acquire the lock. If so, the exiting thread could exit
a61af66fc99e Initial load
duke
parents:
diff changeset
3825 // immediately without waking a successor, otherwise the exiting
a61af66fc99e Initial load
duke
parents:
diff changeset
3826 // thread would need to dequeue and wake a successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3827 // (Note that we'd need to make the post-drop spin short, but no
a61af66fc99e Initial load
duke
parents:
diff changeset
3828 // shorter than the worst-case round-trip cache-line migration time.
a61af66fc99e Initial load
duke
parents:
diff changeset
3829 // The dropped lock needs to become visible to the spinner, and then
a61af66fc99e Initial load
duke
parents:
diff changeset
3830 // the acquisition of the lock by the spinner must become visible to
a61af66fc99e Initial load
duke
parents:
diff changeset
3831 // the exiting thread).
a61af66fc99e Initial load
duke
parents:
diff changeset
3832 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3833
a61af66fc99e Initial load
duke
parents:
diff changeset
3834 // It appears that an heir-presumptive (successor) must be made ready.
a61af66fc99e Initial load
duke
parents:
diff changeset
3835 // Only the current lock owner can manipulate the EntryList or
a61af66fc99e Initial load
duke
parents:
diff changeset
3836 // drain _cxq, so we need to reacquire the lock. If we fail
a61af66fc99e Initial load
duke
parents:
diff changeset
3837 // to reacquire the lock the responsibility for ensuring succession
a61af66fc99e Initial load
duke
parents:
diff changeset
3838 // falls to the new owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
3839 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3840 if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3841 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3842 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3843 TEVENT (Exit - Reacquired) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3844 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3845 if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3846 OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
3847 OrderAccess::storeload() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3848 // Ratify the previously observed values.
a61af66fc99e Initial load
duke
parents:
diff changeset
3849 if (_cxq == NULL || _succ != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3850 TEVENT (Inflated exit - simple egress) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3851 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3852 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3853
a61af66fc99e Initial load
duke
parents:
diff changeset
3854 // inopportune interleaving -- the exiting thread (this thread)
a61af66fc99e Initial load
duke
parents:
diff changeset
3855 // in the fast-exit path raced an entering thread in the slow-enter
a61af66fc99e Initial load
duke
parents:
diff changeset
3856 // path.
a61af66fc99e Initial load
duke
parents:
diff changeset
3857 // We have two choices:
a61af66fc99e Initial load
duke
parents:
diff changeset
3858 // A. Try to reacquire the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3859 // If the CAS() fails return immediately, otherwise
a61af66fc99e Initial load
duke
parents:
diff changeset
3860 // we either restart/rerun the exit operation, or simply
a61af66fc99e Initial load
duke
parents:
diff changeset
3861 // fall-through into the code below which wakes a successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
3862 // B. If the elements forming the EntryList|cxq are TSM
a61af66fc99e Initial load
duke
parents:
diff changeset
3863 // we could simply unpark() the lead thread and return
a61af66fc99e Initial load
duke
parents:
diff changeset
3864 // without having set _succ.
a61af66fc99e Initial load
duke
parents:
diff changeset
3865 if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3866 TEVENT (Inflated exit - reacquired succeeded) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3867 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3868 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3869 TEVENT (Inflated exit - reacquired failed) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3870 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3871 TEVENT (Inflated exit - complex egress) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3872 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3873 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3874
a61af66fc99e Initial load
duke
parents:
diff changeset
3875 guarantee (_owner == THREAD, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3876
a61af66fc99e Initial load
duke
parents:
diff changeset
3877 // Select an appropriate successor ("heir presumptive") from the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3878 // and make it ready. Generally we just wake the head of EntryList .
a61af66fc99e Initial load
duke
parents:
diff changeset
3879 // There's no algorithmic constraint that we use the head - it's just
a61af66fc99e Initial load
duke
parents:
diff changeset
3880 // a policy decision. Note that the thread at head of the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3881 // remains at the head until it acquires the lock. This means we'll
a61af66fc99e Initial load
duke
parents:
diff changeset
3882 // repeatedly wake the same thread until it manages to grab the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
3883 // This is generally a good policy - if we're seeing lots of futile wakeups
a61af66fc99e Initial load
duke
parents:
diff changeset
3884 // at least we're waking/rewaking a thread that's like to be hot or warm
a61af66fc99e Initial load
duke
parents:
diff changeset
3885 // (have residual D$ and TLB affinity).
a61af66fc99e Initial load
duke
parents:
diff changeset
3886 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3887 // "Wakeup locality" optimization:
a61af66fc99e Initial load
duke
parents:
diff changeset
3888 // http://j2se.east/~dice/PERSIST/040825-WakeLocality.txt
a61af66fc99e Initial load
duke
parents:
diff changeset
3889 // In the future we'll try to bias the selection mechanism
a61af66fc99e Initial load
duke
parents:
diff changeset
3890 // to preferentially pick a thread that recently ran on
a61af66fc99e Initial load
duke
parents:
diff changeset
3891 // a processor element that shares cache with the CPU on which
a61af66fc99e Initial load
duke
parents:
diff changeset
3892 // the exiting thread is running. We need access to Solaris'
a61af66fc99e Initial load
duke
parents:
diff changeset
3893 // schedctl.sc_cpu to make that work.
a61af66fc99e Initial load
duke
parents:
diff changeset
3894 //
a61af66fc99e Initial load
duke
parents:
diff changeset
3895 ObjectWaiter * w = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3896 int QMode = Knob_QMode ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3897
a61af66fc99e Initial load
duke
parents:
diff changeset
3898 if (QMode == 2 && _cxq != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3899 // QMode == 2 : cxq has precedence over EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3900 // Try to directly wake a successor from the cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3901 // If successful, the successor will need to unlink itself from cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3902 w = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3903 assert (w != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3904 assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3905 ExitEpilog (Self, w) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3906 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3907 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3908
a61af66fc99e Initial load
duke
parents:
diff changeset
3909 if (QMode == 3 && _cxq != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3910 // Aggressively drain cxq into EntryList at the first opportunity.
a61af66fc99e Initial load
duke
parents:
diff changeset
3911 // This policy ensure that recently-run threads live at the head of EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3912 // Drain _cxq into EntryList - bulk transfer.
a61af66fc99e Initial load
duke
parents:
diff changeset
3913 // First, detach _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3914 // The following loop is tantamount to: w = swap (&cxq, NULL)
a61af66fc99e Initial load
duke
parents:
diff changeset
3915 w = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3916 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3917 assert (w != NULL, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3918 ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3919 if (u == w) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3920 w = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3921 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3922 assert (w != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3923
a61af66fc99e Initial load
duke
parents:
diff changeset
3924 ObjectWaiter * q = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3925 ObjectWaiter * p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3926 for (p = w ; p != NULL ; p = p->_next) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3927 guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3928 p->TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3929 p->_prev = q ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3930 q = p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3931 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3932
a61af66fc99e Initial load
duke
parents:
diff changeset
3933 // Append the RATs to the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3934 // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
3935 ObjectWaiter * Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3936 for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3937 if (Tail == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3938 _EntryList = w ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3939 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
3940 Tail->_next = w ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3941 w->_prev = Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3942 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3943
a61af66fc99e Initial load
duke
parents:
diff changeset
3944 // Fall thru into code that tries to wake a successor from EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3945 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3946
a61af66fc99e Initial load
duke
parents:
diff changeset
3947 if (QMode == 4 && _cxq != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3948 // Aggressively drain cxq into EntryList at the first opportunity.
a61af66fc99e Initial load
duke
parents:
diff changeset
3949 // This policy ensure that recently-run threads live at the head of EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3950
a61af66fc99e Initial load
duke
parents:
diff changeset
3951 // Drain _cxq into EntryList - bulk transfer.
a61af66fc99e Initial load
duke
parents:
diff changeset
3952 // First, detach _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
3953 // The following loop is tantamount to: w = swap (&cxq, NULL)
a61af66fc99e Initial load
duke
parents:
diff changeset
3954 w = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3955 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3956 assert (w != NULL, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3957 ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3958 if (u == w) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3959 w = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3960 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3961 assert (w != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3962
a61af66fc99e Initial load
duke
parents:
diff changeset
3963 ObjectWaiter * q = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3964 ObjectWaiter * p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3965 for (p = w ; p != NULL ; p = p->_next) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3966 guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3967 p->TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3968 p->_prev = q ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3969 q = p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3970 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3971
a61af66fc99e Initial load
duke
parents:
diff changeset
3972 // Prepend the RATs to the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3973 if (_EntryList != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3974 q->_next = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3975 _EntryList->_prev = q ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3976 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3977 _EntryList = w ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3978
a61af66fc99e Initial load
duke
parents:
diff changeset
3979 // Fall thru into code that tries to wake a successor from EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
3980 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3981
a61af66fc99e Initial load
duke
parents:
diff changeset
3982 w = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3983 if (w != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
3984 // I'd like to write: guarantee (w->_thread != Self).
a61af66fc99e Initial load
duke
parents:
diff changeset
3985 // But in practice an exiting thread may find itself on the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3986 // Lets say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and
a61af66fc99e Initial load
duke
parents:
diff changeset
3987 // then calls exit(). Exit release the lock by setting O._owner to NULL.
a61af66fc99e Initial load
duke
parents:
diff changeset
3988 // Lets say T1 then stalls. T2 acquires O and calls O.notify(). The
a61af66fc99e Initial load
duke
parents:
diff changeset
3989 // notify() operation moves T1 from O's waitset to O's EntryList. T2 then
a61af66fc99e Initial load
duke
parents:
diff changeset
3990 // release the lock "O". T2 resumes immediately after the ST of null into
a61af66fc99e Initial load
duke
parents:
diff changeset
3991 // _owner, above. T2 notices that the EntryList is populated, so it
a61af66fc99e Initial load
duke
parents:
diff changeset
3992 // reacquires the lock and then finds itself on the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
3993 // Given all that, we have to tolerate the circumstance where "w" is
a61af66fc99e Initial load
duke
parents:
diff changeset
3994 // associated with Self.
a61af66fc99e Initial load
duke
parents:
diff changeset
3995 assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3996 ExitEpilog (Self, w) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3997 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
3998 }
a61af66fc99e Initial load
duke
parents:
diff changeset
3999
a61af66fc99e Initial load
duke
parents:
diff changeset
4000 // If we find that both _cxq and EntryList are null then just
a61af66fc99e Initial load
duke
parents:
diff changeset
4001 // re-run the exit protocol from the top.
a61af66fc99e Initial load
duke
parents:
diff changeset
4002 w = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4003 if (w == NULL) continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4004
a61af66fc99e Initial load
duke
parents:
diff changeset
4005 // Drain _cxq into EntryList - bulk transfer.
a61af66fc99e Initial load
duke
parents:
diff changeset
4006 // First, detach _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
4007 // The following loop is tantamount to: w = swap (&cxq, NULL)
a61af66fc99e Initial load
duke
parents:
diff changeset
4008 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4009 assert (w != NULL, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4010 ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4011 if (u == w) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4012 w = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4013 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4014 TEVENT (Inflated exit - drain cxq into EntryList) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4015
a61af66fc99e Initial load
duke
parents:
diff changeset
4016 assert (w != NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4017 assert (_EntryList == NULL , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4018
a61af66fc99e Initial load
duke
parents:
diff changeset
4019 // Convert the LIFO SLL anchored by _cxq into a DLL.
a61af66fc99e Initial load
duke
parents:
diff changeset
4020 // The list reorganization step operates in O(LENGTH(w)) time.
a61af66fc99e Initial load
duke
parents:
diff changeset
4021 // It's critical that this step operate quickly as
a61af66fc99e Initial load
duke
parents:
diff changeset
4022 // "Self" still holds the outer-lock, restricting parallelism
a61af66fc99e Initial load
duke
parents:
diff changeset
4023 // and effectively lengthening the critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
4024 // Invariant: s chases t chases u.
a61af66fc99e Initial load
duke
parents:
diff changeset
4025 // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
a61af66fc99e Initial load
duke
parents:
diff changeset
4026 // we have faster access to the tail.
a61af66fc99e Initial load
duke
parents:
diff changeset
4027
a61af66fc99e Initial load
duke
parents:
diff changeset
4028 if (QMode == 1) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4029 // QMode == 1 : drain cxq to EntryList, reversing order
a61af66fc99e Initial load
duke
parents:
diff changeset
4030 // We also reverse the order of the list.
a61af66fc99e Initial load
duke
parents:
diff changeset
4031 ObjectWaiter * s = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4032 ObjectWaiter * t = w ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4033 ObjectWaiter * u = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4034 while (t != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4035 guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4036 t->TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4037 u = t->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4038 t->_prev = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4039 t->_next = s ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4040 s = t;
a61af66fc99e Initial load
duke
parents:
diff changeset
4041 t = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4042 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4043 _EntryList = s ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4044 assert (s != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4045 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4046 // QMode == 0 or QMode == 2
a61af66fc99e Initial load
duke
parents:
diff changeset
4047 _EntryList = w ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4048 ObjectWaiter * q = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4049 ObjectWaiter * p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4050 for (p = w ; p != NULL ; p = p->_next) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4051 guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4052 p->TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4053 p->_prev = q ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4054 q = p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4055 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4056 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4057
a61af66fc99e Initial load
duke
parents:
diff changeset
4058 // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
a61af66fc99e Initial load
duke
parents:
diff changeset
4059 // The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
a61af66fc99e Initial load
duke
parents:
diff changeset
4060
a61af66fc99e Initial load
duke
parents:
diff changeset
4061 // See if we can abdicate to a spinner instead of waking a thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
4062 // A primary goal of the implementation is to reduce the
a61af66fc99e Initial load
duke
parents:
diff changeset
4063 // context-switch rate.
a61af66fc99e Initial load
duke
parents:
diff changeset
4064 if (_succ != NULL) continue;
a61af66fc99e Initial load
duke
parents:
diff changeset
4065
a61af66fc99e Initial load
duke
parents:
diff changeset
4066 w = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4067 if (w != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4068 guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4069 ExitEpilog (Self, w) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4070 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4071 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4072 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4073 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4074 // complete_exit exits a lock returning recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
4075 // complete_exit/reenter operate as a wait without waiting
a61af66fc99e Initial load
duke
parents:
diff changeset
4076 // complete_exit requires an inflated monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
4077 // The _owner field is not always the Thread addr even with an
a61af66fc99e Initial load
duke
parents:
diff changeset
4078 // inflated monitor, e.g. the monitor can be inflated by a non-owning
a61af66fc99e Initial load
duke
parents:
diff changeset
4079 // thread due to contention.
a61af66fc99e Initial load
duke
parents:
diff changeset
4080 intptr_t ObjectMonitor::complete_exit(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4081 Thread * const Self = THREAD;
a61af66fc99e Initial load
duke
parents:
diff changeset
4082 assert(Self->is_Java_thread(), "Must be Java thread!");
a61af66fc99e Initial load
duke
parents:
diff changeset
4083 JavaThread *jt = (JavaThread *)THREAD;
a61af66fc99e Initial load
duke
parents:
diff changeset
4084
a61af66fc99e Initial load
duke
parents:
diff changeset
4085 DeferredInitialize();
a61af66fc99e Initial load
duke
parents:
diff changeset
4086
a61af66fc99e Initial load
duke
parents:
diff changeset
4087 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4088 if (THREAD->is_lock_owned ((address)_owner)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4089 assert(_recursions == 0, "internal state error");
a61af66fc99e Initial load
duke
parents:
diff changeset
4090 _owner = THREAD ; /* Convert from basiclock addr to Thread addr */
a61af66fc99e Initial load
duke
parents:
diff changeset
4091 _recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4092 OwnerIsThread = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4093 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4094 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4095
a61af66fc99e Initial load
duke
parents:
diff changeset
4096 guarantee(Self == _owner, "complete_exit not owner");
a61af66fc99e Initial load
duke
parents:
diff changeset
4097 intptr_t save = _recursions; // record the old recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
4098 _recursions = 0; // set the recursion level to be 0
a61af66fc99e Initial load
duke
parents:
diff changeset
4099 exit (Self) ; // exit the monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
4100 guarantee (_owner != Self, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
4101 return save;
a61af66fc99e Initial load
duke
parents:
diff changeset
4102 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4103
a61af66fc99e Initial load
duke
parents:
diff changeset
4104 // reenter() enters a lock and sets recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
4105 // complete_exit/reenter operate as a wait without waiting
a61af66fc99e Initial load
duke
parents:
diff changeset
4106 void ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4107 Thread * const Self = THREAD;
a61af66fc99e Initial load
duke
parents:
diff changeset
4108 assert(Self->is_Java_thread(), "Must be Java thread!");
a61af66fc99e Initial load
duke
parents:
diff changeset
4109 JavaThread *jt = (JavaThread *)THREAD;
a61af66fc99e Initial load
duke
parents:
diff changeset
4110
a61af66fc99e Initial load
duke
parents:
diff changeset
4111 guarantee(_owner != Self, "reenter already owner");
a61af66fc99e Initial load
duke
parents:
diff changeset
4112 enter (THREAD); // enter the monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
4113 guarantee (_recursions == 0, "reenter recursion");
a61af66fc99e Initial load
duke
parents:
diff changeset
4114 _recursions = recursions;
a61af66fc99e Initial load
duke
parents:
diff changeset
4115 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
4116 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4117
a61af66fc99e Initial load
duke
parents:
diff changeset
4118 // Note: a subset of changes to ObjectMonitor::wait()
a61af66fc99e Initial load
duke
parents:
diff changeset
4119 // will need to be replicated in complete_exit above
a61af66fc99e Initial load
duke
parents:
diff changeset
4120 void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4121 Thread * const Self = THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4122 assert(Self->is_Java_thread(), "Must be Java thread!");
a61af66fc99e Initial load
duke
parents:
diff changeset
4123 JavaThread *jt = (JavaThread *)THREAD;
a61af66fc99e Initial load
duke
parents:
diff changeset
4124
a61af66fc99e Initial load
duke
parents:
diff changeset
4125 DeferredInitialize () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4126
a61af66fc99e Initial load
duke
parents:
diff changeset
4127 // Throw IMSX or IEX.
a61af66fc99e Initial load
duke
parents:
diff changeset
4128 CHECK_OWNER();
a61af66fc99e Initial load
duke
parents:
diff changeset
4129
a61af66fc99e Initial load
duke
parents:
diff changeset
4130 // check for a pending interrupt
a61af66fc99e Initial load
duke
parents:
diff changeset
4131 if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4132 // post monitor waited event. Note that this is past-tense, we are done waiting.
a61af66fc99e Initial load
duke
parents:
diff changeset
4133 if (JvmtiExport::should_post_monitor_waited()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4134 // Note: 'false' parameter is passed here because the
a61af66fc99e Initial load
duke
parents:
diff changeset
4135 // wait was not timed out due to thread interrupt.
a61af66fc99e Initial load
duke
parents:
diff changeset
4136 JvmtiExport::post_monitor_waited(jt, this, false);
a61af66fc99e Initial load
duke
parents:
diff changeset
4137 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4138 TEVENT (Wait - Throw IEX) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4139 THROW(vmSymbols::java_lang_InterruptedException());
a61af66fc99e Initial load
duke
parents:
diff changeset
4140 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4141 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4142 TEVENT (Wait) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4143
a61af66fc99e Initial load
duke
parents:
diff changeset
4144 assert (Self->_Stalled == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4145 Self->_Stalled = intptr_t(this) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4146 jt->set_current_waiting_monitor(this);
a61af66fc99e Initial load
duke
parents:
diff changeset
4147
a61af66fc99e Initial load
duke
parents:
diff changeset
4148 // create a node to be put into the queue
a61af66fc99e Initial load
duke
parents:
diff changeset
4149 // Critically, after we reset() the event but prior to park(), we must check
a61af66fc99e Initial load
duke
parents:
diff changeset
4150 // for a pending interrupt.
a61af66fc99e Initial load
duke
parents:
diff changeset
4151 ObjectWaiter node(Self);
a61af66fc99e Initial load
duke
parents:
diff changeset
4152 node.TState = ObjectWaiter::TS_WAIT ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4153 Self->_ParkEvent->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4154 OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
a61af66fc99e Initial load
duke
parents:
diff changeset
4155
a61af66fc99e Initial load
duke
parents:
diff changeset
4156 // Enter the waiting queue, which is a circular doubly linked list in this case
a61af66fc99e Initial load
duke
parents:
diff changeset
4157 // but it could be a priority queue or any data structure.
a61af66fc99e Initial load
duke
parents:
diff changeset
4158 // _WaitSetLock protects the wait queue. Normally the wait queue is accessed only
a61af66fc99e Initial load
duke
parents:
diff changeset
4159 // by the the owner of the monitor *except* in the case where park()
a61af66fc99e Initial load
duke
parents:
diff changeset
4160 // returns because of a timeout of interrupt. Contention is exceptionally rare
a61af66fc99e Initial load
duke
parents:
diff changeset
4161 // so we use a simple spin-lock instead of a heavier-weight blocking lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
4162
a61af66fc99e Initial load
duke
parents:
diff changeset
4163 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4164 AddWaiter (&node) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4165 Thread::SpinRelease (&_WaitSetLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4166
a61af66fc99e Initial load
duke
parents:
diff changeset
4167 if ((SyncFlags & 4) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4168 _Responsible = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4169 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4170 intptr_t save = _recursions; // record the old recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
4171 _waiters++; // increment the number of waiters
a61af66fc99e Initial load
duke
parents:
diff changeset
4172 _recursions = 0; // set the recursion level to be 1
a61af66fc99e Initial load
duke
parents:
diff changeset
4173 exit (Self) ; // exit the monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
4174 guarantee (_owner != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4175
a61af66fc99e Initial load
duke
parents:
diff changeset
4176 // As soon as the ObjectMonitor's ownership is dropped in the exit()
a61af66fc99e Initial load
duke
parents:
diff changeset
4177 // call above, another thread can enter() the ObjectMonitor, do the
a61af66fc99e Initial load
duke
parents:
diff changeset
4178 // notify(), and exit() the ObjectMonitor. If the other thread's
a61af66fc99e Initial load
duke
parents:
diff changeset
4179 // exit() call chooses this thread as the successor and the unpark()
a61af66fc99e Initial load
duke
parents:
diff changeset
4180 // call happens to occur while this thread is posting a
a61af66fc99e Initial load
duke
parents:
diff changeset
4181 // MONITOR_CONTENDED_EXIT event, then we run the risk of the event
a61af66fc99e Initial load
duke
parents:
diff changeset
4182 // handler using RawMonitors and consuming the unpark().
a61af66fc99e Initial load
duke
parents:
diff changeset
4183 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4184 // To avoid the problem, we re-post the event. This does no harm
a61af66fc99e Initial load
duke
parents:
diff changeset
4185 // even if the original unpark() was not consumed because we are the
a61af66fc99e Initial load
duke
parents:
diff changeset
4186 // chosen successor for this monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
4187 if (node._notified != 0 && _succ == Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4188 node._event->unpark();
a61af66fc99e Initial load
duke
parents:
diff changeset
4189 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4190
a61af66fc99e Initial load
duke
parents:
diff changeset
4191 // The thread is on the WaitSet list - now park() it.
a61af66fc99e Initial load
duke
parents:
diff changeset
4192 // On MP systems it's conceivable that a brief spin before we park
a61af66fc99e Initial load
duke
parents:
diff changeset
4193 // could be profitable.
a61af66fc99e Initial load
duke
parents:
diff changeset
4194 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4195 // TODO-FIXME: change the following logic to a loop of the form
a61af66fc99e Initial load
duke
parents:
diff changeset
4196 // while (!timeout && !interrupted && _notified == 0) park()
a61af66fc99e Initial load
duke
parents:
diff changeset
4197
a61af66fc99e Initial load
duke
parents:
diff changeset
4198 int ret = OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4199 int WasNotified = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4200 { // State transition wrappers
a61af66fc99e Initial load
duke
parents:
diff changeset
4201 OSThread* osthread = Self->osthread();
a61af66fc99e Initial load
duke
parents:
diff changeset
4202 OSThreadWaitState osts(osthread, true);
a61af66fc99e Initial load
duke
parents:
diff changeset
4203 {
a61af66fc99e Initial load
duke
parents:
diff changeset
4204 ThreadBlockInVM tbivm(jt);
a61af66fc99e Initial load
duke
parents:
diff changeset
4205 // Thread is in thread_blocked state and oop access is unsafe.
a61af66fc99e Initial load
duke
parents:
diff changeset
4206 jt->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
4207
a61af66fc99e Initial load
duke
parents:
diff changeset
4208 if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4209 // Intentionally empty
a61af66fc99e Initial load
duke
parents:
diff changeset
4210 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4211 if (node._notified == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4212 if (millis <= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4213 Self->_ParkEvent->park () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4214 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4215 ret = Self->_ParkEvent->park (millis) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4216 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4217 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4218
a61af66fc99e Initial load
duke
parents:
diff changeset
4219 // were we externally suspended while we were waiting?
a61af66fc99e Initial load
duke
parents:
diff changeset
4220 if (ExitSuspendEquivalent (jt)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4221 // TODO-FIXME: add -- if succ == Self then succ = null.
a61af66fc99e Initial load
duke
parents:
diff changeset
4222 jt->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
4223 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4224
a61af66fc99e Initial load
duke
parents:
diff changeset
4225 } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm
a61af66fc99e Initial load
duke
parents:
diff changeset
4226
a61af66fc99e Initial load
duke
parents:
diff changeset
4227
a61af66fc99e Initial load
duke
parents:
diff changeset
4228 // Node may be on the WaitSet, the EntryList (or cxq), or in transition
a61af66fc99e Initial load
duke
parents:
diff changeset
4229 // from the WaitSet to the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
4230 // See if we need to remove Node from the WaitSet.
a61af66fc99e Initial load
duke
parents:
diff changeset
4231 // We use double-checked locking to avoid grabbing _WaitSetLock
a61af66fc99e Initial load
duke
parents:
diff changeset
4232 // if the thread is not on the wait queue.
a61af66fc99e Initial load
duke
parents:
diff changeset
4233 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4234 // Note that we don't need a fence before the fetch of TState.
a61af66fc99e Initial load
duke
parents:
diff changeset
4235 // In the worst case we'll fetch a old-stale value of TS_WAIT previously
a61af66fc99e Initial load
duke
parents:
diff changeset
4236 // written by the is thread. (perhaps the fetch might even be satisfied
a61af66fc99e Initial load
duke
parents:
diff changeset
4237 // by a look-aside into the processor's own store buffer, although given
a61af66fc99e Initial load
duke
parents:
diff changeset
4238 // the length of the code path between the prior ST and this load that's
a61af66fc99e Initial load
duke
parents:
diff changeset
4239 // highly unlikely). If the following LD fetches a stale TS_WAIT value
a61af66fc99e Initial load
duke
parents:
diff changeset
4240 // then we'll acquire the lock and then re-fetch a fresh TState value.
a61af66fc99e Initial load
duke
parents:
diff changeset
4241 // That is, we fail toward safety.
a61af66fc99e Initial load
duke
parents:
diff changeset
4242
a61af66fc99e Initial load
duke
parents:
diff changeset
4243 if (node.TState == ObjectWaiter::TS_WAIT) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4244 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4245 if (node.TState == ObjectWaiter::TS_WAIT) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4246 DequeueSpecificWaiter (&node) ; // unlink from WaitSet
a61af66fc99e Initial load
duke
parents:
diff changeset
4247 assert(node._notified == 0, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
4248 node.TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4249 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4250 Thread::SpinRelease (&_WaitSetLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4251 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4252
a61af66fc99e Initial load
duke
parents:
diff changeset
4253 // The thread is now either on off-list (TS_RUN),
a61af66fc99e Initial load
duke
parents:
diff changeset
4254 // on the EntryList (TS_ENTER), or on the cxq (TS_CXQ).
a61af66fc99e Initial load
duke
parents:
diff changeset
4255 // The Node's TState variable is stable from the perspective of this thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
4256 // No other threads will asynchronously modify TState.
a61af66fc99e Initial load
duke
parents:
diff changeset
4257 guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4258 OrderAccess::loadload() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4259 if (_succ == Self) _succ = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4260 WasNotified = node._notified ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4261
a61af66fc99e Initial load
duke
parents:
diff changeset
4262 // Reentry phase -- reacquire the monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
4263 // re-enter contended monitor after object.wait().
a61af66fc99e Initial load
duke
parents:
diff changeset
4264 // retain OBJECT_WAIT state until re-enter successfully completes
a61af66fc99e Initial load
duke
parents:
diff changeset
4265 // Thread state is thread_in_vm and oop access is again safe,
a61af66fc99e Initial load
duke
parents:
diff changeset
4266 // although the raw address of the object may have changed.
a61af66fc99e Initial load
duke
parents:
diff changeset
4267 // (Don't cache naked oops over safepoints, of course).
a61af66fc99e Initial load
duke
parents:
diff changeset
4268
a61af66fc99e Initial load
duke
parents:
diff changeset
4269 // post monitor waited event. Note that this is past-tense, we are done waiting.
a61af66fc99e Initial load
duke
parents:
diff changeset
4270 if (JvmtiExport::should_post_monitor_waited()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4271 JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
a61af66fc99e Initial load
duke
parents:
diff changeset
4272 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4273 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4274
a61af66fc99e Initial load
duke
parents:
diff changeset
4275 assert (Self->_Stalled != 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4276 Self->_Stalled = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4277
a61af66fc99e Initial load
duke
parents:
diff changeset
4278 assert (_owner != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4279 ObjectWaiter::TStates v = node.TState ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4280 if (v == ObjectWaiter::TS_RUN) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4281 enter (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4282 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4283 guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4284 ReenterI (Self, &node) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4285 node.wait_reenter_end(this);
a61af66fc99e Initial load
duke
parents:
diff changeset
4286 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4287
a61af66fc99e Initial load
duke
parents:
diff changeset
4288 // Self has reacquired the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
4289 // Lifecycle - the node representing Self must not appear on any queues.
a61af66fc99e Initial load
duke
parents:
diff changeset
4290 // Node is about to go out-of-scope, but even if it were immortal we wouldn't
a61af66fc99e Initial load
duke
parents:
diff changeset
4291 // want residual elements associated with this thread left on any lists.
a61af66fc99e Initial load
duke
parents:
diff changeset
4292 guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4293 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4294 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4295 } // OSThreadWaitState()
a61af66fc99e Initial load
duke
parents:
diff changeset
4296
a61af66fc99e Initial load
duke
parents:
diff changeset
4297 jt->set_current_waiting_monitor(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
4298
a61af66fc99e Initial load
duke
parents:
diff changeset
4299 guarantee (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4300 _recursions = save; // restore the old recursion count
a61af66fc99e Initial load
duke
parents:
diff changeset
4301 _waiters--; // decrement the number of waiters
a61af66fc99e Initial load
duke
parents:
diff changeset
4302
a61af66fc99e Initial load
duke
parents:
diff changeset
4303 // Verify a few postconditions
a61af66fc99e Initial load
duke
parents:
diff changeset
4304 assert (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4305 assert (_succ != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4306 assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4307
a61af66fc99e Initial load
duke
parents:
diff changeset
4308 if (SyncFlags & 32) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4309 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4310 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4311
a61af66fc99e Initial load
duke
parents:
diff changeset
4312 // check if the notification happened
a61af66fc99e Initial load
duke
parents:
diff changeset
4313 if (!WasNotified) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4314 // no, it could be timeout or Thread.interrupt() or both
a61af66fc99e Initial load
duke
parents:
diff changeset
4315 // check for interrupt event, otherwise it is timeout
a61af66fc99e Initial load
duke
parents:
diff changeset
4316 if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4317 TEVENT (Wait - throw IEX from epilog) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4318 THROW(vmSymbols::java_lang_InterruptedException());
a61af66fc99e Initial load
duke
parents:
diff changeset
4319 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4320 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4321
a61af66fc99e Initial load
duke
parents:
diff changeset
4322 // NOTE: Spurious wake up will be consider as timeout.
a61af66fc99e Initial load
duke
parents:
diff changeset
4323 // Monitor notify has precedence over thread interrupt.
a61af66fc99e Initial load
duke
parents:
diff changeset
4324 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4325
a61af66fc99e Initial load
duke
parents:
diff changeset
4326
a61af66fc99e Initial load
duke
parents:
diff changeset
4327 // Consider:
a61af66fc99e Initial load
duke
parents:
diff changeset
4328 // If the lock is cool (cxq == null && succ == null) and we're on an MP system
a61af66fc99e Initial load
duke
parents:
diff changeset
4329 // then instead of transferring a thread from the WaitSet to the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
4330 // we might just dequeue a thread from the WaitSet and directly unpark() it.
a61af66fc99e Initial load
duke
parents:
diff changeset
4331
a61af66fc99e Initial load
duke
parents:
diff changeset
4332 void ObjectMonitor::notify(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4333 CHECK_OWNER();
a61af66fc99e Initial load
duke
parents:
diff changeset
4334 if (_WaitSet == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4335 TEVENT (Empty-Notify) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4336 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4337 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4338 DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
4339
a61af66fc99e Initial load
duke
parents:
diff changeset
4340 int Policy = Knob_MoveNotifyee ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4341
a61af66fc99e Initial load
duke
parents:
diff changeset
4342 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4343 ObjectWaiter * iterator = DequeueWaiter() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4344 if (iterator != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4345 TEVENT (Notify1 - Transfer) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4346 guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4347 guarantee (iterator->_notified == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4348 // Disposition - what might we do with iterator ?
a61af66fc99e Initial load
duke
parents:
diff changeset
4349 // a. add it directly to the EntryList - either tail or head.
a61af66fc99e Initial load
duke
parents:
diff changeset
4350 // b. push it onto the front of the _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
4351 // For now we use (a).
a61af66fc99e Initial load
duke
parents:
diff changeset
4352 if (Policy != 4) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4353 iterator->TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4354 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4355 iterator->_notified = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4356
a61af66fc99e Initial load
duke
parents:
diff changeset
4357 ObjectWaiter * List = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4358 if (List != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4359 assert (List->_prev == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4360 assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4361 assert (List != iterator, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4362 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4363
a61af66fc99e Initial load
duke
parents:
diff changeset
4364 if (Policy == 0) { // prepend to EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
4365 if (List == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4366 iterator->_next = iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4367 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4368 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4369 List->_prev = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4370 iterator->_next = List ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4371 iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4372 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4373 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4374 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4375 if (Policy == 1) { // append to EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
4376 if (List == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4377 iterator->_next = iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4378 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4379 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4380 // CONSIDER: finding the tail currently requires a linear-time walk of
a61af66fc99e Initial load
duke
parents:
diff changeset
4381 // the EntryList. We can make tail access constant-time by converting to
a61af66fc99e Initial load
duke
parents:
diff changeset
4382 // a CDLL instead of using our current DLL.
a61af66fc99e Initial load
duke
parents:
diff changeset
4383 ObjectWaiter * Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4384 for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4385 assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4386 Tail->_next = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4387 iterator->_prev = Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4388 iterator->_next = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4389 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4390 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4391 if (Policy == 2) { // prepend to cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
4392 // prepend to cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
4393 if (List == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4394 iterator->_next = iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4395 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4396 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4397 iterator->TState = ObjectWaiter::TS_CXQ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4398 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4399 ObjectWaiter * Front = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4400 iterator->_next = Front ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4401 if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4402 break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4403 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4404 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4405 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4406 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4407 if (Policy == 3) { // append to cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
4408 iterator->TState = ObjectWaiter::TS_CXQ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4409 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4410 ObjectWaiter * Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4411 Tail = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4412 if (Tail == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4413 iterator->_next = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4414 if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4415 break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4416 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4417 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4418 while (Tail->_next != NULL) Tail = Tail->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4419 Tail->_next = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4420 iterator->_prev = Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4421 iterator->_next = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4422 break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4423 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4424 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4425 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4426 ParkEvent * ev = iterator->_event ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4427 iterator->TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4428 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4429 ev->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4430 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4431
a61af66fc99e Initial load
duke
parents:
diff changeset
4432 if (Policy < 4) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4433 iterator->wait_reenter_begin(this);
a61af66fc99e Initial load
duke
parents:
diff changeset
4434 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4435
a61af66fc99e Initial load
duke
parents:
diff changeset
4436 // _WaitSetLock protects the wait queue, not the EntryList. We could
a61af66fc99e Initial load
duke
parents:
diff changeset
4437 // move the add-to-EntryList operation, above, outside the critical section
a61af66fc99e Initial load
duke
parents:
diff changeset
4438 // protected by _WaitSetLock. In practice that's not useful. With the
a61af66fc99e Initial load
duke
parents:
diff changeset
4439 // exception of wait() timeouts and interrupts the monitor owner
a61af66fc99e Initial load
duke
parents:
diff changeset
4440 // is the only thread that grabs _WaitSetLock. There's almost no contention
a61af66fc99e Initial load
duke
parents:
diff changeset
4441 // on _WaitSetLock so it's not profitable to reduce the length of the
a61af66fc99e Initial load
duke
parents:
diff changeset
4442 // critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
4443 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4444
a61af66fc99e Initial load
duke
parents:
diff changeset
4445 Thread::SpinRelease (&_WaitSetLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4446
a61af66fc99e Initial load
duke
parents:
diff changeset
4447 if (iterator != NULL && ObjectSynchronizer::_sync_Notifications != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4448 ObjectSynchronizer::_sync_Notifications->inc() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4449 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4450 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4451
a61af66fc99e Initial load
duke
parents:
diff changeset
4452
a61af66fc99e Initial load
duke
parents:
diff changeset
4453 void ObjectMonitor::notifyAll(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4454 CHECK_OWNER();
a61af66fc99e Initial load
duke
parents:
diff changeset
4455 ObjectWaiter* iterator;
a61af66fc99e Initial load
duke
parents:
diff changeset
4456 if (_WaitSet == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4457 TEVENT (Empty-NotifyAll) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4458 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4459 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4460 DTRACE_MONITOR_PROBE(notifyAll, this, object(), THREAD);
a61af66fc99e Initial load
duke
parents:
diff changeset
4461
a61af66fc99e Initial load
duke
parents:
diff changeset
4462 int Policy = Knob_MoveNotifyee ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4463 int Tally = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4464 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notifyall") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4465
a61af66fc99e Initial load
duke
parents:
diff changeset
4466 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4467 iterator = DequeueWaiter () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4468 if (iterator == NULL) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4469 TEVENT (NotifyAll - Transfer1) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4470 ++Tally ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4471
a61af66fc99e Initial load
duke
parents:
diff changeset
4472 // Disposition - what might we do with iterator ?
a61af66fc99e Initial load
duke
parents:
diff changeset
4473 // a. add it directly to the EntryList - either tail or head.
a61af66fc99e Initial load
duke
parents:
diff changeset
4474 // b. push it onto the front of the _cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
4475 // For now we use (a).
a61af66fc99e Initial load
duke
parents:
diff changeset
4476 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4477 // TODO-FIXME: currently notifyAll() transfers the waiters one-at-a-time from the waitset
a61af66fc99e Initial load
duke
parents:
diff changeset
4478 // to the EntryList. This could be done more efficiently with a single bulk transfer,
a61af66fc99e Initial load
duke
parents:
diff changeset
4479 // but in practice it's not time-critical. Beware too, that in prepend-mode we invert the
a61af66fc99e Initial load
duke
parents:
diff changeset
4480 // order of the waiters. Lets say that the waitset is "ABCD" and the EntryList is "XYZ".
a61af66fc99e Initial load
duke
parents:
diff changeset
4481 // After a notifyAll() in prepend mode the waitset will be empty and the EntryList will
a61af66fc99e Initial load
duke
parents:
diff changeset
4482 // be "DCBAXYZ".
a61af66fc99e Initial load
duke
parents:
diff changeset
4483
a61af66fc99e Initial load
duke
parents:
diff changeset
4484 guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4485 guarantee (iterator->_notified == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4486 iterator->_notified = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4487 if (Policy != 4) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4488 iterator->TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4489 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4490
a61af66fc99e Initial load
duke
parents:
diff changeset
4491 ObjectWaiter * List = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4492 if (List != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4493 assert (List->_prev == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4494 assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4495 assert (List != iterator, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4496 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4497
a61af66fc99e Initial load
duke
parents:
diff changeset
4498 if (Policy == 0) { // prepend to EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
4499 if (List == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4500 iterator->_next = iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4501 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4502 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4503 List->_prev = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4504 iterator->_next = List ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4505 iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4506 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4507 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4508 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4509 if (Policy == 1) { // append to EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
4510 if (List == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4511 iterator->_next = iterator->_prev = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4512 _EntryList = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4513 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4514 // CONSIDER: finding the tail currently requires a linear-time walk of
a61af66fc99e Initial load
duke
parents:
diff changeset
4515 // the EntryList. We can make tail access constant-time by converting to
a61af66fc99e Initial load
duke
parents:
diff changeset
4516 // a CDLL instead of using our current DLL.
a61af66fc99e Initial load
duke
parents:
diff changeset
4517 ObjectWaiter * Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4518 for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4519 assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4520 Tail->_next = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4521 iterator->_prev = Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4522 iterator->_next = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4523 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4524 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4525 if (Policy == 2) { // prepend to cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
4526 // prepend to cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
4527 iterator->TState = ObjectWaiter::TS_CXQ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4528 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4529 ObjectWaiter * Front = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4530 iterator->_next = Front ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4531 if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4532 break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4533 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4534 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4535 } else
a61af66fc99e Initial load
duke
parents:
diff changeset
4536 if (Policy == 3) { // append to cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
4537 iterator->TState = ObjectWaiter::TS_CXQ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4538 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4539 ObjectWaiter * Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4540 Tail = _cxq ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4541 if (Tail == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4542 iterator->_next = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4543 if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4544 break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4545 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4546 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4547 while (Tail->_next != NULL) Tail = Tail->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4548 Tail->_next = iterator ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4549 iterator->_prev = Tail ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4550 iterator->_next = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4551 break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4552 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4553 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4554 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4555 ParkEvent * ev = iterator->_event ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4556 iterator->TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4557 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4558 ev->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4559 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4560
a61af66fc99e Initial load
duke
parents:
diff changeset
4561 if (Policy < 4) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4562 iterator->wait_reenter_begin(this);
a61af66fc99e Initial load
duke
parents:
diff changeset
4563 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4564
a61af66fc99e Initial load
duke
parents:
diff changeset
4565 // _WaitSetLock protects the wait queue, not the EntryList. We could
a61af66fc99e Initial load
duke
parents:
diff changeset
4566 // move the add-to-EntryList operation, above, outside the critical section
a61af66fc99e Initial load
duke
parents:
diff changeset
4567 // protected by _WaitSetLock. In practice that's not useful. With the
a61af66fc99e Initial load
duke
parents:
diff changeset
4568 // exception of wait() timeouts and interrupts the monitor owner
a61af66fc99e Initial load
duke
parents:
diff changeset
4569 // is the only thread that grabs _WaitSetLock. There's almost no contention
a61af66fc99e Initial load
duke
parents:
diff changeset
4570 // on _WaitSetLock so it's not profitable to reduce the length of the
a61af66fc99e Initial load
duke
parents:
diff changeset
4571 // critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
4572 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4573
a61af66fc99e Initial load
duke
parents:
diff changeset
4574 Thread::SpinRelease (&_WaitSetLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4575
a61af66fc99e Initial load
duke
parents:
diff changeset
4576 if (Tally != 0 && ObjectSynchronizer::_sync_Notifications != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4577 ObjectSynchronizer::_sync_Notifications->inc(Tally) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4578 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4579 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4580
a61af66fc99e Initial load
duke
parents:
diff changeset
4581 // check_slow() is a misnomer. It's called to simply to throw an IMSX exception.
a61af66fc99e Initial load
duke
parents:
diff changeset
4582 // TODO-FIXME: remove check_slow() -- it's likely dead.
a61af66fc99e Initial load
duke
parents:
diff changeset
4583
a61af66fc99e Initial load
duke
parents:
diff changeset
4584 void ObjectMonitor::check_slow(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4585 TEVENT (check_slow - throw IMSX) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4586 assert(THREAD != _owner && !THREAD->is_lock_owned((address) _owner), "must not be owner");
a61af66fc99e Initial load
duke
parents:
diff changeset
4587 THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread not owner");
a61af66fc99e Initial load
duke
parents:
diff changeset
4588 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4589
a61af66fc99e Initial load
duke
parents:
diff changeset
4590
a61af66fc99e Initial load
duke
parents:
diff changeset
4591 // -------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
4592 // The raw monitor subsystem is entirely distinct from normal
a61af66fc99e Initial load
duke
parents:
diff changeset
4593 // java-synchronization or jni-synchronization. raw monitors are not
a61af66fc99e Initial load
duke
parents:
diff changeset
4594 // associated with objects. They can be implemented in any manner
a61af66fc99e Initial load
duke
parents:
diff changeset
4595 // that makes sense. The original implementors decided to piggy-back
a61af66fc99e Initial load
duke
parents:
diff changeset
4596 // the raw-monitor implementation on the existing Java objectMonitor mechanism.
a61af66fc99e Initial load
duke
parents:
diff changeset
4597 // This flaw needs to fixed. We should reimplement raw monitors as sui-generis.
a61af66fc99e Initial load
duke
parents:
diff changeset
4598 // Specifically, we should not implement raw monitors via java monitors.
a61af66fc99e Initial load
duke
parents:
diff changeset
4599 // Time permitting, we should disentangle and deconvolve the two implementations
a61af66fc99e Initial load
duke
parents:
diff changeset
4600 // and move the resulting raw monitor implementation over to the JVMTI directories.
a61af66fc99e Initial load
duke
parents:
diff changeset
4601 // Ideally, the raw monitor implementation would be built on top of
a61af66fc99e Initial load
duke
parents:
diff changeset
4602 // park-unpark and nothing else.
a61af66fc99e Initial load
duke
parents:
diff changeset
4603 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4604 // raw monitors are used mainly by JVMTI
a61af66fc99e Initial load
duke
parents:
diff changeset
4605 // The raw monitor implementation borrows the ObjectMonitor structure,
a61af66fc99e Initial load
duke
parents:
diff changeset
4606 // but the operators are degenerate and extremely simple.
a61af66fc99e Initial load
duke
parents:
diff changeset
4607 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4608 // Mixed use of a single objectMonitor instance -- as both a raw monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
4609 // and a normal java monitor -- is not permissible.
a61af66fc99e Initial load
duke
parents:
diff changeset
4610 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4611 // Note that we use the single RawMonitor_lock to protect queue operations for
a61af66fc99e Initial load
duke
parents:
diff changeset
4612 // _all_ raw monitors. This is a scalability impediment, but since raw monitor usage
a61af66fc99e Initial load
duke
parents:
diff changeset
4613 // is deprecated and rare, this is not of concern. The RawMonitor_lock can not
a61af66fc99e Initial load
duke
parents:
diff changeset
4614 // be held indefinitely. The critical sections must be short and bounded.
a61af66fc99e Initial load
duke
parents:
diff changeset
4615 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4616 // -------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
4617
a61af66fc99e Initial load
duke
parents:
diff changeset
4618 int ObjectMonitor::SimpleEnter (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4619 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4620 if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4621 return OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4622 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4623
a61af66fc99e Initial load
duke
parents:
diff changeset
4624 ObjectWaiter Node (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4625 Self->_ParkEvent->reset() ; // strictly optional
a61af66fc99e Initial load
duke
parents:
diff changeset
4626 Node.TState = ObjectWaiter::TS_ENTER ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4627
a61af66fc99e Initial load
duke
parents:
diff changeset
4628 RawMonitor_lock->lock_without_safepoint_check() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4629 Node._next = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4630 _EntryList = &Node ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4631 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4632 if (_owner == NULL && Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4633 _EntryList = Node._next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4634 RawMonitor_lock->unlock() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4635 return OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4636 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4637 RawMonitor_lock->unlock() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4638 while (Node.TState == ObjectWaiter::TS_ENTER) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4639 Self->_ParkEvent->park() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4640 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4641 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4642 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4643
a61af66fc99e Initial load
duke
parents:
diff changeset
4644 int ObjectMonitor::SimpleExit (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4645 guarantee (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4646 OrderAccess::release_store_ptr (&_owner, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4647 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4648 if (_EntryList == NULL) return OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4649 ObjectWaiter * w ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4650
a61af66fc99e Initial load
duke
parents:
diff changeset
4651 RawMonitor_lock->lock_without_safepoint_check() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4652 w = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4653 if (w != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4654 _EntryList = w->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4655 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4656 RawMonitor_lock->unlock() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4657 if (w != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4658 guarantee (w ->TState == ObjectWaiter::TS_ENTER, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4659 ParkEvent * ev = w->_event ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4660 w->TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4661 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4662 ev->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4663 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4664 return OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4665 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4666
a61af66fc99e Initial load
duke
parents:
diff changeset
4667 int ObjectMonitor::SimpleWait (Thread * Self, jlong millis) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4668 guarantee (_owner == Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4669 guarantee (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4670
a61af66fc99e Initial load
duke
parents:
diff changeset
4671 ObjectWaiter Node (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4672 Node._notified = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4673 Node.TState = ObjectWaiter::TS_WAIT ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4674
a61af66fc99e Initial load
duke
parents:
diff changeset
4675 RawMonitor_lock->lock_without_safepoint_check() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4676 Node._next = _WaitSet ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4677 _WaitSet = &Node ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4678 RawMonitor_lock->unlock() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4679
a61af66fc99e Initial load
duke
parents:
diff changeset
4680 SimpleExit (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4681 guarantee (_owner != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4682
a61af66fc99e Initial load
duke
parents:
diff changeset
4683 int ret = OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4684 if (millis <= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4685 Self->_ParkEvent->park();
a61af66fc99e Initial load
duke
parents:
diff changeset
4686 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4687 ret = Self->_ParkEvent->park(millis);
a61af66fc99e Initial load
duke
parents:
diff changeset
4688 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4689
a61af66fc99e Initial load
duke
parents:
diff changeset
4690 // If thread still resides on the waitset then unlink it.
a61af66fc99e Initial load
duke
parents:
diff changeset
4691 // Double-checked locking -- the usage is safe in this context
a61af66fc99e Initial load
duke
parents:
diff changeset
4692 // as we TState is volatile and the lock-unlock operators are
a61af66fc99e Initial load
duke
parents:
diff changeset
4693 // serializing (barrier-equivalent).
a61af66fc99e Initial load
duke
parents:
diff changeset
4694
a61af66fc99e Initial load
duke
parents:
diff changeset
4695 if (Node.TState == ObjectWaiter::TS_WAIT) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4696 RawMonitor_lock->lock_without_safepoint_check() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4697 if (Node.TState == ObjectWaiter::TS_WAIT) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4698 // Simple O(n) unlink, but performance isn't critical here.
a61af66fc99e Initial load
duke
parents:
diff changeset
4699 ObjectWaiter * p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4700 ObjectWaiter * q = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4701 for (p = _WaitSet ; p != &Node; p = p->_next) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4702 q = p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4703 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4704 guarantee (p == &Node, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4705 if (q == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4706 guarantee (p == _WaitSet, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4707 _WaitSet = p->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4708 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4709 guarantee (p == q->_next, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4710 q->_next = p->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4711 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4712 Node.TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4713 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4714 RawMonitor_lock->unlock() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4715 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4716
a61af66fc99e Initial load
duke
parents:
diff changeset
4717 guarantee (Node.TState == ObjectWaiter::TS_RUN, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4718 SimpleEnter (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4719
a61af66fc99e Initial load
duke
parents:
diff changeset
4720 guarantee (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4721 guarantee (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4722 return ret ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4723 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4724
a61af66fc99e Initial load
duke
parents:
diff changeset
4725 int ObjectMonitor::SimpleNotify (Thread * Self, bool All) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4726 guarantee (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4727 if (_WaitSet == NULL) return OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4728
a61af66fc99e Initial load
duke
parents:
diff changeset
4729 // We have two options:
a61af66fc99e Initial load
duke
parents:
diff changeset
4730 // A. Transfer the threads from the WaitSet to the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
4731 // B. Remove the thread from the WaitSet and unpark() it.
a61af66fc99e Initial load
duke
parents:
diff changeset
4732 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4733 // We use (B), which is crude and results in lots of futile
a61af66fc99e Initial load
duke
parents:
diff changeset
4734 // context switching. In particular (B) induces lots of contention.
a61af66fc99e Initial load
duke
parents:
diff changeset
4735
a61af66fc99e Initial load
duke
parents:
diff changeset
4736 ParkEvent * ev = NULL ; // consider using a small auto array ...
a61af66fc99e Initial load
duke
parents:
diff changeset
4737 RawMonitor_lock->lock_without_safepoint_check() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4738 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4739 ObjectWaiter * w = _WaitSet ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4740 if (w == NULL) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4741 _WaitSet = w->_next ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4742 if (ev != NULL) { ev->unpark(); ev = NULL; }
a61af66fc99e Initial load
duke
parents:
diff changeset
4743 ev = w->_event ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4744 OrderAccess::loadstore() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4745 w->TState = ObjectWaiter::TS_RUN ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4746 OrderAccess::storeload();
a61af66fc99e Initial load
duke
parents:
diff changeset
4747 if (!All) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4748 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4749 RawMonitor_lock->unlock() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4750 if (ev != NULL) ev->unpark();
a61af66fc99e Initial load
duke
parents:
diff changeset
4751 return OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4752 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4753
a61af66fc99e Initial load
duke
parents:
diff changeset
4754 // Any JavaThread will enter here with state _thread_blocked
a61af66fc99e Initial load
duke
parents:
diff changeset
4755 int ObjectMonitor::raw_enter(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4756 TEVENT (raw_enter) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4757 void * Contended ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4758
a61af66fc99e Initial load
duke
parents:
diff changeset
4759 // don't enter raw monitor if thread is being externally suspended, it will
a61af66fc99e Initial load
duke
parents:
diff changeset
4760 // surprise the suspender if a "suspended" thread can still enter monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
4761 JavaThread * jt = (JavaThread *)THREAD;
a61af66fc99e Initial load
duke
parents:
diff changeset
4762 if (THREAD->is_Java_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4763 jt->SR_lock()->lock_without_safepoint_check();
a61af66fc99e Initial load
duke
parents:
diff changeset
4764 while (jt->is_external_suspend()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4765 jt->SR_lock()->unlock();
a61af66fc99e Initial load
duke
parents:
diff changeset
4766 jt->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
4767 jt->SR_lock()->lock_without_safepoint_check();
a61af66fc99e Initial load
duke
parents:
diff changeset
4768 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4769 // guarded by SR_lock to avoid racing with new external suspend requests.
a61af66fc99e Initial load
duke
parents:
diff changeset
4770 Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4771 jt->SR_lock()->unlock();
a61af66fc99e Initial load
duke
parents:
diff changeset
4772 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4773 Contended = Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4774 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4775
a61af66fc99e Initial load
duke
parents:
diff changeset
4776 if (Contended == THREAD) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4777 _recursions ++ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4778 return OM_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4779 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4780
a61af66fc99e Initial load
duke
parents:
diff changeset
4781 if (Contended == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4782 guarantee (_owner == THREAD, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4783 guarantee (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4784 return OM_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4785 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4786
a61af66fc99e Initial load
duke
parents:
diff changeset
4787 THREAD->set_current_pending_monitor(this);
a61af66fc99e Initial load
duke
parents:
diff changeset
4788
a61af66fc99e Initial load
duke
parents:
diff changeset
4789 if (!THREAD->is_Java_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4790 // No other non-Java threads besides VM thread would acquire
a61af66fc99e Initial load
duke
parents:
diff changeset
4791 // a raw monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
4792 assert(THREAD->is_VM_thread(), "must be VM thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
4793 SimpleEnter (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4794 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
4795 guarantee (jt->thread_state() == _thread_blocked, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4796 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4797 jt->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
4798 // cleared by handle_special_suspend_equivalent_condition() or
a61af66fc99e Initial load
duke
parents:
diff changeset
4799 // java_suspend_self()
a61af66fc99e Initial load
duke
parents:
diff changeset
4800 SimpleEnter (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4801
a61af66fc99e Initial load
duke
parents:
diff changeset
4802 // were we externally suspended while we were waiting?
a61af66fc99e Initial load
duke
parents:
diff changeset
4803 if (!jt->handle_special_suspend_equivalent_condition()) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4804
a61af66fc99e Initial load
duke
parents:
diff changeset
4805 // This thread was externally suspended
a61af66fc99e Initial load
duke
parents:
diff changeset
4806 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4807 // This logic isn't needed for JVMTI raw monitors,
a61af66fc99e Initial load
duke
parents:
diff changeset
4808 // but doesn't hurt just in case the suspend rules change. This
a61af66fc99e Initial load
duke
parents:
diff changeset
4809 // logic is needed for the ObjectMonitor.wait() reentry phase.
a61af66fc99e Initial load
duke
parents:
diff changeset
4810 // We have reentered the contended monitor, but while we were
a61af66fc99e Initial load
duke
parents:
diff changeset
4811 // waiting another thread suspended us. We don't want to reenter
a61af66fc99e Initial load
duke
parents:
diff changeset
4812 // the monitor while suspended because that would surprise the
a61af66fc99e Initial load
duke
parents:
diff changeset
4813 // thread that suspended us.
a61af66fc99e Initial load
duke
parents:
diff changeset
4814 //
a61af66fc99e Initial load
duke
parents:
diff changeset
4815 // Drop the lock -
a61af66fc99e Initial load
duke
parents:
diff changeset
4816 SimpleExit (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4817
a61af66fc99e Initial load
duke
parents:
diff changeset
4818 jt->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
4819 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4820
a61af66fc99e Initial load
duke
parents:
diff changeset
4821 assert(_owner == THREAD, "Fatal error with monitor owner!");
a61af66fc99e Initial load
duke
parents:
diff changeset
4822 assert(_recursions == 0, "Fatal error with monitor recursions!");
a61af66fc99e Initial load
duke
parents:
diff changeset
4823 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4824
a61af66fc99e Initial load
duke
parents:
diff changeset
4825 THREAD->set_current_pending_monitor(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
4826 guarantee (_recursions == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4827 return OM_OK;
a61af66fc99e Initial load
duke
parents:
diff changeset
4828 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4829
a61af66fc99e Initial load
duke
parents:
diff changeset
4830 // Used mainly for JVMTI raw monitor implementation
a61af66fc99e Initial load
duke
parents:
diff changeset
4831 // Also used for ObjectMonitor::wait().
a61af66fc99e Initial load
duke
parents:
diff changeset
4832 int ObjectMonitor::raw_exit(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4833 TEVENT (raw_exit) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4834 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4835 return OM_ILLEGAL_MONITOR_STATE;
a61af66fc99e Initial load
duke
parents:
diff changeset
4836 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4837 if (_recursions > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4838 --_recursions ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4839 return OM_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4840 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4841
a61af66fc99e Initial load
duke
parents:
diff changeset
4842 void * List = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4843 SimpleExit (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4844
a61af66fc99e Initial load
duke
parents:
diff changeset
4845 return OM_OK;
a61af66fc99e Initial load
duke
parents:
diff changeset
4846 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4847
a61af66fc99e Initial load
duke
parents:
diff changeset
4848 // Used for JVMTI raw monitor implementation.
a61af66fc99e Initial load
duke
parents:
diff changeset
4849 // All JavaThreads will enter here with state _thread_blocked
a61af66fc99e Initial load
duke
parents:
diff changeset
4850
a61af66fc99e Initial load
duke
parents:
diff changeset
4851 int ObjectMonitor::raw_wait(jlong millis, bool interruptible, TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4852 TEVENT (raw_wait) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4853 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4854 return OM_ILLEGAL_MONITOR_STATE;
a61af66fc99e Initial load
duke
parents:
diff changeset
4855 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4856
a61af66fc99e Initial load
duke
parents:
diff changeset
4857 // To avoid spurious wakeups we reset the parkevent -- This is strictly optional.
a61af66fc99e Initial load
duke
parents:
diff changeset
4858 // The caller must be able to tolerate spurious returns from raw_wait().
a61af66fc99e Initial load
duke
parents:
diff changeset
4859 THREAD->_ParkEvent->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4860 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4861
a61af66fc99e Initial load
duke
parents:
diff changeset
4862 // check interrupt event
a61af66fc99e Initial load
duke
parents:
diff changeset
4863 if (interruptible && Thread::is_interrupted(THREAD, true)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4864 return OM_INTERRUPTED;
a61af66fc99e Initial load
duke
parents:
diff changeset
4865 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4866
a61af66fc99e Initial load
duke
parents:
diff changeset
4867 intptr_t save = _recursions ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4868 _recursions = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4869 _waiters ++ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4870 if (THREAD->is_Java_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4871 guarantee (((JavaThread *) THREAD)->thread_state() == _thread_blocked, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4872 ((JavaThread *)THREAD)->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
4873 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4874 int rv = SimpleWait (THREAD, millis) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4875 _recursions = save ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4876 _waiters -- ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4877
a61af66fc99e Initial load
duke
parents:
diff changeset
4878 guarantee (THREAD == _owner, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4879 if (THREAD->is_Java_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4880 JavaThread * jSelf = (JavaThread *) THREAD ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4881 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4882 if (!jSelf->handle_special_suspend_equivalent_condition()) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4883 SimpleExit (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4884 jSelf->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
4885 SimpleEnter (THREAD) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4886 jSelf->set_suspend_equivalent() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4887 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4888 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4889 guarantee (THREAD == _owner, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4890
a61af66fc99e Initial load
duke
parents:
diff changeset
4891 if (interruptible && Thread::is_interrupted(THREAD, true)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4892 return OM_INTERRUPTED;
a61af66fc99e Initial load
duke
parents:
diff changeset
4893 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4894 return OM_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4895 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4896
a61af66fc99e Initial load
duke
parents:
diff changeset
4897 int ObjectMonitor::raw_notify(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4898 TEVENT (raw_notify) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4899 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4900 return OM_ILLEGAL_MONITOR_STATE;
a61af66fc99e Initial load
duke
parents:
diff changeset
4901 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4902 SimpleNotify (THREAD, false) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4903 return OM_OK;
a61af66fc99e Initial load
duke
parents:
diff changeset
4904 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4905
a61af66fc99e Initial load
duke
parents:
diff changeset
4906 int ObjectMonitor::raw_notifyAll(TRAPS) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4907 TEVENT (raw_notifyAll) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4908 if (THREAD != _owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4909 return OM_ILLEGAL_MONITOR_STATE;
a61af66fc99e Initial load
duke
parents:
diff changeset
4910 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4911 SimpleNotify (THREAD, true) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
4912 return OM_OK;
a61af66fc99e Initial load
duke
parents:
diff changeset
4913 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4914
a61af66fc99e Initial load
duke
parents:
diff changeset
4915 #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
4916 void ObjectMonitor::verify() {
a61af66fc99e Initial load
duke
parents:
diff changeset
4917 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4918
a61af66fc99e Initial load
duke
parents:
diff changeset
4919 void ObjectMonitor::print() {
a61af66fc99e Initial load
duke
parents:
diff changeset
4920 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4921 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
4922
a61af66fc99e Initial load
duke
parents:
diff changeset
4923 //------------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
4924 // Non-product code
a61af66fc99e Initial load
duke
parents:
diff changeset
4925
a61af66fc99e Initial load
duke
parents:
diff changeset
4926 #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
4927
a61af66fc99e Initial load
duke
parents:
diff changeset
4928 void ObjectSynchronizer::trace_locking(Handle locking_obj, bool is_compiled,
a61af66fc99e Initial load
duke
parents:
diff changeset
4929 bool is_method, bool is_locking) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4930 // Don't know what to do here
a61af66fc99e Initial load
duke
parents:
diff changeset
4931 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4932
a61af66fc99e Initial load
duke
parents:
diff changeset
4933 // Verify all monitors in the monitor cache, the verification is weak.
a61af66fc99e Initial load
duke
parents:
diff changeset
4934 void ObjectSynchronizer::verify() {
a61af66fc99e Initial load
duke
parents:
diff changeset
4935 ObjectMonitor* block = gBlockList;
a61af66fc99e Initial load
duke
parents:
diff changeset
4936 ObjectMonitor* mid;
a61af66fc99e Initial load
duke
parents:
diff changeset
4937 while (block) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4938 assert(block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
4939 for (int i = 1; i < _BLOCKSIZE; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4940 mid = block + i;
a61af66fc99e Initial load
duke
parents:
diff changeset
4941 oop object = (oop) mid->object();
a61af66fc99e Initial load
duke
parents:
diff changeset
4942 if (object != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4943 mid->verify();
a61af66fc99e Initial load
duke
parents:
diff changeset
4944 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4945 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4946 block = (ObjectMonitor*) block->FreeNext;
a61af66fc99e Initial load
duke
parents:
diff changeset
4947 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4948 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4949
a61af66fc99e Initial load
duke
parents:
diff changeset
4950 // Check if monitor belongs to the monitor cache
a61af66fc99e Initial load
duke
parents:
diff changeset
4951 // The list is grow-only so it's *relatively* safe to traverse
a61af66fc99e Initial load
duke
parents:
diff changeset
4952 // the list of extant blocks without taking a lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
4953
a61af66fc99e Initial load
duke
parents:
diff changeset
4954 int ObjectSynchronizer::verify_objmon_isinpool(ObjectMonitor *monitor) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4955 ObjectMonitor* block = gBlockList;
a61af66fc99e Initial load
duke
parents:
diff changeset
4956
a61af66fc99e Initial load
duke
parents:
diff changeset
4957 while (block) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4958 assert(block->object() == CHAINMARKER, "must be a block header");
a61af66fc99e Initial load
duke
parents:
diff changeset
4959 if (monitor > &block[0] && monitor < &block[_BLOCKSIZE]) {
a61af66fc99e Initial load
duke
parents:
diff changeset
4960 address mon = (address) monitor;
a61af66fc99e Initial load
duke
parents:
diff changeset
4961 address blk = (address) block;
a61af66fc99e Initial load
duke
parents:
diff changeset
4962 size_t diff = mon - blk;
a61af66fc99e Initial load
duke
parents:
diff changeset
4963 assert((diff % sizeof(ObjectMonitor)) == 0, "check");
a61af66fc99e Initial load
duke
parents:
diff changeset
4964 return 1;
a61af66fc99e Initial load
duke
parents:
diff changeset
4965 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4966 block = (ObjectMonitor*) block->FreeNext;
a61af66fc99e Initial load
duke
parents:
diff changeset
4967 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4968 return 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
4969 }
a61af66fc99e Initial load
duke
parents:
diff changeset
4970
a61af66fc99e Initial load
duke
parents:
diff changeset
4971 #endif