annotate src/share/vm/runtime/mutex.cpp @ 8854:754c24457b20

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