annotate src/share/vm/runtime/synchronizer.cpp @ 1145:e018e6884bd8

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