annotate src/share/vm/runtime/mutex.cpp @ 6862:8a5ea0a9ccc4

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