annotate src/share/vm/runtime/mutex.cpp @ 2368:dde920245681

6896099: Integrate CMS heap ergo with default heap sizing ergo 6627787: CMS: JVM refuses to start up with -Xms16m -Xmx16m 7000125: CMS: Anti-monotone young gen sizing with respect to maximum whole heap size specification 7027529: CMS: retire CMSUseOldDefaults flag Summary: Simplify CMS heap sizing code, relying on ergonomic initial sizing consistent with other collectors for the most part, controlling only young gen sizing to rein in pause times. Make CMS young gen sizing default statically cpu-dependant. Remove inconsistencies wrt generation sizing and policy code, allowing for the fixing for 6627787 and 7000125. For 7027529, retire the flag CMSUseOldDefaults which had been introduced as a bridge from JDK 5 to JDK 6 a number of years ago. Reviewed-by: brutisso, poonam
author ysr
date Wed, 16 Mar 2011 10:37:08 -0700
parents f95d63e2154a
children f08d439fab8c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1
a61af66fc99e Initial load
duke
parents:
diff changeset
2 /*
1972
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
3 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
5 *
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
8 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
9 *
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
14 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
15 *
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
19 *
1552
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1490
diff changeset
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1490
diff changeset
21 * or visit www.oracle.com if you need additional information or have any
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1490
diff changeset
22 * questions.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
23 *
a61af66fc99e Initial load
duke
parents:
diff changeset
24 */
a61af66fc99e Initial load
duke
parents:
diff changeset
25
1972
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
26 #include "precompiled.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
27 #include "runtime/mutex.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
28 #include "runtime/osThread.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
29 #include "utilities/events.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
30 #ifdef TARGET_OS_FAMILY_linux
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
31 # include "mutex_linux.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
32 # include "thread_linux.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
33 #endif
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
34 #ifdef TARGET_OS_FAMILY_solaris
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
35 # include "mutex_solaris.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
36 # include "thread_solaris.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
37 #endif
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
38 #ifdef TARGET_OS_FAMILY_windows
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
39 # include "mutex_windows.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
40 # include "thread_windows.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1552
diff changeset
41 #endif
0
a61af66fc99e Initial load
duke
parents:
diff changeset
42
a61af66fc99e Initial load
duke
parents:
diff changeset
43 // o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o
a61af66fc99e Initial load
duke
parents:
diff changeset
44 //
a61af66fc99e Initial load
duke
parents:
diff changeset
45 // Native Monitor-Mutex locking - theory of operations
a61af66fc99e Initial load
duke
parents:
diff changeset
46 //
a61af66fc99e Initial load
duke
parents:
diff changeset
47 // * Native Monitors are completely unrelated to Java-level monitors,
a61af66fc99e Initial load
duke
parents:
diff changeset
48 // although the "back-end" slow-path implementations share a common lineage.
a61af66fc99e Initial load
duke
parents:
diff changeset
49 // See objectMonitor:: in synchronizer.cpp.
a61af66fc99e Initial load
duke
parents:
diff changeset
50 // Native Monitors do *not* support nesting or recursion but otherwise
a61af66fc99e Initial load
duke
parents:
diff changeset
51 // they're basically Hoare-flavor monitors.
a61af66fc99e Initial load
duke
parents:
diff changeset
52 //
a61af66fc99e Initial load
duke
parents:
diff changeset
53 // * A thread acquires ownership of a Monitor/Mutex by CASing the LockByte
a61af66fc99e Initial load
duke
parents:
diff changeset
54 // in the _LockWord from zero to non-zero. Note that the _Owner field
a61af66fc99e Initial load
duke
parents:
diff changeset
55 // is advisory and is used only to verify that the thread calling unlock()
a61af66fc99e Initial load
duke
parents:
diff changeset
56 // is indeed the last thread to have acquired the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
57 //
a61af66fc99e Initial load
duke
parents:
diff changeset
58 // * Contending threads "push" themselves onto the front of the contention
a61af66fc99e Initial load
duke
parents:
diff changeset
59 // queue -- called the cxq -- with CAS and then spin/park.
a61af66fc99e Initial load
duke
parents:
diff changeset
60 // The _LockWord contains the LockByte as well as the pointer to the head
a61af66fc99e Initial load
duke
parents:
diff changeset
61 // of the cxq. Colocating the LockByte with the cxq precludes certain races.
a61af66fc99e Initial load
duke
parents:
diff changeset
62 //
a61af66fc99e Initial load
duke
parents:
diff changeset
63 // * Using a separately addressable LockByte allows for CAS:MEMBAR or CAS:0
a61af66fc99e Initial load
duke
parents:
diff changeset
64 // idioms. We currently use MEMBAR in the uncontended unlock() path, as
a61af66fc99e Initial load
duke
parents:
diff changeset
65 // MEMBAR often has less latency than CAS. If warranted, we could switch to
a61af66fc99e Initial load
duke
parents:
diff changeset
66 // a CAS:0 mode, using timers to close the resultant race, as is done
a61af66fc99e Initial load
duke
parents:
diff changeset
67 // with Java Monitors in synchronizer.cpp.
a61af66fc99e Initial load
duke
parents:
diff changeset
68 //
a61af66fc99e Initial load
duke
parents:
diff changeset
69 // See the following for a discussion of the relative cost of atomics (CAS)
a61af66fc99e Initial load
duke
parents:
diff changeset
70 // MEMBAR, and ways to eliminate such instructions from the common-case paths:
a61af66fc99e Initial load
duke
parents:
diff changeset
71 // -- http://blogs.sun.com/dave/entry/biased_locking_in_hotspot
a61af66fc99e Initial load
duke
parents:
diff changeset
72 // -- http://blogs.sun.com/dave/resource/MustangSync.pdf
a61af66fc99e Initial load
duke
parents:
diff changeset
73 // -- http://blogs.sun.com/dave/resource/synchronization-public2.pdf
a61af66fc99e Initial load
duke
parents:
diff changeset
74 // -- synchronizer.cpp
a61af66fc99e Initial load
duke
parents:
diff changeset
75 //
a61af66fc99e Initial load
duke
parents:
diff changeset
76 // * Overall goals - desiderata
a61af66fc99e Initial load
duke
parents:
diff changeset
77 // 1. Minimize context switching
a61af66fc99e Initial load
duke
parents:
diff changeset
78 // 2. Minimize lock migration
a61af66fc99e Initial load
duke
parents:
diff changeset
79 // 3. Minimize CPI -- affinity and locality
a61af66fc99e Initial load
duke
parents:
diff changeset
80 // 4. Minimize the execution of high-latency instructions such as CAS or MEMBAR
a61af66fc99e Initial load
duke
parents:
diff changeset
81 // 5. Minimize outer lock hold times
a61af66fc99e Initial load
duke
parents:
diff changeset
82 // 6. Behave gracefully on a loaded system
a61af66fc99e Initial load
duke
parents:
diff changeset
83 //
a61af66fc99e Initial load
duke
parents:
diff changeset
84 // * Thread flow and list residency:
a61af66fc99e Initial load
duke
parents:
diff changeset
85 //
a61af66fc99e Initial load
duke
parents:
diff changeset
86 // Contention queue --> EntryList --> OnDeck --> Owner --> !Owner
a61af66fc99e Initial load
duke
parents:
diff changeset
87 // [..resident on monitor list..]
a61af66fc99e Initial load
duke
parents:
diff changeset
88 // [...........contending..................]
a61af66fc99e Initial load
duke
parents:
diff changeset
89 //
a61af66fc99e Initial load
duke
parents:
diff changeset
90 // -- The contention queue (cxq) contains recently-arrived threads (RATs).
a61af66fc99e Initial load
duke
parents:
diff changeset
91 // Threads on the cxq eventually drain into the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
92 // -- Invariant: a thread appears on at most one list -- cxq, EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
93 // or WaitSet -- at any one time.
a61af66fc99e Initial load
duke
parents:
diff changeset
94 // -- For a given monitor there can be at most one "OnDeck" thread at any
a61af66fc99e Initial load
duke
parents:
diff changeset
95 // given time but if needbe this particular invariant could be relaxed.
a61af66fc99e Initial load
duke
parents:
diff changeset
96 //
a61af66fc99e Initial load
duke
parents:
diff changeset
97 // * The WaitSet and EntryList linked lists are composed of ParkEvents.
a61af66fc99e Initial load
duke
parents:
diff changeset
98 // I use ParkEvent instead of threads as ParkEvents are immortal and
a61af66fc99e Initial load
duke
parents:
diff changeset
99 // type-stable, meaning we can safely unpark() a possibly stale
a61af66fc99e Initial load
duke
parents:
diff changeset
100 // list element in the unlock()-path. (That's benign).
a61af66fc99e Initial load
duke
parents:
diff changeset
101 //
a61af66fc99e Initial load
duke
parents:
diff changeset
102 // * Succession policy - providing for progress:
a61af66fc99e Initial load
duke
parents:
diff changeset
103 //
a61af66fc99e Initial load
duke
parents:
diff changeset
104 // As necessary, the unlock()ing thread identifies, unlinks, and unparks
a61af66fc99e Initial load
duke
parents:
diff changeset
105 // an "heir presumptive" tentative successor thread from the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
106 // This becomes the so-called "OnDeck" thread, of which there can be only
a61af66fc99e Initial load
duke
parents:
diff changeset
107 // one at any given time for a given monitor. The wakee will recontend
a61af66fc99e Initial load
duke
parents:
diff changeset
108 // for ownership of monitor.
a61af66fc99e Initial load
duke
parents:
diff changeset
109 //
a61af66fc99e Initial load
duke
parents:
diff changeset
110 // Succession is provided for by a policy of competitive handoff.
a61af66fc99e Initial load
duke
parents:
diff changeset
111 // The exiting thread does _not_ grant or pass ownership to the
a61af66fc99e Initial load
duke
parents:
diff changeset
112 // successor thread. (This is also referred to as "handoff" succession").
a61af66fc99e Initial load
duke
parents:
diff changeset
113 // Instead the exiting thread releases ownership and possibly wakes
a61af66fc99e Initial load
duke
parents:
diff changeset
114 // a successor, so the successor can (re)compete for ownership of the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
115 //
a61af66fc99e Initial load
duke
parents:
diff changeset
116 // Competitive handoff provides excellent overall throughput at the expense
a61af66fc99e Initial load
duke
parents:
diff changeset
117 // of short-term fairness. If fairness is a concern then one remedy might
a61af66fc99e Initial load
duke
parents:
diff changeset
118 // be to add an AcquireCounter field to the monitor. After a thread acquires
a61af66fc99e Initial load
duke
parents:
diff changeset
119 // the lock it will decrement the AcquireCounter field. When the count
a61af66fc99e Initial load
duke
parents:
diff changeset
120 // reaches 0 the thread would reset the AcquireCounter variable, abdicate
a61af66fc99e Initial load
duke
parents:
diff changeset
121 // the lock directly to some thread on the EntryList, and then move itself to the
a61af66fc99e Initial load
duke
parents:
diff changeset
122 // tail of the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
123 //
a61af66fc99e Initial load
duke
parents:
diff changeset
124 // But in practice most threads engage or otherwise participate in resource
a61af66fc99e Initial load
duke
parents:
diff changeset
125 // bounded producer-consumer relationships, so lock domination is not usually
a61af66fc99e Initial load
duke
parents:
diff changeset
126 // a practical concern. Recall too, that in general it's easier to construct
a61af66fc99e Initial load
duke
parents:
diff changeset
127 // a fair lock from a fast lock, but not vice-versa.
a61af66fc99e Initial load
duke
parents:
diff changeset
128 //
a61af66fc99e Initial load
duke
parents:
diff changeset
129 // * The cxq can have multiple concurrent "pushers" but only one concurrent
a61af66fc99e Initial load
duke
parents:
diff changeset
130 // detaching thread. This mechanism is immune from the ABA corruption.
a61af66fc99e Initial load
duke
parents:
diff changeset
131 // More precisely, the CAS-based "push" onto cxq is ABA-oblivious.
a61af66fc99e Initial load
duke
parents:
diff changeset
132 // We use OnDeck as a pseudo-lock to enforce the at-most-one detaching
a61af66fc99e Initial load
duke
parents:
diff changeset
133 // thread constraint.
a61af66fc99e Initial load
duke
parents:
diff changeset
134 //
a61af66fc99e Initial load
duke
parents:
diff changeset
135 // * Taken together, the cxq and the EntryList constitute or form a
a61af66fc99e Initial load
duke
parents:
diff changeset
136 // single logical queue of threads stalled trying to acquire the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
137 // We use two distinct lists to reduce heat on the list ends.
a61af66fc99e Initial load
duke
parents:
diff changeset
138 // Threads in lock() enqueue onto cxq while threads in unlock() will
a61af66fc99e Initial load
duke
parents:
diff changeset
139 // dequeue from the EntryList. (c.f. Michael Scott's "2Q" algorithm).
a61af66fc99e Initial load
duke
parents:
diff changeset
140 // A key desideratum is to minimize queue & monitor metadata manipulation
a61af66fc99e Initial load
duke
parents:
diff changeset
141 // that occurs while holding the "outer" monitor lock -- that is, we want to
a61af66fc99e Initial load
duke
parents:
diff changeset
142 // minimize monitor lock holds times.
a61af66fc99e Initial load
duke
parents:
diff changeset
143 //
a61af66fc99e Initial load
duke
parents:
diff changeset
144 // The EntryList is ordered by the prevailing queue discipline and
a61af66fc99e Initial load
duke
parents:
diff changeset
145 // can be organized in any convenient fashion, such as a doubly-linked list or
a61af66fc99e Initial load
duke
parents:
diff changeset
146 // a circular doubly-linked list. If we need a priority queue then something akin
a61af66fc99e Initial load
duke
parents:
diff changeset
147 // to Solaris' sleepq would work nicely. Viz.,
a61af66fc99e Initial load
duke
parents:
diff changeset
148 // -- http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c.
a61af66fc99e Initial load
duke
parents:
diff changeset
149 // -- http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/os/sleepq.c
a61af66fc99e Initial load
duke
parents:
diff changeset
150 // Queue discipline is enforced at ::unlock() time, when the unlocking thread
a61af66fc99e Initial load
duke
parents:
diff changeset
151 // drains the cxq into the EntryList, and orders or reorders the threads on the
a61af66fc99e Initial load
duke
parents:
diff changeset
152 // EntryList accordingly.
a61af66fc99e Initial load
duke
parents:
diff changeset
153 //
a61af66fc99e Initial load
duke
parents:
diff changeset
154 // Barring "lock barging", this mechanism provides fair cyclic ordering,
a61af66fc99e Initial load
duke
parents:
diff changeset
155 // somewhat similar to an elevator-scan.
a61af66fc99e Initial load
duke
parents:
diff changeset
156 //
a61af66fc99e Initial load
duke
parents:
diff changeset
157 // * OnDeck
a61af66fc99e Initial load
duke
parents:
diff changeset
158 // -- For a given monitor there can be at most one OnDeck thread at any given
a61af66fc99e Initial load
duke
parents:
diff changeset
159 // instant. The OnDeck thread is contending for the lock, but has been
a61af66fc99e Initial load
duke
parents:
diff changeset
160 // unlinked from the EntryList and cxq by some previous unlock() operations.
a61af66fc99e Initial load
duke
parents:
diff changeset
161 // Once a thread has been designated the OnDeck thread it will remain so
a61af66fc99e Initial load
duke
parents:
diff changeset
162 // until it manages to acquire the lock -- being OnDeck is a stable property.
a61af66fc99e Initial load
duke
parents:
diff changeset
163 // -- Threads on the EntryList or cxq are _not allowed to attempt lock acquisition.
a61af66fc99e Initial load
duke
parents:
diff changeset
164 // -- OnDeck also serves as an "inner lock" as follows. Threads in unlock() will, after
a61af66fc99e Initial load
duke
parents:
diff changeset
165 // having cleared the LockByte and dropped the outer lock, attempt to "trylock"
a61af66fc99e Initial load
duke
parents:
diff changeset
166 // OnDeck by CASing the field from null to non-null. If successful, that thread
a61af66fc99e Initial load
duke
parents:
diff changeset
167 // is then responsible for progress and succession and can use CAS to detach and
a61af66fc99e Initial load
duke
parents:
diff changeset
168 // drain the cxq into the EntryList. By convention, only this thread, the holder of
a61af66fc99e Initial load
duke
parents:
diff changeset
169 // the OnDeck inner lock, can manipulate the EntryList or detach and drain the
a61af66fc99e Initial load
duke
parents:
diff changeset
170 // RATs on the cxq into the EntryList. This avoids ABA corruption on the cxq as
a61af66fc99e Initial load
duke
parents:
diff changeset
171 // we allow multiple concurrent "push" operations but restrict detach concurrency
a61af66fc99e Initial load
duke
parents:
diff changeset
172 // to at most one thread. Having selected and detached a successor, the thread then
a61af66fc99e Initial load
duke
parents:
diff changeset
173 // changes the OnDeck to refer to that successor, and then unparks the successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
174 // That successor will eventually acquire the lock and clear OnDeck. Beware
a61af66fc99e Initial load
duke
parents:
diff changeset
175 // that the OnDeck usage as a lock is asymmetric. A thread in unlock() transiently
a61af66fc99e Initial load
duke
parents:
diff changeset
176 // "acquires" OnDeck, performs queue manipulations, passes OnDeck to some successor,
a61af66fc99e Initial load
duke
parents:
diff changeset
177 // and then the successor eventually "drops" OnDeck. Note that there's never
a61af66fc99e Initial load
duke
parents:
diff changeset
178 // any sense of contention on the inner lock, however. Threads never contend
a61af66fc99e Initial load
duke
parents:
diff changeset
179 // or wait for the inner lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
180 // -- OnDeck provides for futile wakeup throttling a described in section 3.3 of
a61af66fc99e Initial load
duke
parents:
diff changeset
181 // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
a61af66fc99e Initial load
duke
parents:
diff changeset
182 // In a sense, OnDeck subsumes the ObjectMonitor _Succ and ObjectWaiter
a61af66fc99e Initial load
duke
parents:
diff changeset
183 // TState fields found in Java-level objectMonitors. (See synchronizer.cpp).
a61af66fc99e Initial load
duke
parents:
diff changeset
184 //
a61af66fc99e Initial load
duke
parents:
diff changeset
185 // * Waiting threads reside on the WaitSet list -- wait() puts
a61af66fc99e Initial load
duke
parents:
diff changeset
186 // the caller onto the WaitSet. Notify() or notifyAll() simply
a61af66fc99e Initial load
duke
parents:
diff changeset
187 // transfers threads from the WaitSet to either the EntryList or cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
188 // Subsequent unlock() operations will eventually unpark the notifyee.
a61af66fc99e Initial load
duke
parents:
diff changeset
189 // Unparking a notifee in notify() proper is inefficient - if we were to do so
a61af66fc99e Initial load
duke
parents:
diff changeset
190 // it's likely the notifyee would simply impale itself on the lock held
a61af66fc99e Initial load
duke
parents:
diff changeset
191 // by the notifier.
a61af66fc99e Initial load
duke
parents:
diff changeset
192 //
a61af66fc99e Initial load
duke
parents:
diff changeset
193 // * The mechanism is obstruction-free in that if the holder of the transient
a61af66fc99e Initial load
duke
parents:
diff changeset
194 // OnDeck lock in unlock() is preempted or otherwise stalls, other threads
a61af66fc99e Initial load
duke
parents:
diff changeset
195 // can still acquire and release the outer lock and continue to make progress.
a61af66fc99e Initial load
duke
parents:
diff changeset
196 // At worst, waking of already blocked contending threads may be delayed,
a61af66fc99e Initial load
duke
parents:
diff changeset
197 // but nothing worse. (We only use "trylock" operations on the inner OnDeck
a61af66fc99e Initial load
duke
parents:
diff changeset
198 // lock).
a61af66fc99e Initial load
duke
parents:
diff changeset
199 //
a61af66fc99e Initial load
duke
parents:
diff changeset
200 // * Note that thread-local storage must be initialized before a thread
a61af66fc99e Initial load
duke
parents:
diff changeset
201 // uses Native monitors or mutexes. The native monitor-mutex subsystem
a61af66fc99e Initial load
duke
parents:
diff changeset
202 // depends on Thread::current().
a61af66fc99e Initial load
duke
parents:
diff changeset
203 //
a61af66fc99e Initial load
duke
parents:
diff changeset
204 // * The monitor synchronization subsystem avoids the use of native
a61af66fc99e Initial load
duke
parents:
diff changeset
205 // synchronization primitives except for the narrow platform-specific
a61af66fc99e Initial load
duke
parents:
diff changeset
206 // park-unpark abstraction. See the comments in os_solaris.cpp regarding
a61af66fc99e Initial load
duke
parents:
diff changeset
207 // the semantics of park-unpark. Put another way, this monitor implementation
a61af66fc99e Initial load
duke
parents:
diff changeset
208 // depends only on atomic operations and park-unpark. The monitor subsystem
a61af66fc99e Initial load
duke
parents:
diff changeset
209 // manages all RUNNING->BLOCKED and BLOCKED->READY transitions while the
a61af66fc99e Initial load
duke
parents:
diff changeset
210 // underlying OS manages the READY<->RUN transitions.
a61af66fc99e Initial load
duke
parents:
diff changeset
211 //
a61af66fc99e Initial load
duke
parents:
diff changeset
212 // * The memory consistency model provide by lock()-unlock() is at least as
a61af66fc99e Initial load
duke
parents:
diff changeset
213 // strong or stronger than the Java Memory model defined by JSR-133.
a61af66fc99e Initial load
duke
parents:
diff changeset
214 // That is, we guarantee at least entry consistency, if not stronger.
a61af66fc99e Initial load
duke
parents:
diff changeset
215 // See http://g.oswego.edu/dl/jmm/cookbook.html.
a61af66fc99e Initial load
duke
parents:
diff changeset
216 //
a61af66fc99e Initial load
duke
parents:
diff changeset
217 // * Thread:: currently contains a set of purpose-specific ParkEvents:
a61af66fc99e Initial load
duke
parents:
diff changeset
218 // _MutexEvent, _ParkEvent, etc. A better approach might be to do away with
a61af66fc99e Initial load
duke
parents:
diff changeset
219 // the purpose-specific ParkEvents and instead implement a general per-thread
a61af66fc99e Initial load
duke
parents:
diff changeset
220 // stack of available ParkEvents which we could provision on-demand. The
a61af66fc99e Initial load
duke
parents:
diff changeset
221 // stack acts as a local cache to avoid excessive calls to ParkEvent::Allocate()
a61af66fc99e Initial load
duke
parents:
diff changeset
222 // and ::Release(). A thread would simply pop an element from the local stack before it
a61af66fc99e Initial load
duke
parents:
diff changeset
223 // enqueued or park()ed. When the contention was over the thread would
a61af66fc99e Initial load
duke
parents:
diff changeset
224 // push the no-longer-needed ParkEvent back onto its stack.
a61af66fc99e Initial load
duke
parents:
diff changeset
225 //
a61af66fc99e Initial load
duke
parents:
diff changeset
226 // * A slightly reduced form of ILock() and IUnlock() have been partially
a61af66fc99e Initial load
duke
parents:
diff changeset
227 // model-checked (Murphi) for safety and progress at T=1,2,3 and 4.
a61af66fc99e Initial load
duke
parents:
diff changeset
228 // It'd be interesting to see if TLA/TLC could be useful as well.
a61af66fc99e Initial load
duke
parents:
diff changeset
229 //
a61af66fc99e Initial load
duke
parents:
diff changeset
230 // * Mutex-Monitor is a low-level "leaf" subsystem. That is, the monitor
a61af66fc99e Initial load
duke
parents:
diff changeset
231 // code should never call other code in the JVM that might itself need to
a61af66fc99e Initial load
duke
parents:
diff changeset
232 // acquire monitors or mutexes. That's true *except* in the case of the
a61af66fc99e Initial load
duke
parents:
diff changeset
233 // ThreadBlockInVM state transition wrappers. The ThreadBlockInVM DTOR handles
a61af66fc99e Initial load
duke
parents:
diff changeset
234 // mutator reentry (ingress) by checking for a pending safepoint in which case it will
a61af66fc99e Initial load
duke
parents:
diff changeset
235 // call SafepointSynchronize::block(), which in turn may call Safepoint_lock->lock(), etc.
a61af66fc99e Initial load
duke
parents:
diff changeset
236 // In that particular case a call to lock() for a given Monitor can end up recursively
a61af66fc99e Initial load
duke
parents:
diff changeset
237 // calling lock() on another monitor. While distasteful, this is largely benign
a61af66fc99e Initial load
duke
parents:
diff changeset
238 // as the calls come from jacket that wraps lock(), and not from deep within lock() itself.
a61af66fc99e Initial load
duke
parents:
diff changeset
239 //
a61af66fc99e Initial load
duke
parents:
diff changeset
240 // It's unfortunate that native mutexes and thread state transitions were convolved.
a61af66fc99e Initial load
duke
parents:
diff changeset
241 // They're really separate concerns and should have remained that way. Melding
a61af66fc99e Initial load
duke
parents:
diff changeset
242 // them together was facile -- a bit too facile. The current implementation badly
a61af66fc99e Initial load
duke
parents:
diff changeset
243 // conflates the two concerns.
a61af66fc99e Initial load
duke
parents:
diff changeset
244 //
a61af66fc99e Initial load
duke
parents:
diff changeset
245 // * TODO-FIXME:
a61af66fc99e Initial load
duke
parents:
diff changeset
246 //
a61af66fc99e Initial load
duke
parents:
diff changeset
247 // -- Add DTRACE probes for contended acquire, contended acquired, contended unlock
a61af66fc99e Initial load
duke
parents:
diff changeset
248 // We should also add DTRACE probes in the ParkEvent subsystem for
a61af66fc99e Initial load
duke
parents:
diff changeset
249 // Park-entry, Park-exit, and Unpark.
a61af66fc99e Initial load
duke
parents:
diff changeset
250 //
a61af66fc99e Initial load
duke
parents:
diff changeset
251 // -- We have an excess of mutex-like constructs in the JVM, namely:
a61af66fc99e Initial load
duke
parents:
diff changeset
252 // 1. objectMonitors for Java-level synchronization (synchronizer.cpp)
a61af66fc99e Initial load
duke
parents:
diff changeset
253 // 2. low-level muxAcquire and muxRelease
a61af66fc99e Initial load
duke
parents:
diff changeset
254 // 3. low-level spinAcquire and spinRelease
a61af66fc99e Initial load
duke
parents:
diff changeset
255 // 4. native Mutex:: and Monitor::
a61af66fc99e Initial load
duke
parents:
diff changeset
256 // 5. jvm_raw_lock() and _unlock()
a61af66fc99e Initial load
duke
parents:
diff changeset
257 // 6. JVMTI raw monitors -- distinct from (5) despite having a confusingly
a61af66fc99e Initial load
duke
parents:
diff changeset
258 // similar name.
a61af66fc99e Initial load
duke
parents:
diff changeset
259 //
a61af66fc99e Initial load
duke
parents:
diff changeset
260 // o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o
a61af66fc99e Initial load
duke
parents:
diff changeset
261
a61af66fc99e Initial load
duke
parents:
diff changeset
262
a61af66fc99e Initial load
duke
parents:
diff changeset
263 // CASPTR() uses the canonical argument order that dominates in the literature.
a61af66fc99e Initial load
duke
parents:
diff changeset
264 // Our internal cmpxchg_ptr() uses a bastardized ordering to accommodate Sun .il templates.
a61af66fc99e Initial load
duke
parents:
diff changeset
265
a61af66fc99e Initial load
duke
parents:
diff changeset
266 #define CASPTR(a,c,s) intptr_t(Atomic::cmpxchg_ptr ((void *)(s),(void *)(a),(void *)(c)))
a61af66fc99e Initial load
duke
parents:
diff changeset
267 #define UNS(x) (uintptr_t(x))
a61af66fc99e Initial load
duke
parents:
diff changeset
268 #define TRACE(m) { static volatile int ctr = 0 ; int x = ++ctr ; if ((x & (x-1))==0) { ::printf ("%d:%s\n", x, #m); ::fflush(stdout); }}
a61af66fc99e Initial load
duke
parents:
diff changeset
269
a61af66fc99e Initial load
duke
parents:
diff changeset
270 // Simplistic low-quality Marsaglia SHIFT-XOR RNG.
a61af66fc99e Initial load
duke
parents:
diff changeset
271 // Bijective except for the trailing mask operation.
a61af66fc99e Initial load
duke
parents:
diff changeset
272 // Useful for spin loops as the compiler can't optimize it away.
a61af66fc99e Initial load
duke
parents:
diff changeset
273
a61af66fc99e Initial load
duke
parents:
diff changeset
274 static inline jint MarsagliaXORV (jint x) {
a61af66fc99e Initial load
duke
parents:
diff changeset
275 if (x == 0) x = 1|os::random() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
276 x ^= x << 6;
a61af66fc99e Initial load
duke
parents:
diff changeset
277 x ^= ((unsigned)x) >> 21;
a61af66fc99e Initial load
duke
parents:
diff changeset
278 x ^= x << 7 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
279 return x & 0x7FFFFFFF ;
a61af66fc99e Initial load
duke
parents:
diff changeset
280 }
a61af66fc99e Initial load
duke
parents:
diff changeset
281
a61af66fc99e Initial load
duke
parents:
diff changeset
282 static inline jint MarsagliaXOR (jint * const a) {
a61af66fc99e Initial load
duke
parents:
diff changeset
283 jint x = *a ;
a61af66fc99e Initial load
duke
parents:
diff changeset
284 if (x == 0) x = UNS(a)|1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
285 x ^= x << 6;
a61af66fc99e Initial load
duke
parents:
diff changeset
286 x ^= ((unsigned)x) >> 21;
a61af66fc99e Initial load
duke
parents:
diff changeset
287 x ^= x << 7 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
288 *a = x ;
a61af66fc99e Initial load
duke
parents:
diff changeset
289 return x & 0x7FFFFFFF ;
a61af66fc99e Initial load
duke
parents:
diff changeset
290 }
a61af66fc99e Initial load
duke
parents:
diff changeset
291
a61af66fc99e Initial load
duke
parents:
diff changeset
292 static int Stall (int its) {
a61af66fc99e Initial load
duke
parents:
diff changeset
293 static volatile jint rv = 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
294 volatile int OnFrame = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
295 jint v = rv ^ UNS(OnFrame) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
296 while (--its >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
297 v = MarsagliaXORV (v) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
298 }
a61af66fc99e Initial load
duke
parents:
diff changeset
299 // Make this impossible for the compiler to optimize away,
a61af66fc99e Initial load
duke
parents:
diff changeset
300 // but (mostly) avoid W coherency sharing on MP systems.
a61af66fc99e Initial load
duke
parents:
diff changeset
301 if (v == 0x12345) rv = v ;
a61af66fc99e Initial load
duke
parents:
diff changeset
302 return v ;
a61af66fc99e Initial load
duke
parents:
diff changeset
303 }
a61af66fc99e Initial load
duke
parents:
diff changeset
304
a61af66fc99e Initial load
duke
parents:
diff changeset
305 int Monitor::TryLock () {
a61af66fc99e Initial load
duke
parents:
diff changeset
306 intptr_t v = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
307 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
308 if ((v & _LBIT) != 0) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
309 const intptr_t u = CASPTR (&_LockWord, v, v|_LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
310 if (v == u) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
311 v = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
312 }
a61af66fc99e Initial load
duke
parents:
diff changeset
313 }
a61af66fc99e Initial load
duke
parents:
diff changeset
314
a61af66fc99e Initial load
duke
parents:
diff changeset
315 int Monitor::TryFast () {
a61af66fc99e Initial load
duke
parents:
diff changeset
316 // Optimistic fast-path form ...
a61af66fc99e Initial load
duke
parents:
diff changeset
317 // Fast-path attempt for the common uncontended case.
a61af66fc99e Initial load
duke
parents:
diff changeset
318 // Avoid RTS->RTO $ coherence upgrade on typical SMP systems.
a61af66fc99e Initial load
duke
parents:
diff changeset
319 intptr_t v = CASPTR (&_LockWord, 0, _LBIT) ; // agro ...
a61af66fc99e Initial load
duke
parents:
diff changeset
320 if (v == 0) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
321
a61af66fc99e Initial load
duke
parents:
diff changeset
322 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
323 if ((v & _LBIT) != 0) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
324 const intptr_t u = CASPTR (&_LockWord, v, v|_LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
325 if (v == u) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
326 v = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
327 }
a61af66fc99e Initial load
duke
parents:
diff changeset
328 }
a61af66fc99e Initial load
duke
parents:
diff changeset
329
a61af66fc99e Initial load
duke
parents:
diff changeset
330 int Monitor::ILocked () {
a61af66fc99e Initial load
duke
parents:
diff changeset
331 const intptr_t w = _LockWord.FullWord & 0xFF ;
a61af66fc99e Initial load
duke
parents:
diff changeset
332 assert (w == 0 || w == _LBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
333 return w == _LBIT ;
a61af66fc99e Initial load
duke
parents:
diff changeset
334 }
a61af66fc99e Initial load
duke
parents:
diff changeset
335
a61af66fc99e Initial load
duke
parents:
diff changeset
336 // Polite TATAS spinlock with exponential backoff - bounded spin.
a61af66fc99e Initial load
duke
parents:
diff changeset
337 // Ideally we'd use processor cycles, time or vtime to control
a61af66fc99e Initial load
duke
parents:
diff changeset
338 // the loop, but we currently use iterations.
a61af66fc99e Initial load
duke
parents:
diff changeset
339 // All the constants within were derived empirically but work over
a61af66fc99e Initial load
duke
parents:
diff changeset
340 // over the spectrum of J2SE reference platforms.
a61af66fc99e Initial load
duke
parents:
diff changeset
341 // On Niagara-class systems the back-off is unnecessary but
a61af66fc99e Initial load
duke
parents:
diff changeset
342 // is relatively harmless. (At worst it'll slightly retard
a61af66fc99e Initial load
duke
parents:
diff changeset
343 // acquisition times). The back-off is critical for older SMP systems
a61af66fc99e Initial load
duke
parents:
diff changeset
344 // where constant fetching of the LockWord would otherwise impair
a61af66fc99e Initial load
duke
parents:
diff changeset
345 // scalability.
a61af66fc99e Initial load
duke
parents:
diff changeset
346 //
a61af66fc99e Initial load
duke
parents:
diff changeset
347 // Clamp spinning at approximately 1/2 of a context-switch round-trip.
a61af66fc99e Initial load
duke
parents:
diff changeset
348 // See synchronizer.cpp for details and rationale.
a61af66fc99e Initial load
duke
parents:
diff changeset
349
a61af66fc99e Initial load
duke
parents:
diff changeset
350 int Monitor::TrySpin (Thread * const Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
351 if (TryLock()) return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
352 if (!os::is_MP()) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
353
a61af66fc99e Initial load
duke
parents:
diff changeset
354 int Probes = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
355 int Delay = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
356 int Steps = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
357 int SpinMax = NativeMonitorSpinLimit ;
a61af66fc99e Initial load
duke
parents:
diff changeset
358 int flgs = NativeMonitorFlags ;
a61af66fc99e Initial load
duke
parents:
diff changeset
359 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
360 intptr_t v = _LockWord.FullWord;
a61af66fc99e Initial load
duke
parents:
diff changeset
361 if ((v & _LBIT) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
362 if (CASPTR (&_LockWord, v, v|_LBIT) == v) {
a61af66fc99e Initial load
duke
parents:
diff changeset
363 return 1 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
364 }
a61af66fc99e Initial load
duke
parents:
diff changeset
365 continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
366 }
a61af66fc99e Initial load
duke
parents:
diff changeset
367
a61af66fc99e Initial load
duke
parents:
diff changeset
368 if ((flgs & 8) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
369 SpinPause () ;
a61af66fc99e Initial load
duke
parents:
diff changeset
370 }
a61af66fc99e Initial load
duke
parents:
diff changeset
371
a61af66fc99e Initial load
duke
parents:
diff changeset
372 // Periodically increase Delay -- variable Delay form
a61af66fc99e Initial load
duke
parents:
diff changeset
373 // conceptually: delay *= 1 + 1/Exponent
a61af66fc99e Initial load
duke
parents:
diff changeset
374 ++ Probes;
a61af66fc99e Initial load
duke
parents:
diff changeset
375 if (Probes > SpinMax) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
376
a61af66fc99e Initial load
duke
parents:
diff changeset
377 if ((Probes & 0x7) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
378 Delay = ((Delay << 1)|1) & 0x7FF ;
a61af66fc99e Initial load
duke
parents:
diff changeset
379 // CONSIDER: Delay += 1 + (Delay/4); Delay &= 0x7FF ;
a61af66fc99e Initial load
duke
parents:
diff changeset
380 }
a61af66fc99e Initial load
duke
parents:
diff changeset
381
a61af66fc99e Initial load
duke
parents:
diff changeset
382 if (flgs & 2) continue ;
a61af66fc99e Initial load
duke
parents:
diff changeset
383
a61af66fc99e Initial load
duke
parents:
diff changeset
384 // Consider checking _owner's schedctl state, if OFFPROC abort spin.
a61af66fc99e Initial load
duke
parents:
diff changeset
385 // If the owner is OFFPROC then it's unlike that the lock will be dropped
a61af66fc99e Initial load
duke
parents:
diff changeset
386 // in a timely fashion, which suggests that spinning would not be fruitful
a61af66fc99e Initial load
duke
parents:
diff changeset
387 // or profitable.
a61af66fc99e Initial load
duke
parents:
diff changeset
388
a61af66fc99e Initial load
duke
parents:
diff changeset
389 // Stall for "Delay" time units - iterations in the current implementation.
a61af66fc99e Initial load
duke
parents:
diff changeset
390 // Avoid generating coherency traffic while stalled.
a61af66fc99e Initial load
duke
parents:
diff changeset
391 // Possible ways to delay:
a61af66fc99e Initial load
duke
parents:
diff changeset
392 // PAUSE, SLEEP, MEMBAR #sync, MEMBAR #halt,
a61af66fc99e Initial load
duke
parents:
diff changeset
393 // wr %g0,%asi, gethrtime, rdstick, rdtick, rdtsc, etc. ...
a61af66fc99e Initial load
duke
parents:
diff changeset
394 // Note that on Niagara-class systems we want to minimize STs in the
a61af66fc99e Initial load
duke
parents:
diff changeset
395 // spin loop. N1 and brethren write-around the L1$ over the xbar into the L2$.
a61af66fc99e Initial load
duke
parents:
diff changeset
396 // Furthermore, they don't have a W$ like traditional SPARC processors.
a61af66fc99e Initial load
duke
parents:
diff changeset
397 // We currently use a Marsaglia Shift-Xor RNG loop.
a61af66fc99e Initial load
duke
parents:
diff changeset
398 Steps += Delay ;
a61af66fc99e Initial load
duke
parents:
diff changeset
399 if (Self != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
400 jint rv = Self->rng[0] ;
a61af66fc99e Initial load
duke
parents:
diff changeset
401 for (int k = Delay ; --k >= 0; ) {
a61af66fc99e Initial load
duke
parents:
diff changeset
402 rv = MarsagliaXORV (rv) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
403 if ((flgs & 4) == 0 && SafepointSynchronize::do_call_back()) return 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
404 }
a61af66fc99e Initial load
duke
parents:
diff changeset
405 Self->rng[0] = rv ;
a61af66fc99e Initial load
duke
parents:
diff changeset
406 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
407 Stall (Delay) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
408 }
a61af66fc99e Initial load
duke
parents:
diff changeset
409 }
a61af66fc99e Initial load
duke
parents:
diff changeset
410 }
a61af66fc99e Initial load
duke
parents:
diff changeset
411
a61af66fc99e Initial load
duke
parents:
diff changeset
412 static int ParkCommon (ParkEvent * ev, jlong timo) {
a61af66fc99e Initial load
duke
parents:
diff changeset
413 // Diagnostic support - periodically unwedge blocked threads
a61af66fc99e Initial load
duke
parents:
diff changeset
414 intx nmt = NativeMonitorTimeout ;
a61af66fc99e Initial load
duke
parents:
diff changeset
415 if (nmt > 0 && (nmt < timo || timo <= 0)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
416 timo = nmt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
417 }
a61af66fc99e Initial load
duke
parents:
diff changeset
418 int err = OS_OK ;
a61af66fc99e Initial load
duke
parents:
diff changeset
419 if (0 == timo) {
a61af66fc99e Initial load
duke
parents:
diff changeset
420 ev->park() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
421 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
422 err = ev->park(timo) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
423 }
a61af66fc99e Initial load
duke
parents:
diff changeset
424 return err ;
a61af66fc99e Initial load
duke
parents:
diff changeset
425 }
a61af66fc99e Initial load
duke
parents:
diff changeset
426
a61af66fc99e Initial load
duke
parents:
diff changeset
427 inline int Monitor::AcquireOrPush (ParkEvent * ESelf) {
a61af66fc99e Initial load
duke
parents:
diff changeset
428 intptr_t v = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
429 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
430 if ((v & _LBIT) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
431 const intptr_t u = CASPTR (&_LockWord, v, v|_LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
432 if (u == v) return 1 ; // indicate acquired
a61af66fc99e Initial load
duke
parents:
diff changeset
433 v = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
434 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
435 // Anticipate success ...
a61af66fc99e Initial load
duke
parents:
diff changeset
436 ESelf->ListNext = (ParkEvent *) (v & ~_LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
437 const intptr_t u = CASPTR (&_LockWord, v, intptr_t(ESelf)|_LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
438 if (u == v) return 0 ; // indicate pushed onto cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
439 v = u ;
a61af66fc99e Initial load
duke
parents:
diff changeset
440 }
a61af66fc99e Initial load
duke
parents:
diff changeset
441 // Interference - LockWord change - just retry
a61af66fc99e Initial load
duke
parents:
diff changeset
442 }
a61af66fc99e Initial load
duke
parents:
diff changeset
443 }
a61af66fc99e Initial load
duke
parents:
diff changeset
444
a61af66fc99e Initial load
duke
parents:
diff changeset
445 // ILock and IWait are the lowest level primitive internal blocking
a61af66fc99e Initial load
duke
parents:
diff changeset
446 // synchronization functions. The callers of IWait and ILock must have
a61af66fc99e Initial load
duke
parents:
diff changeset
447 // performed any needed state transitions beforehand.
a61af66fc99e Initial load
duke
parents:
diff changeset
448 // IWait and ILock may directly call park() without any concern for thread state.
a61af66fc99e Initial load
duke
parents:
diff changeset
449 // Note that ILock and IWait do *not* access _owner.
a61af66fc99e Initial load
duke
parents:
diff changeset
450 // _owner is a higher-level logical concept.
a61af66fc99e Initial load
duke
parents:
diff changeset
451
a61af66fc99e Initial load
duke
parents:
diff changeset
452 void Monitor::ILock (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
453 assert (_OnDeck != Self->_MutexEvent, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
454
a61af66fc99e Initial load
duke
parents:
diff changeset
455 if (TryFast()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
456 Exeunt:
a61af66fc99e Initial load
duke
parents:
diff changeset
457 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
458 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
459 }
a61af66fc99e Initial load
duke
parents:
diff changeset
460
a61af66fc99e Initial load
duke
parents:
diff changeset
461 ParkEvent * const ESelf = Self->_MutexEvent ;
a61af66fc99e Initial load
duke
parents:
diff changeset
462 assert (_OnDeck != ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
463
a61af66fc99e Initial load
duke
parents:
diff changeset
464 // As an optimization, spinners could conditionally try to set ONDECK to _LBIT
a61af66fc99e Initial load
duke
parents:
diff changeset
465 // Synchronizer.cpp uses a similar optimization.
a61af66fc99e Initial load
duke
parents:
diff changeset
466 if (TrySpin (Self)) goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
467
a61af66fc99e Initial load
duke
parents:
diff changeset
468 // Slow-path - the lock is contended.
a61af66fc99e Initial load
duke
parents:
diff changeset
469 // Either Enqueue Self on cxq or acquire the outer lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
470 // LockWord encoding = (cxq,LOCKBYTE)
a61af66fc99e Initial load
duke
parents:
diff changeset
471 ESelf->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
472 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
473
a61af66fc99e Initial load
duke
parents:
diff changeset
474 // Optional optimization ... try barging on the inner lock
a61af66fc99e Initial load
duke
parents:
diff changeset
475 if ((NativeMonitorFlags & 32) && CASPTR (&_OnDeck, NULL, UNS(Self)) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
476 goto OnDeck_LOOP ;
a61af66fc99e Initial load
duke
parents:
diff changeset
477 }
a61af66fc99e Initial load
duke
parents:
diff changeset
478
a61af66fc99e Initial load
duke
parents:
diff changeset
479 if (AcquireOrPush (ESelf)) goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
480
a61af66fc99e Initial load
duke
parents:
diff changeset
481 // At any given time there is at most one ondeck thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
482 // ondeck implies not resident on cxq and not resident on EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
483 // Only the OnDeck thread can try to acquire -- contended for -- the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
484 // CONSIDER: use Self->OnDeck instead of m->OnDeck.
a61af66fc99e Initial load
duke
parents:
diff changeset
485 // Deschedule Self so that others may run.
a61af66fc99e Initial load
duke
parents:
diff changeset
486 while (_OnDeck != ESelf) {
a61af66fc99e Initial load
duke
parents:
diff changeset
487 ParkCommon (ESelf, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
488 }
a61af66fc99e Initial load
duke
parents:
diff changeset
489
a61af66fc99e Initial load
duke
parents:
diff changeset
490 // Self is now in the ONDECK position and will remain so until it
a61af66fc99e Initial load
duke
parents:
diff changeset
491 // manages to acquire the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
492 OnDeck_LOOP:
a61af66fc99e Initial load
duke
parents:
diff changeset
493 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
494 assert (_OnDeck == ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
495 if (TrySpin (Self)) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
496 // CONSIDER: if ESelf->TryPark() && TryLock() break ...
a61af66fc99e Initial load
duke
parents:
diff changeset
497 // It's probably wise to spin only if we *actually* blocked
a61af66fc99e Initial load
duke
parents:
diff changeset
498 // CONSIDER: check the lockbyte, if it remains set then
a61af66fc99e Initial load
duke
parents:
diff changeset
499 // preemptively drain the cxq into the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
500 // The best place and time to perform queue operations -- lock metadata --
a61af66fc99e Initial load
duke
parents:
diff changeset
501 // is _before having acquired the outer lock, while waiting for the lock to drop.
a61af66fc99e Initial load
duke
parents:
diff changeset
502 ParkCommon (ESelf, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
503 }
a61af66fc99e Initial load
duke
parents:
diff changeset
504
a61af66fc99e Initial load
duke
parents:
diff changeset
505 assert (_OnDeck == ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
506 _OnDeck = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
507
a61af66fc99e Initial load
duke
parents:
diff changeset
508 // Note that we current drop the inner lock (clear OnDeck) in the slow-path
a61af66fc99e Initial load
duke
parents:
diff changeset
509 // epilog immediately after having acquired the outer lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
510 // But instead we could consider the following optimizations:
a61af66fc99e Initial load
duke
parents:
diff changeset
511 // A. Shift or defer dropping the inner lock until the subsequent IUnlock() operation.
a61af66fc99e Initial load
duke
parents:
diff changeset
512 // This might avoid potential reacquisition of the inner lock in IUlock().
a61af66fc99e Initial load
duke
parents:
diff changeset
513 // B. While still holding the inner lock, attempt to opportunistically select
a61af66fc99e Initial load
duke
parents:
diff changeset
514 // and unlink the next ONDECK thread from the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
515 // If successful, set ONDECK to refer to that thread, otherwise clear ONDECK.
a61af66fc99e Initial load
duke
parents:
diff changeset
516 // It's critical that the select-and-unlink operation run in constant-time as
a61af66fc99e Initial load
duke
parents:
diff changeset
517 // it executes when holding the outer lock and may artificially increase the
a61af66fc99e Initial load
duke
parents:
diff changeset
518 // effective length of the critical section.
a61af66fc99e Initial load
duke
parents:
diff changeset
519 // Note that (A) and (B) are tantamount to succession by direct handoff for
a61af66fc99e Initial load
duke
parents:
diff changeset
520 // the inner lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
521 goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
522 }
a61af66fc99e Initial load
duke
parents:
diff changeset
523
a61af66fc99e Initial load
duke
parents:
diff changeset
524 void Monitor::IUnlock (bool RelaxAssert) {
a61af66fc99e Initial load
duke
parents:
diff changeset
525 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
526 _LockWord.Bytes[_LSBINDEX] = 0 ; // drop outer lock
a61af66fc99e Initial load
duke
parents:
diff changeset
527 OrderAccess::storeload ();
a61af66fc99e Initial load
duke
parents:
diff changeset
528 ParkEvent * const w = _OnDeck ;
a61af66fc99e Initial load
duke
parents:
diff changeset
529 assert (RelaxAssert || w != Thread::current()->_MutexEvent, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
530 if (w != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
531 // Either we have a valid ondeck thread or ondeck is transiently "locked"
a61af66fc99e Initial load
duke
parents:
diff changeset
532 // by some exiting thread as it arranges for succession. The LSBit of
a61af66fc99e Initial load
duke
parents:
diff changeset
533 // OnDeck allows us to discriminate two cases. If the latter, the
a61af66fc99e Initial load
duke
parents:
diff changeset
534 // responsibility for progress and succession lies with that other thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
535 // For good performance, we also depend on the fact that redundant unpark()
a61af66fc99e Initial load
duke
parents:
diff changeset
536 // operations are cheap. That is, repeated Unpark()ing of the ONDECK thread
a61af66fc99e Initial load
duke
parents:
diff changeset
537 // is inexpensive. This approach provides implicit futile wakeup throttling.
a61af66fc99e Initial load
duke
parents:
diff changeset
538 // Note that the referent "w" might be stale with respect to the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
539 // In that case the following unpark() is harmless and the worst that'll happen
a61af66fc99e Initial load
duke
parents:
diff changeset
540 // is a spurious return from a park() operation. Critically, if "w" _is stale,
a61af66fc99e Initial load
duke
parents:
diff changeset
541 // then progress is known to have occurred as that means the thread associated
a61af66fc99e Initial load
duke
parents:
diff changeset
542 // with "w" acquired the lock. In that case this thread need take no further
a61af66fc99e Initial load
duke
parents:
diff changeset
543 // action to guarantee progress.
a61af66fc99e Initial load
duke
parents:
diff changeset
544 if ((UNS(w) & _LBIT) == 0) w->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
545 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
546 }
a61af66fc99e Initial load
duke
parents:
diff changeset
547
a61af66fc99e Initial load
duke
parents:
diff changeset
548 intptr_t cxq = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
549 if (((cxq & ~_LBIT)|UNS(_EntryList)) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
550 return ; // normal fast-path exit - cxq and EntryList both empty
a61af66fc99e Initial load
duke
parents:
diff changeset
551 }
a61af66fc99e Initial load
duke
parents:
diff changeset
552 if (cxq & _LBIT) {
a61af66fc99e Initial load
duke
parents:
diff changeset
553 // Optional optimization ...
a61af66fc99e Initial load
duke
parents:
diff changeset
554 // Some other thread acquired the lock in the window since this
a61af66fc99e Initial load
duke
parents:
diff changeset
555 // thread released it. Succession is now that thread's responsibility.
a61af66fc99e Initial load
duke
parents:
diff changeset
556 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
557 }
a61af66fc99e Initial load
duke
parents:
diff changeset
558
a61af66fc99e Initial load
duke
parents:
diff changeset
559 Succession:
a61af66fc99e Initial load
duke
parents:
diff changeset
560 // Slow-path exit - this thread must ensure succession and progress.
a61af66fc99e Initial load
duke
parents:
diff changeset
561 // OnDeck serves as lock to protect cxq and EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
562 // Only the holder of OnDeck can manipulate EntryList or detach the RATs from cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
563 // Avoid ABA - allow multiple concurrent producers (enqueue via push-CAS)
a61af66fc99e Initial load
duke
parents:
diff changeset
564 // but only one concurrent consumer (detacher of RATs).
a61af66fc99e Initial load
duke
parents:
diff changeset
565 // Consider protecting this critical section with schedctl on Solaris.
a61af66fc99e Initial load
duke
parents:
diff changeset
566 // Unlike a normal lock, however, the exiting thread "locks" OnDeck,
a61af66fc99e Initial load
duke
parents:
diff changeset
567 // picks a successor and marks that thread as OnDeck. That successor
a61af66fc99e Initial load
duke
parents:
diff changeset
568 // thread will then clear OnDeck once it eventually acquires the outer lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
569 if (CASPTR (&_OnDeck, NULL, _LBIT) != UNS(NULL)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
570 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
571 }
a61af66fc99e Initial load
duke
parents:
diff changeset
572
a61af66fc99e Initial load
duke
parents:
diff changeset
573 ParkEvent * List = _EntryList ;
a61af66fc99e Initial load
duke
parents:
diff changeset
574 if (List != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
575 // Transfer the head of the EntryList to the OnDeck position.
a61af66fc99e Initial load
duke
parents:
diff changeset
576 // Once OnDeck, a thread stays OnDeck until it acquires the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
577 // For a given lock there is at most OnDeck thread at any one instant.
a61af66fc99e Initial load
duke
parents:
diff changeset
578 WakeOne:
a61af66fc99e Initial load
duke
parents:
diff changeset
579 assert (List == _EntryList, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
580 ParkEvent * const w = List ;
a61af66fc99e Initial load
duke
parents:
diff changeset
581 assert (RelaxAssert || w != Thread::current()->_MutexEvent, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
582 _EntryList = w->ListNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
583 // as a diagnostic measure consider setting w->_ListNext = BAD
a61af66fc99e Initial load
duke
parents:
diff changeset
584 assert (UNS(_OnDeck) == _LBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
585 _OnDeck = w ; // pass OnDeck to w.
a61af66fc99e Initial load
duke
parents:
diff changeset
586 // w will clear OnDeck once it acquires the outer lock
a61af66fc99e Initial load
duke
parents:
diff changeset
587
a61af66fc99e Initial load
duke
parents:
diff changeset
588 // Another optional optimization ...
a61af66fc99e Initial load
duke
parents:
diff changeset
589 // For heavily contended locks it's not uncommon that some other
a61af66fc99e Initial load
duke
parents:
diff changeset
590 // thread acquired the lock while this thread was arranging succession.
a61af66fc99e Initial load
duke
parents:
diff changeset
591 // Try to defer the unpark() operation - Delegate the responsibility
a61af66fc99e Initial load
duke
parents:
diff changeset
592 // for unpark()ing the OnDeck thread to the current or subsequent owners
a61af66fc99e Initial load
duke
parents:
diff changeset
593 // That is, the new owner is responsible for unparking the OnDeck thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
594 OrderAccess::storeload() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
595 cxq = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
596 if (cxq & _LBIT) return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
597
a61af66fc99e Initial load
duke
parents:
diff changeset
598 w->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
599 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
600 }
a61af66fc99e Initial load
duke
parents:
diff changeset
601
a61af66fc99e Initial load
duke
parents:
diff changeset
602 cxq = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
603 if ((cxq & ~_LBIT) != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
604 // The EntryList is empty but the cxq is populated.
a61af66fc99e Initial load
duke
parents:
diff changeset
605 // drain RATs from cxq into EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
606 // Detach RATs segment with CAS and then merge into EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
607 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
608 // optional optimization - if locked, the owner is responsible for succession
a61af66fc99e Initial load
duke
parents:
diff changeset
609 if (cxq & _LBIT) goto Punt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
610 const intptr_t vfy = CASPTR (&_LockWord, cxq, cxq & _LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
611 if (vfy == cxq) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
612 cxq = vfy ;
a61af66fc99e Initial load
duke
parents:
diff changeset
613 // Interference - LockWord changed - Just retry
a61af66fc99e Initial load
duke
parents:
diff changeset
614 // We can see concurrent interference from contending threads
a61af66fc99e Initial load
duke
parents:
diff changeset
615 // pushing themselves onto the cxq or from lock-unlock operations.
a61af66fc99e Initial load
duke
parents:
diff changeset
616 // From the perspective of this thread, EntryList is stable and
a61af66fc99e Initial load
duke
parents:
diff changeset
617 // the cxq is prepend-only -- the head is volatile but the interior
a61af66fc99e Initial load
duke
parents:
diff changeset
618 // of the cxq is stable. In theory if we encounter interference from threads
a61af66fc99e Initial load
duke
parents:
diff changeset
619 // pushing onto cxq we could simply break off the original cxq suffix and
a61af66fc99e Initial load
duke
parents:
diff changeset
620 // move that segment to the EntryList, avoiding a 2nd or multiple CAS attempts
a61af66fc99e Initial load
duke
parents:
diff changeset
621 // on the high-traffic LockWord variable. For instance lets say the cxq is "ABCD"
a61af66fc99e Initial load
duke
parents:
diff changeset
622 // when we first fetch cxq above. Between the fetch -- where we observed "A"
a61af66fc99e Initial load
duke
parents:
diff changeset
623 // -- and CAS -- where we attempt to CAS null over A -- "PQR" arrive,
a61af66fc99e Initial load
duke
parents:
diff changeset
624 // yielding cxq = "PQRABCD". In this case we could simply set A.ListNext
a61af66fc99e Initial load
duke
parents:
diff changeset
625 // null, leaving cxq = "PQRA" and transfer the "BCD" segment to the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
626 // Note too, that it's safe for this thread to traverse the cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
627 // without taking any special concurrency precautions.
a61af66fc99e Initial load
duke
parents:
diff changeset
628 }
a61af66fc99e Initial load
duke
parents:
diff changeset
629
a61af66fc99e Initial load
duke
parents:
diff changeset
630 // We don't currently reorder the cxq segment as we move it onto
a61af66fc99e Initial load
duke
parents:
diff changeset
631 // the EntryList, but it might make sense to reverse the order
a61af66fc99e Initial load
duke
parents:
diff changeset
632 // or perhaps sort by thread priority. See the comments in
a61af66fc99e Initial load
duke
parents:
diff changeset
633 // synchronizer.cpp objectMonitor::exit().
a61af66fc99e Initial load
duke
parents:
diff changeset
634 assert (_EntryList == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
635 _EntryList = List = (ParkEvent *)(cxq & ~_LBIT) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
636 assert (List != NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
637 goto WakeOne ;
a61af66fc99e Initial load
duke
parents:
diff changeset
638 }
a61af66fc99e Initial load
duke
parents:
diff changeset
639
a61af66fc99e Initial load
duke
parents:
diff changeset
640 // cxq|EntryList is empty.
a61af66fc99e Initial load
duke
parents:
diff changeset
641 // w == NULL implies that cxq|EntryList == NULL in the past.
a61af66fc99e Initial load
duke
parents:
diff changeset
642 // Possible race - rare inopportune interleaving.
a61af66fc99e Initial load
duke
parents:
diff changeset
643 // A thread could have added itself to cxq since this thread previously checked.
a61af66fc99e Initial load
duke
parents:
diff changeset
644 // Detect and recover by refetching cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
645 Punt:
a61af66fc99e Initial load
duke
parents:
diff changeset
646 assert (UNS(_OnDeck) == _LBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
647 _OnDeck = NULL ; // Release inner lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
648 OrderAccess::storeload(); // Dekker duality - pivot point
a61af66fc99e Initial load
duke
parents:
diff changeset
649
a61af66fc99e Initial load
duke
parents:
diff changeset
650 // Resample LockWord/cxq to recover from possible race.
a61af66fc99e Initial load
duke
parents:
diff changeset
651 // For instance, while this thread T1 held OnDeck, some other thread T2 might
a61af66fc99e Initial load
duke
parents:
diff changeset
652 // acquire the outer lock. Another thread T3 might try to acquire the outer
a61af66fc99e Initial load
duke
parents:
diff changeset
653 // lock, but encounter contention and enqueue itself on cxq. T2 then drops the
a61af66fc99e Initial load
duke
parents:
diff changeset
654 // outer lock, but skips succession as this thread T1 still holds OnDeck.
a61af66fc99e Initial load
duke
parents:
diff changeset
655 // T1 is and remains responsible for ensuring succession of T3.
a61af66fc99e Initial load
duke
parents:
diff changeset
656 //
a61af66fc99e Initial load
duke
parents:
diff changeset
657 // Note that we don't need to recheck EntryList, just cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
658 // If threads moved onto EntryList since we dropped OnDeck
a61af66fc99e Initial load
duke
parents:
diff changeset
659 // that implies some other thread forced succession.
a61af66fc99e Initial load
duke
parents:
diff changeset
660 cxq = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
661 if ((cxq & ~_LBIT) != 0 && (cxq & _LBIT) == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
662 goto Succession ; // potential race -- re-run succession
a61af66fc99e Initial load
duke
parents:
diff changeset
663 }
a61af66fc99e Initial load
duke
parents:
diff changeset
664 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
665 }
a61af66fc99e Initial load
duke
parents:
diff changeset
666
a61af66fc99e Initial load
duke
parents:
diff changeset
667 bool Monitor::notify() {
a61af66fc99e Initial load
duke
parents:
diff changeset
668 assert (_owner == Thread::current(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
669 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
670 if (_WaitSet == NULL) return true ;
a61af66fc99e Initial load
duke
parents:
diff changeset
671 NotifyCount ++ ;
a61af66fc99e Initial load
duke
parents:
diff changeset
672
a61af66fc99e Initial load
duke
parents:
diff changeset
673 // Transfer one thread from the WaitSet to the EntryList or cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
674 // Currently we just unlink the head of the WaitSet and prepend to the cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
675 // And of course we could just unlink it and unpark it, too, but
a61af66fc99e Initial load
duke
parents:
diff changeset
676 // in that case it'd likely impale itself on the reentry.
a61af66fc99e Initial load
duke
parents:
diff changeset
677 Thread::muxAcquire (_WaitLock, "notify:WaitLock") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
678 ParkEvent * nfy = _WaitSet ;
a61af66fc99e Initial load
duke
parents:
diff changeset
679 if (nfy != NULL) { // DCL idiom
a61af66fc99e Initial load
duke
parents:
diff changeset
680 _WaitSet = nfy->ListNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
681 assert (nfy->Notified == 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
682 // push nfy onto the cxq
a61af66fc99e Initial load
duke
parents:
diff changeset
683 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
684 const intptr_t v = _LockWord.FullWord ;
a61af66fc99e Initial load
duke
parents:
diff changeset
685 assert ((v & 0xFF) == _LBIT, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
686 nfy->ListNext = (ParkEvent *)(v & ~_LBIT);
a61af66fc99e Initial load
duke
parents:
diff changeset
687 if (CASPTR (&_LockWord, v, UNS(nfy)|_LBIT) == v) break;
a61af66fc99e Initial load
duke
parents:
diff changeset
688 // interference - _LockWord changed -- just retry
a61af66fc99e Initial load
duke
parents:
diff changeset
689 }
a61af66fc99e Initial load
duke
parents:
diff changeset
690 // Note that setting Notified before pushing nfy onto the cxq is
a61af66fc99e Initial load
duke
parents:
diff changeset
691 // also legal and safe, but the safety properties are much more
a61af66fc99e Initial load
duke
parents:
diff changeset
692 // subtle, so for the sake of code stewardship ...
a61af66fc99e Initial load
duke
parents:
diff changeset
693 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
694 nfy->Notified = 1;
a61af66fc99e Initial load
duke
parents:
diff changeset
695 }
a61af66fc99e Initial load
duke
parents:
diff changeset
696 Thread::muxRelease (_WaitLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
697 if (nfy != NULL && (NativeMonitorFlags & 16)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
698 // Experimental code ... light up the wakee in the hope that this thread (the owner)
a61af66fc99e Initial load
duke
parents:
diff changeset
699 // will drop the lock just about the time the wakee comes ONPROC.
a61af66fc99e Initial load
duke
parents:
diff changeset
700 nfy->unpark() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
701 }
a61af66fc99e Initial load
duke
parents:
diff changeset
702 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
703 return true ;
a61af66fc99e Initial load
duke
parents:
diff changeset
704 }
a61af66fc99e Initial load
duke
parents:
diff changeset
705
a61af66fc99e Initial load
duke
parents:
diff changeset
706 // Currently notifyAll() transfers the waiters one-at-a-time from the waitset
a61af66fc99e Initial load
duke
parents:
diff changeset
707 // to the cxq. This could be done more efficiently with a single bulk en-mass transfer,
a61af66fc99e Initial load
duke
parents:
diff changeset
708 // but in practice notifyAll() for large #s of threads is rare and not time-critical.
a61af66fc99e Initial load
duke
parents:
diff changeset
709 // Beware too, that we invert the order of the waiters. Lets say that the
a61af66fc99e Initial load
duke
parents:
diff changeset
710 // waitset is "ABCD" and the cxq is "XYZ". After a notifyAll() the waitset
a61af66fc99e Initial load
duke
parents:
diff changeset
711 // will be empty and the cxq will be "DCBAXYZ". This is benign, of course.
a61af66fc99e Initial load
duke
parents:
diff changeset
712
a61af66fc99e Initial load
duke
parents:
diff changeset
713 bool Monitor::notify_all() {
a61af66fc99e Initial load
duke
parents:
diff changeset
714 assert (_owner == Thread::current(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
715 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
716 while (_WaitSet != NULL) notify() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
717 return true ;
a61af66fc99e Initial load
duke
parents:
diff changeset
718 }
a61af66fc99e Initial load
duke
parents:
diff changeset
719
a61af66fc99e Initial load
duke
parents:
diff changeset
720 int Monitor::IWait (Thread * Self, jlong timo) {
a61af66fc99e Initial load
duke
parents:
diff changeset
721 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
722
a61af66fc99e Initial load
duke
parents:
diff changeset
723 // Phases:
a61af66fc99e Initial load
duke
parents:
diff changeset
724 // 1. Enqueue Self on WaitSet - currently prepend
a61af66fc99e Initial load
duke
parents:
diff changeset
725 // 2. unlock - drop the outer lock
a61af66fc99e Initial load
duke
parents:
diff changeset
726 // 3. wait for either notification or timeout
a61af66fc99e Initial load
duke
parents:
diff changeset
727 // 4. lock - reentry - reacquire the outer lock
a61af66fc99e Initial load
duke
parents:
diff changeset
728
a61af66fc99e Initial load
duke
parents:
diff changeset
729 ParkEvent * const ESelf = Self->_MutexEvent ;
a61af66fc99e Initial load
duke
parents:
diff changeset
730 ESelf->Notified = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
731 ESelf->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
732 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
733
a61af66fc99e Initial load
duke
parents:
diff changeset
734 // Add Self to WaitSet
a61af66fc99e Initial load
duke
parents:
diff changeset
735 // Ideally only the holder of the outer lock would manipulate the WaitSet -
a61af66fc99e Initial load
duke
parents:
diff changeset
736 // That is, the outer lock would implicitly protect the WaitSet.
a61af66fc99e Initial load
duke
parents:
diff changeset
737 // But if a thread in wait() encounters a timeout it will need to dequeue itself
a61af66fc99e Initial load
duke
parents:
diff changeset
738 // from the WaitSet _before it becomes the owner of the lock. We need to dequeue
a61af66fc99e Initial load
duke
parents:
diff changeset
739 // as the ParkEvent -- which serves as a proxy for the thread -- can't reside
a61af66fc99e Initial load
duke
parents:
diff changeset
740 // on both the WaitSet and the EntryList|cxq at the same time.. That is, a thread
a61af66fc99e Initial load
duke
parents:
diff changeset
741 // on the WaitSet can't be allowed to compete for the lock until it has managed to
a61af66fc99e Initial load
duke
parents:
diff changeset
742 // unlink its ParkEvent from WaitSet. Thus the need for WaitLock.
a61af66fc99e Initial load
duke
parents:
diff changeset
743 // Contention on the WaitLock is minimal.
a61af66fc99e Initial load
duke
parents:
diff changeset
744 //
a61af66fc99e Initial load
duke
parents:
diff changeset
745 // Another viable approach would be add another ParkEvent, "WaitEvent" to the
a61af66fc99e Initial load
duke
parents:
diff changeset
746 // thread class. The WaitSet would be composed of WaitEvents. Only the
a61af66fc99e Initial load
duke
parents:
diff changeset
747 // owner of the outer lock would manipulate the WaitSet. A thread in wait()
a61af66fc99e Initial load
duke
parents:
diff changeset
748 // could then compete for the outer lock, and then, if necessary, unlink itself
a61af66fc99e Initial load
duke
parents:
diff changeset
749 // from the WaitSet only after having acquired the outer lock. More precisely,
a61af66fc99e Initial load
duke
parents:
diff changeset
750 // there would be no WaitLock. A thread in in wait() would enqueue its WaitEvent
a61af66fc99e Initial load
duke
parents:
diff changeset
751 // on the WaitSet; release the outer lock; wait for either notification or timeout;
a61af66fc99e Initial load
duke
parents:
diff changeset
752 // reacquire the inner lock; and then, if needed, unlink itself from the WaitSet.
a61af66fc99e Initial load
duke
parents:
diff changeset
753 //
a61af66fc99e Initial load
duke
parents:
diff changeset
754 // Alternatively, a 2nd set of list link fields in the ParkEvent might suffice.
a61af66fc99e Initial load
duke
parents:
diff changeset
755 // One set would be for the WaitSet and one for the EntryList.
a61af66fc99e Initial load
duke
parents:
diff changeset
756 // We could also deconstruct the ParkEvent into a "pure" event and add a
a61af66fc99e Initial load
duke
parents:
diff changeset
757 // new immortal/TSM "ListElement" class that referred to ParkEvents.
a61af66fc99e Initial load
duke
parents:
diff changeset
758 // In that case we could have one ListElement on the WaitSet and another
a61af66fc99e Initial load
duke
parents:
diff changeset
759 // on the EntryList, with both referring to the same pure Event.
a61af66fc99e Initial load
duke
parents:
diff changeset
760
a61af66fc99e Initial load
duke
parents:
diff changeset
761 Thread::muxAcquire (_WaitLock, "wait:WaitLock:Add") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
762 ESelf->ListNext = _WaitSet ;
a61af66fc99e Initial load
duke
parents:
diff changeset
763 _WaitSet = ESelf ;
a61af66fc99e Initial load
duke
parents:
diff changeset
764 Thread::muxRelease (_WaitLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
765
a61af66fc99e Initial load
duke
parents:
diff changeset
766 // Release the outer lock
a61af66fc99e Initial load
duke
parents:
diff changeset
767 // We call IUnlock (RelaxAssert=true) as a thread T1 might
a61af66fc99e Initial load
duke
parents:
diff changeset
768 // enqueue itself on the WaitSet, call IUnlock(), drop the lock,
a61af66fc99e Initial load
duke
parents:
diff changeset
769 // and then stall before it can attempt to wake a successor.
a61af66fc99e Initial load
duke
parents:
diff changeset
770 // Some other thread T2 acquires the lock, and calls notify(), moving
a61af66fc99e Initial load
duke
parents:
diff changeset
771 // T1 from the WaitSet to the cxq. T2 then drops the lock. T1 resumes,
a61af66fc99e Initial load
duke
parents:
diff changeset
772 // and then finds *itself* on the cxq. During the course of a normal
a61af66fc99e Initial load
duke
parents:
diff changeset
773 // IUnlock() call a thread should _never find itself on the EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
774 // or cxq, but in the case of wait() it's possible.
a61af66fc99e Initial load
duke
parents:
diff changeset
775 // See synchronizer.cpp objectMonitor::wait().
a61af66fc99e Initial load
duke
parents:
diff changeset
776 IUnlock (true) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
777
a61af66fc99e Initial load
duke
parents:
diff changeset
778 // Wait for either notification or timeout
a61af66fc99e Initial load
duke
parents:
diff changeset
779 // Beware that in some circumstances we might propagate
a61af66fc99e Initial load
duke
parents:
diff changeset
780 // spurious wakeups back to the caller.
a61af66fc99e Initial load
duke
parents:
diff changeset
781
a61af66fc99e Initial load
duke
parents:
diff changeset
782 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
783 if (ESelf->Notified) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
784 int err = ParkCommon (ESelf, timo) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
785 if (err == OS_TIMEOUT || (NativeMonitorFlags & 1)) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
786 }
a61af66fc99e Initial load
duke
parents:
diff changeset
787
a61af66fc99e Initial load
duke
parents:
diff changeset
788 // Prepare for reentry - if necessary, remove ESelf from WaitSet
a61af66fc99e Initial load
duke
parents:
diff changeset
789 // ESelf can be:
a61af66fc99e Initial load
duke
parents:
diff changeset
790 // 1. Still on the WaitSet. This can happen if we exited the loop by timeout.
a61af66fc99e Initial load
duke
parents:
diff changeset
791 // 2. On the cxq or EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
792 // 3. Not resident on cxq, EntryList or WaitSet, but in the OnDeck position.
a61af66fc99e Initial load
duke
parents:
diff changeset
793
a61af66fc99e Initial load
duke
parents:
diff changeset
794 OrderAccess::fence() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
795 int WasOnWaitSet = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
796 if (ESelf->Notified == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
797 Thread::muxAcquire (_WaitLock, "wait:WaitLock:remove") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
798 if (ESelf->Notified == 0) { // DCL idiom
a61af66fc99e Initial load
duke
parents:
diff changeset
799 assert (_OnDeck != ESelf, "invariant") ; // can't be both OnDeck and on WaitSet
a61af66fc99e Initial load
duke
parents:
diff changeset
800 // ESelf is resident on the WaitSet -- unlink it.
a61af66fc99e Initial load
duke
parents:
diff changeset
801 // A doubly-linked list would be better here so we can unlink in constant-time.
a61af66fc99e Initial load
duke
parents:
diff changeset
802 // We have to unlink before we potentially recontend as ESelf might otherwise
a61af66fc99e Initial load
duke
parents:
diff changeset
803 // end up on the cxq|EntryList -- it can't be on two lists at once.
a61af66fc99e Initial load
duke
parents:
diff changeset
804 ParkEvent * p = _WaitSet ;
a61af66fc99e Initial load
duke
parents:
diff changeset
805 ParkEvent * q = NULL ; // classic q chases p
a61af66fc99e Initial load
duke
parents:
diff changeset
806 while (p != NULL && p != ESelf) {
a61af66fc99e Initial load
duke
parents:
diff changeset
807 q = p ;
a61af66fc99e Initial load
duke
parents:
diff changeset
808 p = p->ListNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
809 }
a61af66fc99e Initial load
duke
parents:
diff changeset
810 assert (p == ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
811 if (p == _WaitSet) { // found at head
a61af66fc99e Initial load
duke
parents:
diff changeset
812 assert (q == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
813 _WaitSet = p->ListNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
814 } else { // found in interior
a61af66fc99e Initial load
duke
parents:
diff changeset
815 assert (q->ListNext == p, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
816 q->ListNext = p->ListNext ;
a61af66fc99e Initial load
duke
parents:
diff changeset
817 }
a61af66fc99e Initial load
duke
parents:
diff changeset
818 WasOnWaitSet = 1 ; // We were *not* notified but instead encountered timeout
a61af66fc99e Initial load
duke
parents:
diff changeset
819 }
a61af66fc99e Initial load
duke
parents:
diff changeset
820 Thread::muxRelease (_WaitLock) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
821 }
a61af66fc99e Initial load
duke
parents:
diff changeset
822
a61af66fc99e Initial load
duke
parents:
diff changeset
823 // Reentry phase - reacquire the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
824 if (WasOnWaitSet) {
a61af66fc99e Initial load
duke
parents:
diff changeset
825 // ESelf was previously on the WaitSet but we just unlinked it above
a61af66fc99e Initial load
duke
parents:
diff changeset
826 // because of a timeout. ESelf is not resident on any list and is not OnDeck
a61af66fc99e Initial load
duke
parents:
diff changeset
827 assert (_OnDeck != ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
828 ILock (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
829 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
830 // A prior notify() operation moved ESelf from the WaitSet to the cxq.
a61af66fc99e Initial load
duke
parents:
diff changeset
831 // ESelf is now on the cxq, EntryList or at the OnDeck position.
a61af66fc99e Initial load
duke
parents:
diff changeset
832 // The following fragment is extracted from Monitor::ILock()
a61af66fc99e Initial load
duke
parents:
diff changeset
833 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
834 if (_OnDeck == ESelf && TrySpin(Self)) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
835 ParkCommon (ESelf, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
836 }
a61af66fc99e Initial load
duke
parents:
diff changeset
837 assert (_OnDeck == ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
838 _OnDeck = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
839 }
a61af66fc99e Initial load
duke
parents:
diff changeset
840
a61af66fc99e Initial load
duke
parents:
diff changeset
841 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
842 return WasOnWaitSet != 0 ; // return true IFF timeout
a61af66fc99e Initial load
duke
parents:
diff changeset
843 }
a61af66fc99e Initial load
duke
parents:
diff changeset
844
a61af66fc99e Initial load
duke
parents:
diff changeset
845
a61af66fc99e Initial load
duke
parents:
diff changeset
846 // ON THE VMTHREAD SNEAKING PAST HELD LOCKS:
a61af66fc99e Initial load
duke
parents:
diff changeset
847 // In particular, there are certain types of global lock that may be held
a61af66fc99e Initial load
duke
parents:
diff changeset
848 // by a Java thread while it is blocked at a safepoint but before it has
a61af66fc99e Initial load
duke
parents:
diff changeset
849 // written the _owner field. These locks may be sneakily acquired by the
a61af66fc99e Initial load
duke
parents:
diff changeset
850 // VM thread during a safepoint to avoid deadlocks. Alternatively, one should
a61af66fc99e Initial load
duke
parents:
diff changeset
851 // identify all such locks, and ensure that Java threads never block at
a61af66fc99e Initial load
duke
parents:
diff changeset
852 // safepoints while holding them (_no_safepoint_check_flag). While it
a61af66fc99e Initial load
duke
parents:
diff changeset
853 // seems as though this could increase the time to reach a safepoint
a61af66fc99e Initial load
duke
parents:
diff changeset
854 // (or at least increase the mean, if not the variance), the latter
a61af66fc99e Initial load
duke
parents:
diff changeset
855 // approach might make for a cleaner, more maintainable JVM design.
a61af66fc99e Initial load
duke
parents:
diff changeset
856 //
a61af66fc99e Initial load
duke
parents:
diff changeset
857 // Sneaking is vile and reprehensible and should be excised at the 1st
a61af66fc99e Initial load
duke
parents:
diff changeset
858 // opportunity. It's possible that the need for sneaking could be obviated
a61af66fc99e Initial load
duke
parents:
diff changeset
859 // as follows. Currently, a thread might (a) while TBIVM, call pthread_mutex_lock
a61af66fc99e Initial load
duke
parents:
diff changeset
860 // or ILock() thus acquiring the "physical" lock underlying Monitor/Mutex.
a61af66fc99e Initial load
duke
parents:
diff changeset
861 // (b) stall at the TBIVM exit point as a safepoint is in effect. Critically,
a61af66fc99e Initial load
duke
parents:
diff changeset
862 // it'll stall at the TBIVM reentry state transition after having acquired the
a61af66fc99e Initial load
duke
parents:
diff changeset
863 // underlying lock, but before having set _owner and having entered the actual
a61af66fc99e Initial load
duke
parents:
diff changeset
864 // critical section. The lock-sneaking facility leverages that fact and allowed the
a61af66fc99e Initial load
duke
parents:
diff changeset
865 // VM thread to logically acquire locks that had already be physically locked by mutators
a61af66fc99e Initial load
duke
parents:
diff changeset
866 // but where mutators were known blocked by the reentry thread state transition.
a61af66fc99e Initial load
duke
parents:
diff changeset
867 //
a61af66fc99e Initial load
duke
parents:
diff changeset
868 // If we were to modify the Monitor-Mutex so that TBIVM state transitions tightly
a61af66fc99e Initial load
duke
parents:
diff changeset
869 // wrapped calls to park(), then we could likely do away with sneaking. We'd
a61af66fc99e Initial load
duke
parents:
diff changeset
870 // decouple lock acquisition and parking. The critical invariant to eliminating
a61af66fc99e Initial load
duke
parents:
diff changeset
871 // sneaking is to ensure that we never "physically" acquire the lock while TBIVM.
a61af66fc99e Initial load
duke
parents:
diff changeset
872 // An easy way to accomplish this is to wrap the park calls in a narrow TBIVM jacket.
a61af66fc99e Initial load
duke
parents:
diff changeset
873 // One difficulty with this approach is that the TBIVM wrapper could recurse and
a61af66fc99e Initial load
duke
parents:
diff changeset
874 // call lock() deep from within a lock() call, while the MutexEvent was already enqueued.
a61af66fc99e Initial load
duke
parents:
diff changeset
875 // Using a stack (N=2 at minimum) of ParkEvents would take care of that problem.
a61af66fc99e Initial load
duke
parents:
diff changeset
876 //
a61af66fc99e Initial load
duke
parents:
diff changeset
877 // But of course the proper ultimate approach is to avoid schemes that require explicit
a61af66fc99e Initial load
duke
parents:
diff changeset
878 // sneaking or dependence on any any clever invariants or subtle implementation properties
a61af66fc99e Initial load
duke
parents:
diff changeset
879 // of Mutex-Monitor and instead directly address the underlying design flaw.
a61af66fc99e Initial load
duke
parents:
diff changeset
880
a61af66fc99e Initial load
duke
parents:
diff changeset
881 void Monitor::lock (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
882 #ifdef CHECK_UNHANDLED_OOPS
a61af66fc99e Initial load
duke
parents:
diff changeset
883 // Clear unhandled oops so we get a crash right away. Only clear for non-vm
a61af66fc99e Initial load
duke
parents:
diff changeset
884 // or GC threads.
a61af66fc99e Initial load
duke
parents:
diff changeset
885 if (Self->is_Java_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
886 Self->clear_unhandled_oops();
a61af66fc99e Initial load
duke
parents:
diff changeset
887 }
a61af66fc99e Initial load
duke
parents:
diff changeset
888 #endif // CHECK_UNHANDLED_OOPS
a61af66fc99e Initial load
duke
parents:
diff changeset
889
a61af66fc99e Initial load
duke
parents:
diff changeset
890 debug_only(check_prelock_state(Self));
a61af66fc99e Initial load
duke
parents:
diff changeset
891 assert (_owner != Self , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
892 assert (_OnDeck != Self->_MutexEvent, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
893
a61af66fc99e Initial load
duke
parents:
diff changeset
894 if (TryFast()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
895 Exeunt:
a61af66fc99e Initial load
duke
parents:
diff changeset
896 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
897 assert (owner() == NULL, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
898 set_owner (Self);
a61af66fc99e Initial load
duke
parents:
diff changeset
899 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
900 }
a61af66fc99e Initial load
duke
parents:
diff changeset
901
a61af66fc99e Initial load
duke
parents:
diff changeset
902 // The lock is contended ...
a61af66fc99e Initial load
duke
parents:
diff changeset
903
a61af66fc99e Initial load
duke
parents:
diff changeset
904 bool can_sneak = Self->is_VM_thread() && SafepointSynchronize::is_at_safepoint();
a61af66fc99e Initial load
duke
parents:
diff changeset
905 if (can_sneak && _owner == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
906 // a java thread has locked the lock but has not entered the
a61af66fc99e Initial load
duke
parents:
diff changeset
907 // critical region -- let's just pretend we've locked the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
908 // and go on. we note this with _snuck so we can also
a61af66fc99e Initial load
duke
parents:
diff changeset
909 // pretend to unlock when the time comes.
a61af66fc99e Initial load
duke
parents:
diff changeset
910 _snuck = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
911 goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
912 }
a61af66fc99e Initial load
duke
parents:
diff changeset
913
a61af66fc99e Initial load
duke
parents:
diff changeset
914 // Try a brief spin to avoid passing thru thread state transition ...
a61af66fc99e Initial load
duke
parents:
diff changeset
915 if (TrySpin (Self)) goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
916
a61af66fc99e Initial load
duke
parents:
diff changeset
917 check_block_state(Self);
a61af66fc99e Initial load
duke
parents:
diff changeset
918 if (Self->is_Java_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
919 // Horribile dictu - we suffer through a state transition
a61af66fc99e Initial load
duke
parents:
diff changeset
920 assert(rank() > Mutex::special, "Potential deadlock with special or lesser rank mutex");
a61af66fc99e Initial load
duke
parents:
diff changeset
921 ThreadBlockInVM tbivm ((JavaThread *) Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
922 ILock (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
923 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
924 // Mirabile dictu
a61af66fc99e Initial load
duke
parents:
diff changeset
925 ILock (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
926 }
a61af66fc99e Initial load
duke
parents:
diff changeset
927 goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
928 }
a61af66fc99e Initial load
duke
parents:
diff changeset
929
a61af66fc99e Initial load
duke
parents:
diff changeset
930 void Monitor::lock() {
a61af66fc99e Initial load
duke
parents:
diff changeset
931 this->lock(Thread::current());
a61af66fc99e Initial load
duke
parents:
diff changeset
932 }
a61af66fc99e Initial load
duke
parents:
diff changeset
933
a61af66fc99e Initial load
duke
parents:
diff changeset
934 // Lock without safepoint check - a degenerate variant of lock().
a61af66fc99e Initial load
duke
parents:
diff changeset
935 // Should ONLY be used by safepoint code and other code
a61af66fc99e Initial load
duke
parents:
diff changeset
936 // that is guaranteed not to block while running inside the VM. If this is called with
a61af66fc99e Initial load
duke
parents:
diff changeset
937 // thread state set to be in VM, the safepoint synchronization code will deadlock!
a61af66fc99e Initial load
duke
parents:
diff changeset
938
a61af66fc99e Initial load
duke
parents:
diff changeset
939 void Monitor::lock_without_safepoint_check (Thread * Self) {
a61af66fc99e Initial load
duke
parents:
diff changeset
940 assert (_owner != Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
941 ILock (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
942 assert (_owner == NULL, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
943 set_owner (Self);
a61af66fc99e Initial load
duke
parents:
diff changeset
944 }
a61af66fc99e Initial load
duke
parents:
diff changeset
945
a61af66fc99e Initial load
duke
parents:
diff changeset
946 void Monitor::lock_without_safepoint_check () {
a61af66fc99e Initial load
duke
parents:
diff changeset
947 lock_without_safepoint_check (Thread::current()) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
948 }
a61af66fc99e Initial load
duke
parents:
diff changeset
949
a61af66fc99e Initial load
duke
parents:
diff changeset
950
a61af66fc99e Initial load
duke
parents:
diff changeset
951 // Returns true if thread succeceed [sic] in grabbing the lock, otherwise false.
a61af66fc99e Initial load
duke
parents:
diff changeset
952
a61af66fc99e Initial load
duke
parents:
diff changeset
953 bool Monitor::try_lock() {
a61af66fc99e Initial load
duke
parents:
diff changeset
954 Thread * const Self = Thread::current();
a61af66fc99e Initial load
duke
parents:
diff changeset
955 debug_only(check_prelock_state(Self));
a61af66fc99e Initial load
duke
parents:
diff changeset
956 // assert(!thread->is_inside_signal_handler(), "don't lock inside signal handler");
a61af66fc99e Initial load
duke
parents:
diff changeset
957
a61af66fc99e Initial load
duke
parents:
diff changeset
958 // Special case, where all Java threads are stopped.
a61af66fc99e Initial load
duke
parents:
diff changeset
959 // The lock may have been acquired but _owner is not yet set.
a61af66fc99e Initial load
duke
parents:
diff changeset
960 // In that case the VM thread can safely grab the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
961 // It strikes me this should appear _after the TryLock() fails, below.
a61af66fc99e Initial load
duke
parents:
diff changeset
962 bool can_sneak = Self->is_VM_thread() && SafepointSynchronize::is_at_safepoint();
a61af66fc99e Initial load
duke
parents:
diff changeset
963 if (can_sneak && _owner == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
964 set_owner(Self); // Do not need to be atomic, since we are at a safepoint
a61af66fc99e Initial load
duke
parents:
diff changeset
965 _snuck = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
966 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
967 }
a61af66fc99e Initial load
duke
parents:
diff changeset
968
a61af66fc99e Initial load
duke
parents:
diff changeset
969 if (TryLock()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
970 // We got the lock
a61af66fc99e Initial load
duke
parents:
diff changeset
971 assert (_owner == NULL, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
972 set_owner (Self);
a61af66fc99e Initial load
duke
parents:
diff changeset
973 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
974 }
a61af66fc99e Initial load
duke
parents:
diff changeset
975 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
976 }
a61af66fc99e Initial load
duke
parents:
diff changeset
977
a61af66fc99e Initial load
duke
parents:
diff changeset
978 void Monitor::unlock() {
a61af66fc99e Initial load
duke
parents:
diff changeset
979 assert (_owner == Thread::current(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
980 assert (_OnDeck != Thread::current()->_MutexEvent , "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
981 set_owner (NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
982 if (_snuck) {
a61af66fc99e Initial load
duke
parents:
diff changeset
983 assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sneak");
a61af66fc99e Initial load
duke
parents:
diff changeset
984 _snuck = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
985 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
986 }
a61af66fc99e Initial load
duke
parents:
diff changeset
987 IUnlock (false) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
988 }
a61af66fc99e Initial load
duke
parents:
diff changeset
989
a61af66fc99e Initial load
duke
parents:
diff changeset
990 // Yet another degenerate version of Monitor::lock() or lock_without_safepoint_check()
a61af66fc99e Initial load
duke
parents:
diff changeset
991 // jvm_raw_lock() and _unlock() can be called by non-Java threads via JVM_RawMonitorEnter.
a61af66fc99e Initial load
duke
parents:
diff changeset
992 //
a61af66fc99e Initial load
duke
parents:
diff changeset
993 // There's no expectation that JVM_RawMonitors will interoperate properly with the native
a61af66fc99e Initial load
duke
parents:
diff changeset
994 // Mutex-Monitor constructs. We happen to implement JVM_RawMonitors in terms of
a61af66fc99e Initial load
duke
parents:
diff changeset
995 // native Mutex-Monitors simply as a matter of convenience. A simple abstraction layer
a61af66fc99e Initial load
duke
parents:
diff changeset
996 // over a pthread_mutex_t would work equally as well, but require more platform-specific
a61af66fc99e Initial load
duke
parents:
diff changeset
997 // code -- a "PlatformMutex". Alternatively, a simply layer over muxAcquire-muxRelease
a61af66fc99e Initial load
duke
parents:
diff changeset
998 // would work too.
a61af66fc99e Initial load
duke
parents:
diff changeset
999 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1000 // Since the caller might be a foreign thread, we don't necessarily have a Thread.MutexEvent
a61af66fc99e Initial load
duke
parents:
diff changeset
1001 // instance available. Instead, we transiently allocate a ParkEvent on-demand if
a61af66fc99e Initial load
duke
parents:
diff changeset
1002 // we encounter contention. That ParkEvent remains associated with the thread
a61af66fc99e Initial load
duke
parents:
diff changeset
1003 // until it manages to acquire the lock, at which time we return the ParkEvent
a61af66fc99e Initial load
duke
parents:
diff changeset
1004 // to the global ParkEvent free list. This is correct and suffices for our purposes.
a61af66fc99e Initial load
duke
parents:
diff changeset
1005 //
a61af66fc99e Initial load
duke
parents:
diff changeset
1006 // Beware that the original jvm_raw_unlock() had a "_snuck" test but that
a61af66fc99e Initial load
duke
parents:
diff changeset
1007 // jvm_raw_lock() didn't have the corresponding test. I suspect that's an
a61af66fc99e Initial load
duke
parents:
diff changeset
1008 // oversight, but I've replicated the original suspect logic in the new code ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1009
a61af66fc99e Initial load
duke
parents:
diff changeset
1010 void Monitor::jvm_raw_lock() {
a61af66fc99e Initial load
duke
parents:
diff changeset
1011 assert(rank() == native, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
1012
a61af66fc99e Initial load
duke
parents:
diff changeset
1013 if (TryLock()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1014 Exeunt:
a61af66fc99e Initial load
duke
parents:
diff changeset
1015 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1016 assert (_owner == NULL, "invariant");
a61af66fc99e Initial load
duke
parents:
diff changeset
1017 // This can potentially be called by non-java Threads. Thus, the ThreadLocalStorage
a61af66fc99e Initial load
duke
parents:
diff changeset
1018 // might return NULL. Don't call set_owner since it will break on an NULL owner
a61af66fc99e Initial load
duke
parents:
diff changeset
1019 // Consider installing a non-null "ANON" distinguished value instead of just NULL.
a61af66fc99e Initial load
duke
parents:
diff changeset
1020 _owner = ThreadLocalStorage::thread();
a61af66fc99e Initial load
duke
parents:
diff changeset
1021 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1022 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1023
a61af66fc99e Initial load
duke
parents:
diff changeset
1024 if (TrySpin(NULL)) goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1025
a61af66fc99e Initial load
duke
parents:
diff changeset
1026 // slow-path - apparent contention
a61af66fc99e Initial load
duke
parents:
diff changeset
1027 // Allocate a ParkEvent for transient use.
a61af66fc99e Initial load
duke
parents:
diff changeset
1028 // The ParkEvent remains associated with this thread until
a61af66fc99e Initial load
duke
parents:
diff changeset
1029 // the time the thread manages to acquire the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1030 ParkEvent * const ESelf = ParkEvent::Allocate(NULL) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1031 ESelf->reset() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1032 OrderAccess::storeload() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1033
a61af66fc99e Initial load
duke
parents:
diff changeset
1034 // Either Enqueue Self on cxq or acquire the outer lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1035 if (AcquireOrPush (ESelf)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1036 ParkEvent::Release (ESelf) ; // surrender the ParkEvent
a61af66fc99e Initial load
duke
parents:
diff changeset
1037 goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1038 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1039
a61af66fc99e Initial load
duke
parents:
diff changeset
1040 // At any given time there is at most one ondeck thread.
a61af66fc99e Initial load
duke
parents:
diff changeset
1041 // ondeck implies not resident on cxq and not resident on EntryList
a61af66fc99e Initial load
duke
parents:
diff changeset
1042 // Only the OnDeck thread can try to acquire -- contended for -- the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1043 // CONSIDER: use Self->OnDeck instead of m->OnDeck.
a61af66fc99e Initial load
duke
parents:
diff changeset
1044 for (;;) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1045 if (_OnDeck == ESelf && TrySpin(NULL)) break ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1046 ParkCommon (ESelf, 0) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1047 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1048
a61af66fc99e Initial load
duke
parents:
diff changeset
1049 assert (_OnDeck == ESelf, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1050 _OnDeck = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1051 ParkEvent::Release (ESelf) ; // surrender the ParkEvent
a61af66fc99e Initial load
duke
parents:
diff changeset
1052 goto Exeunt ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1053 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1054
a61af66fc99e Initial load
duke
parents:
diff changeset
1055 void Monitor::jvm_raw_unlock() {
a61af66fc99e Initial load
duke
parents:
diff changeset
1056 // Nearly the same as Monitor::unlock() ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1057 // directly set _owner instead of using set_owner(null)
a61af66fc99e Initial load
duke
parents:
diff changeset
1058 _owner = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1059 if (_snuck) { // ???
a61af66fc99e Initial load
duke
parents:
diff changeset
1060 assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sneak");
a61af66fc99e Initial load
duke
parents:
diff changeset
1061 _snuck = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
1062 return ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1063 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1064 IUnlock(false) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1065 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1066
a61af66fc99e Initial load
duke
parents:
diff changeset
1067 bool Monitor::wait(bool no_safepoint_check, long timeout, bool as_suspend_equivalent) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1068 Thread * const Self = Thread::current() ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1069 assert (_owner == Self, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1070 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1071
a61af66fc99e Initial load
duke
parents:
diff changeset
1072 // as_suspend_equivalent logically implies !no_safepoint_check
a61af66fc99e Initial load
duke
parents:
diff changeset
1073 guarantee (!as_suspend_equivalent || !no_safepoint_check, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1074 // !no_safepoint_check logically implies java_thread
a61af66fc99e Initial load
duke
parents:
diff changeset
1075 guarantee (no_safepoint_check || Self->is_Java_thread(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1076
a61af66fc99e Initial load
duke
parents:
diff changeset
1077 #ifdef ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
1078 Monitor * least = get_least_ranked_lock_besides_this(Self->owned_locks());
a61af66fc99e Initial load
duke
parents:
diff changeset
1079 assert(least != this, "Specification of get_least_... call above");
a61af66fc99e Initial load
duke
parents:
diff changeset
1080 if (least != NULL && least->rank() <= special) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1081 tty->print("Attempting to wait on monitor %s/%d while holding"
a61af66fc99e Initial load
duke
parents:
diff changeset
1082 " lock %s/%d -- possible deadlock",
a61af66fc99e Initial load
duke
parents:
diff changeset
1083 name(), rank(), least->name(), least->rank());
a61af66fc99e Initial load
duke
parents:
diff changeset
1084 assert(false, "Shouldn't block(wait) while holding a lock of rank special");
a61af66fc99e Initial load
duke
parents:
diff changeset
1085 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1086 #endif // ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
1087
a61af66fc99e Initial load
duke
parents:
diff changeset
1088 int wait_status ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1089 // conceptually set the owner to NULL in anticipation of
a61af66fc99e Initial load
duke
parents:
diff changeset
1090 // abdicating the lock in wait
a61af66fc99e Initial load
duke
parents:
diff changeset
1091 set_owner(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
1092 if (no_safepoint_check) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1093 wait_status = IWait (Self, timeout) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1094 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1095 assert (Self->is_Java_thread(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1096 JavaThread *jt = (JavaThread *)Self;
a61af66fc99e Initial load
duke
parents:
diff changeset
1097
a61af66fc99e Initial load
duke
parents:
diff changeset
1098 // Enter safepoint region - ornate and Rococo ...
a61af66fc99e Initial load
duke
parents:
diff changeset
1099 ThreadBlockInVM tbivm(jt);
a61af66fc99e Initial load
duke
parents:
diff changeset
1100 OSThreadWaitState osts(Self->osthread(), false /* not Object.wait() */);
a61af66fc99e Initial load
duke
parents:
diff changeset
1101
a61af66fc99e Initial load
duke
parents:
diff changeset
1102 if (as_suspend_equivalent) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1103 jt->set_suspend_equivalent();
a61af66fc99e Initial load
duke
parents:
diff changeset
1104 // cleared by handle_special_suspend_equivalent_condition() or
a61af66fc99e Initial load
duke
parents:
diff changeset
1105 // java_suspend_self()
a61af66fc99e Initial load
duke
parents:
diff changeset
1106 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1107
a61af66fc99e Initial load
duke
parents:
diff changeset
1108 wait_status = IWait (Self, timeout) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1109
a61af66fc99e Initial load
duke
parents:
diff changeset
1110 // were we externally suspended while we were waiting?
a61af66fc99e Initial load
duke
parents:
diff changeset
1111 if (as_suspend_equivalent && jt->handle_special_suspend_equivalent_condition()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1112 // Our event wait has finished and we own the lock, but
a61af66fc99e Initial load
duke
parents:
diff changeset
1113 // while we were waiting another thread suspended us. We don't
a61af66fc99e Initial load
duke
parents:
diff changeset
1114 // want to hold the lock while suspended because that
a61af66fc99e Initial load
duke
parents:
diff changeset
1115 // would surprise the thread that suspended us.
a61af66fc99e Initial load
duke
parents:
diff changeset
1116 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1117 IUnlock (true) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1118 jt->java_suspend_self();
a61af66fc99e Initial load
duke
parents:
diff changeset
1119 ILock (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1120 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1121 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1122 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1123
a61af66fc99e Initial load
duke
parents:
diff changeset
1124 // Conceptually reestablish ownership of the lock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1125 // The "real" lock -- the LockByte -- was reacquired by IWait().
a61af66fc99e Initial load
duke
parents:
diff changeset
1126 assert (ILocked(), "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1127 assert (_owner == NULL, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1128 set_owner (Self) ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1129 return wait_status != 0 ; // return true IFF timeout
a61af66fc99e Initial load
duke
parents:
diff changeset
1130 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1131
a61af66fc99e Initial load
duke
parents:
diff changeset
1132 Monitor::~Monitor() {
a61af66fc99e Initial load
duke
parents:
diff changeset
1133 assert ((UNS(_owner)|UNS(_LockWord.FullWord)|UNS(_EntryList)|UNS(_WaitSet)|UNS(_OnDeck)) == 0, "") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1134 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1135
55
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1136 void Monitor::ClearMonitor (Monitor * m, const char *name) {
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1137 m->_owner = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1138 m->_snuck = false ;
55
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1139 if (name == NULL) {
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1140 strcpy(m->_name, "UNKNOWN") ;
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1141 } else {
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1142 strncpy(m->_name, name, MONITOR_NAME_LEN - 1);
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1143 m->_name[MONITOR_NAME_LEN - 1] = '\0';
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1144 }
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1145 m->_LockWord.FullWord = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1146 m->_EntryList = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1147 m->_OnDeck = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1148 m->_WaitSet = NULL ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1149 m->_WaitLock[0] = 0 ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1150 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1151
a61af66fc99e Initial load
duke
parents:
diff changeset
1152 Monitor::Monitor() { ClearMonitor(this); }
a61af66fc99e Initial load
duke
parents:
diff changeset
1153
a61af66fc99e Initial load
duke
parents:
diff changeset
1154 Monitor::Monitor (int Rank, const char * name, bool allow_vm_block) {
55
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1155 ClearMonitor (this, name) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1156 #ifdef ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
1157 _allow_vm_block = allow_vm_block;
a61af66fc99e Initial load
duke
parents:
diff changeset
1158 _rank = Rank ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1159 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1160 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1161
a61af66fc99e Initial load
duke
parents:
diff changeset
1162 Mutex::~Mutex() {
a61af66fc99e Initial load
duke
parents:
diff changeset
1163 assert ((UNS(_owner)|UNS(_LockWord.FullWord)|UNS(_EntryList)|UNS(_WaitSet)|UNS(_OnDeck)) == 0, "") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1164 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1165
a61af66fc99e Initial load
duke
parents:
diff changeset
1166 Mutex::Mutex (int Rank, const char * name, bool allow_vm_block) {
55
2a8eb116ebbe 6610420: Debug VM crashes during monitor lock rank checking
xlu
parents: 0
diff changeset
1167 ClearMonitor ((Monitor *) this, name) ;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1168 #ifdef ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
1169 _allow_vm_block = allow_vm_block;
a61af66fc99e Initial load
duke
parents:
diff changeset
1170 _rank = Rank ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1171 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1172 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1173
a61af66fc99e Initial load
duke
parents:
diff changeset
1174 bool Monitor::owned_by_self() const {
a61af66fc99e Initial load
duke
parents:
diff changeset
1175 bool ret = _owner == Thread::current();
a61af66fc99e Initial load
duke
parents:
diff changeset
1176 assert (!ret || _LockWord.Bytes[_LSBINDEX] != 0, "invariant") ;
a61af66fc99e Initial load
duke
parents:
diff changeset
1177 return ret;
a61af66fc99e Initial load
duke
parents:
diff changeset
1178 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1179
a61af66fc99e Initial load
duke
parents:
diff changeset
1180 void Monitor::print_on_error(outputStream* st) const {
a61af66fc99e Initial load
duke
parents:
diff changeset
1181 st->print("[" PTR_FORMAT, this);
a61af66fc99e Initial load
duke
parents:
diff changeset
1182 st->print("] %s", _name);
a61af66fc99e Initial load
duke
parents:
diff changeset
1183 st->print(" - owner thread: " PTR_FORMAT, _owner);
a61af66fc99e Initial load
duke
parents:
diff changeset
1184 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1185
a61af66fc99e Initial load
duke
parents:
diff changeset
1186
a61af66fc99e Initial load
duke
parents:
diff changeset
1187
a61af66fc99e Initial load
duke
parents:
diff changeset
1188
a61af66fc99e Initial load
duke
parents:
diff changeset
1189 // ----------------------------------------------------------------------------------
a61af66fc99e Initial load
duke
parents:
diff changeset
1190 // Non-product code
a61af66fc99e Initial load
duke
parents:
diff changeset
1191
a61af66fc99e Initial load
duke
parents:
diff changeset
1192 #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
1193 void Monitor::print_on(outputStream* st) const {
a61af66fc99e Initial load
duke
parents:
diff changeset
1194 st->print_cr("Mutex: [0x%lx/0x%lx] %s - owner: 0x%lx", this, _LockWord.FullWord, _name, _owner);
a61af66fc99e Initial load
duke
parents:
diff changeset
1195 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1196 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1197
a61af66fc99e Initial load
duke
parents:
diff changeset
1198 #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
1199 #ifdef ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
1200 Monitor * Monitor::get_least_ranked_lock(Monitor * locks) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1201 Monitor *res, *tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
1202 for (res = tmp = locks; tmp != NULL; tmp = tmp->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1203 if (tmp->rank() < res->rank()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1204 res = tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
1205 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1206 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1207 if (!SafepointSynchronize::is_at_safepoint()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1208 // In this case, we expect the held locks to be
a61af66fc99e Initial load
duke
parents:
diff changeset
1209 // in increasing rank order (modulo any native ranks)
a61af66fc99e Initial load
duke
parents:
diff changeset
1210 for (tmp = locks; tmp != NULL; tmp = tmp->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1211 if (tmp->next() != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1212 assert(tmp->rank() == Mutex::native ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1213 tmp->rank() <= tmp->next()->rank(), "mutex rank anomaly?");
a61af66fc99e Initial load
duke
parents:
diff changeset
1214 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1215 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1216 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1217 return res;
a61af66fc99e Initial load
duke
parents:
diff changeset
1218 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1219
a61af66fc99e Initial load
duke
parents:
diff changeset
1220 Monitor* Monitor::get_least_ranked_lock_besides_this(Monitor* locks) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1221 Monitor *res, *tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
1222 for (res = NULL, tmp = locks; tmp != NULL; tmp = tmp->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1223 if (tmp != this && (res == NULL || tmp->rank() < res->rank())) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1224 res = tmp;
a61af66fc99e Initial load
duke
parents:
diff changeset
1225 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1226 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1227 if (!SafepointSynchronize::is_at_safepoint()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1228 // In this case, we expect the held locks to be
a61af66fc99e Initial load
duke
parents:
diff changeset
1229 // in increasing rank order (modulo any native ranks)
a61af66fc99e Initial load
duke
parents:
diff changeset
1230 for (tmp = locks; tmp != NULL; tmp = tmp->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1231 if (tmp->next() != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1232 assert(tmp->rank() == Mutex::native ||
a61af66fc99e Initial load
duke
parents:
diff changeset
1233 tmp->rank() <= tmp->next()->rank(), "mutex rank anomaly?");
a61af66fc99e Initial load
duke
parents:
diff changeset
1234 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1235 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1236 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1237 return res;
a61af66fc99e Initial load
duke
parents:
diff changeset
1238 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1239
a61af66fc99e Initial load
duke
parents:
diff changeset
1240
a61af66fc99e Initial load
duke
parents:
diff changeset
1241 bool Monitor::contains(Monitor* locks, Monitor * lock) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1242 for (; locks != NULL; locks = locks->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1243 if (locks == lock)
a61af66fc99e Initial load
duke
parents:
diff changeset
1244 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
1245 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1246 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
1247 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1248 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1249
a61af66fc99e Initial load
duke
parents:
diff changeset
1250 // Called immediately after lock acquisition or release as a diagnostic
a61af66fc99e Initial load
duke
parents:
diff changeset
1251 // to track the lock-set of the thread and test for rank violations that
a61af66fc99e Initial load
duke
parents:
diff changeset
1252 // might indicate exposure to deadlock.
a61af66fc99e Initial load
duke
parents:
diff changeset
1253 // Rather like an EventListener for _owner (:>).
a61af66fc99e Initial load
duke
parents:
diff changeset
1254
a61af66fc99e Initial load
duke
parents:
diff changeset
1255 void Monitor::set_owner_implementation(Thread *new_owner) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1256 // This function is solely responsible for maintaining
a61af66fc99e Initial load
duke
parents:
diff changeset
1257 // and checking the invariant that threads and locks
a61af66fc99e Initial load
duke
parents:
diff changeset
1258 // are in a 1/N relation, with some some locks unowned.
a61af66fc99e Initial load
duke
parents:
diff changeset
1259 // It uses the Mutex::_owner, Mutex::_next, and
a61af66fc99e Initial load
duke
parents:
diff changeset
1260 // Thread::_owned_locks fields, and no other function
a61af66fc99e Initial load
duke
parents:
diff changeset
1261 // changes those fields.
a61af66fc99e Initial load
duke
parents:
diff changeset
1262 // It is illegal to set the mutex from one non-NULL
a61af66fc99e Initial load
duke
parents:
diff changeset
1263 // owner to another--it must be owned by NULL as an
a61af66fc99e Initial load
duke
parents:
diff changeset
1264 // intermediate state.
a61af66fc99e Initial load
duke
parents:
diff changeset
1265
a61af66fc99e Initial load
duke
parents:
diff changeset
1266 if (new_owner != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1267 // the thread is acquiring this lock
a61af66fc99e Initial load
duke
parents:
diff changeset
1268
a61af66fc99e Initial load
duke
parents:
diff changeset
1269 assert(new_owner == Thread::current(), "Should I be doing this?");
a61af66fc99e Initial load
duke
parents:
diff changeset
1270 assert(_owner == NULL, "setting the owner thread of an already owned mutex");
a61af66fc99e Initial load
duke
parents:
diff changeset
1271 _owner = new_owner; // set the owner
a61af66fc99e Initial load
duke
parents:
diff changeset
1272
a61af66fc99e Initial load
duke
parents:
diff changeset
1273 // link "this" into the owned locks list
a61af66fc99e Initial load
duke
parents:
diff changeset
1274
a61af66fc99e Initial load
duke
parents:
diff changeset
1275 #ifdef ASSERT // Thread::_owned_locks is under the same ifdef
a61af66fc99e Initial load
duke
parents:
diff changeset
1276 Monitor* locks = get_least_ranked_lock(new_owner->owned_locks());
a61af66fc99e Initial load
duke
parents:
diff changeset
1277 // Mutex::set_owner_implementation is a friend of Thread
a61af66fc99e Initial load
duke
parents:
diff changeset
1278
a61af66fc99e Initial load
duke
parents:
diff changeset
1279 assert(this->rank() >= 0, "bad lock rank");
a61af66fc99e Initial load
duke
parents:
diff changeset
1280
a61af66fc99e Initial load
duke
parents:
diff changeset
1281 if (LogMultipleMutexLocking && locks != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1282 Events::log("thread " INTPTR_FORMAT " locks %s, already owns %s", new_owner, name(), locks->name());
a61af66fc99e Initial load
duke
parents:
diff changeset
1283 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1284
a61af66fc99e Initial load
duke
parents:
diff changeset
1285 // Deadlock avoidance rules require us to acquire Mutexes only in
a61af66fc99e Initial load
duke
parents:
diff changeset
1286 // a global total order. For example m1 is the lowest ranked mutex
a61af66fc99e Initial load
duke
parents:
diff changeset
1287 // that the thread holds and m2 is the mutex the thread is trying
a61af66fc99e Initial load
duke
parents:
diff changeset
1288 // to acquire, then deadlock avoidance rules require that the rank
a61af66fc99e Initial load
duke
parents:
diff changeset
1289 // of m2 be less than the rank of m1.
a61af66fc99e Initial load
duke
parents:
diff changeset
1290 // The rank Mutex::native is an exception in that it is not subject
a61af66fc99e Initial load
duke
parents:
diff changeset
1291 // to the verification rules.
a61af66fc99e Initial load
duke
parents:
diff changeset
1292 // Here are some further notes relating to mutex acquisition anomalies:
a61af66fc99e Initial load
duke
parents:
diff changeset
1293 // . under Solaris, the interrupt lock gets acquired when doing
a61af66fc99e Initial load
duke
parents:
diff changeset
1294 // profiling, so any lock could be held.
a61af66fc99e Initial load
duke
parents:
diff changeset
1295 // . it is also ok to acquire Safepoint_lock at the very end while we
a61af66fc99e Initial load
duke
parents:
diff changeset
1296 // already hold Terminator_lock - may happen because of periodic safepoints
a61af66fc99e Initial load
duke
parents:
diff changeset
1297 if (this->rank() != Mutex::native &&
a61af66fc99e Initial load
duke
parents:
diff changeset
1298 this->rank() != Mutex::suspend_resume &&
a61af66fc99e Initial load
duke
parents:
diff changeset
1299 locks != NULL && locks->rank() <= this->rank() &&
a61af66fc99e Initial load
duke
parents:
diff changeset
1300 !SafepointSynchronize::is_at_safepoint() &&
a61af66fc99e Initial load
duke
parents:
diff changeset
1301 this != Interrupt_lock && this != ProfileVM_lock &&
a61af66fc99e Initial load
duke
parents:
diff changeset
1302 !(this == Safepoint_lock && contains(locks, Terminator_lock) &&
a61af66fc99e Initial load
duke
parents:
diff changeset
1303 SafepointSynchronize::is_synchronizing())) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1304 new_owner->print_owned_locks();
1490
f03d0a26bf83 6888954: argument formatting for assert() and friends
jcoomes
parents: 196
diff changeset
1305 fatal(err_msg("acquiring lock %s/%d out of order with lock %s/%d -- "
f03d0a26bf83 6888954: argument formatting for assert() and friends
jcoomes
parents: 196
diff changeset
1306 "possible deadlock", this->name(), this->rank(),
f03d0a26bf83 6888954: argument formatting for assert() and friends
jcoomes
parents: 196
diff changeset
1307 locks->name(), locks->rank()));
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1308 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1309
a61af66fc99e Initial load
duke
parents:
diff changeset
1310 this->_next = new_owner->_owned_locks;
a61af66fc99e Initial load
duke
parents:
diff changeset
1311 new_owner->_owned_locks = this;
a61af66fc99e Initial load
duke
parents:
diff changeset
1312 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1313
a61af66fc99e Initial load
duke
parents:
diff changeset
1314 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1315 // the thread is releasing this lock
a61af66fc99e Initial load
duke
parents:
diff changeset
1316
a61af66fc99e Initial load
duke
parents:
diff changeset
1317 Thread* old_owner = _owner;
a61af66fc99e Initial load
duke
parents:
diff changeset
1318 debug_only(_last_owner = old_owner);
a61af66fc99e Initial load
duke
parents:
diff changeset
1319
a61af66fc99e Initial load
duke
parents:
diff changeset
1320 assert(old_owner != NULL, "removing the owner thread of an unowned mutex");
a61af66fc99e Initial load
duke
parents:
diff changeset
1321 assert(old_owner == Thread::current(), "removing the owner thread of an unowned mutex");
a61af66fc99e Initial load
duke
parents:
diff changeset
1322
a61af66fc99e Initial load
duke
parents:
diff changeset
1323 _owner = NULL; // set the owner
a61af66fc99e Initial load
duke
parents:
diff changeset
1324
a61af66fc99e Initial load
duke
parents:
diff changeset
1325 #ifdef ASSERT
a61af66fc99e Initial load
duke
parents:
diff changeset
1326 Monitor *locks = old_owner->owned_locks();
a61af66fc99e Initial load
duke
parents:
diff changeset
1327
a61af66fc99e Initial load
duke
parents:
diff changeset
1328 if (LogMultipleMutexLocking && locks != this) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1329 Events::log("thread " INTPTR_FORMAT " unlocks %s, still owns %s", old_owner, this->name(), locks->name());
a61af66fc99e Initial load
duke
parents:
diff changeset
1330 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1331
a61af66fc99e Initial load
duke
parents:
diff changeset
1332 // remove "this" from the owned locks list
a61af66fc99e Initial load
duke
parents:
diff changeset
1333
a61af66fc99e Initial load
duke
parents:
diff changeset
1334 Monitor *prev = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
1335 bool found = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
1336 for (; locks != NULL; prev = locks, locks = locks->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1337 if (locks == this) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1338 found = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
1339 break;
a61af66fc99e Initial load
duke
parents:
diff changeset
1340 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1341 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1342 assert(found, "Removing a lock not owned");
a61af66fc99e Initial load
duke
parents:
diff changeset
1343 if (prev == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1344 old_owner->_owned_locks = _next;
a61af66fc99e Initial load
duke
parents:
diff changeset
1345 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
1346 prev->_next = _next;
a61af66fc99e Initial load
duke
parents:
diff changeset
1347 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1348 _next = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
1349 #endif
a61af66fc99e Initial load
duke
parents:
diff changeset
1350 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1351 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1352
a61af66fc99e Initial load
duke
parents:
diff changeset
1353
a61af66fc99e Initial load
duke
parents:
diff changeset
1354 // Factored out common sanity checks for locking mutex'es. Used by lock() and try_lock()
a61af66fc99e Initial load
duke
parents:
diff changeset
1355 void Monitor::check_prelock_state(Thread *thread) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1356 assert((!thread->is_Java_thread() || ((JavaThread *)thread)->thread_state() == _thread_in_vm)
a61af66fc99e Initial load
duke
parents:
diff changeset
1357 || rank() == Mutex::special, "wrong thread state for using locks");
a61af66fc99e Initial load
duke
parents:
diff changeset
1358 if (StrictSafepointChecks) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1359 if (thread->is_VM_thread() && !allow_vm_block()) {
1490
f03d0a26bf83 6888954: argument formatting for assert() and friends
jcoomes
parents: 196
diff changeset
1360 fatal(err_msg("VM thread using lock %s (not allowed to block on)",
f03d0a26bf83 6888954: argument formatting for assert() and friends
jcoomes
parents: 196
diff changeset
1361 name()));
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1362 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1363 debug_only(if (rank() != Mutex::special) \
a61af66fc99e Initial load
duke
parents:
diff changeset
1364 thread->check_for_valid_safepoint_state(false);)
a61af66fc99e Initial load
duke
parents:
diff changeset
1365 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1366 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1367
a61af66fc99e Initial load
duke
parents:
diff changeset
1368 void Monitor::check_block_state(Thread *thread) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1369 if (!_allow_vm_block && thread->is_VM_thread()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
1370 warning("VM thread blocked on lock");
a61af66fc99e Initial load
duke
parents:
diff changeset
1371 print();
a61af66fc99e Initial load
duke
parents:
diff changeset
1372 BREAKPOINT;
a61af66fc99e Initial load
duke
parents:
diff changeset
1373 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1374 assert(_owner != thread, "deadlock: blocking on monitor owned by current thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
1375 }
a61af66fc99e Initial load
duke
parents:
diff changeset
1376
a61af66fc99e Initial load
duke
parents:
diff changeset
1377 #endif // PRODUCT