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

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