annotate src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp @ 452:00b023ae2d78

6722113: CMS: Incorrect overflow handling during precleaning of Reference lists Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery. Reviewed-by: apetrusenko, jcoomes
author ysr
date Thu, 20 Nov 2008 12:27:41 -0800
parents a61af66fc99e
children c18cbe5936b8
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 * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
18 *
a61af66fc99e Initial load
duke
parents:
diff changeset
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
a61af66fc99e Initial load
duke
parents:
diff changeset
20 * CA 95054 USA or visit www.sun.com if you need additional information or
a61af66fc99e Initial load
duke
parents:
diff changeset
21 * have any questions.
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
a61af66fc99e Initial load
duke
parents:
diff changeset
25 class ConcurrentMarkSweepGeneration;
a61af66fc99e Initial load
duke
parents:
diff changeset
26 class CMSCollector;
a61af66fc99e Initial load
duke
parents:
diff changeset
27
a61af66fc99e Initial load
duke
parents:
diff changeset
28 // The Concurrent Mark Sweep GC Thread (could be several in the future).
a61af66fc99e Initial load
duke
parents:
diff changeset
29 class ConcurrentMarkSweepThread: public ConcurrentGCThread {
a61af66fc99e Initial load
duke
parents:
diff changeset
30 friend class VMStructs;
a61af66fc99e Initial load
duke
parents:
diff changeset
31 friend class ConcurrentMarkSweepGeneration; // XXX should remove friendship
a61af66fc99e Initial load
duke
parents:
diff changeset
32 friend class CMSCollector;
a61af66fc99e Initial load
duke
parents:
diff changeset
33 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
34 virtual void run();
a61af66fc99e Initial load
duke
parents:
diff changeset
35
a61af66fc99e Initial load
duke
parents:
diff changeset
36 private:
a61af66fc99e Initial load
duke
parents:
diff changeset
37 static ConcurrentMarkSweepThread* _cmst;
a61af66fc99e Initial load
duke
parents:
diff changeset
38 static CMSCollector* _collector;
a61af66fc99e Initial load
duke
parents:
diff changeset
39 static SurrogateLockerThread* _slt;
a61af66fc99e Initial load
duke
parents:
diff changeset
40 static SurrogateLockerThread::SLT_msg_type _sltBuffer;
a61af66fc99e Initial load
duke
parents:
diff changeset
41 static Monitor* _sltMonitor;
a61af66fc99e Initial load
duke
parents:
diff changeset
42
a61af66fc99e Initial load
duke
parents:
diff changeset
43 ConcurrentMarkSweepThread* _next;
a61af66fc99e Initial load
duke
parents:
diff changeset
44
a61af66fc99e Initial load
duke
parents:
diff changeset
45 static bool _should_terminate;
a61af66fc99e Initial load
duke
parents:
diff changeset
46
a61af66fc99e Initial load
duke
parents:
diff changeset
47 enum CMS_flag_type {
a61af66fc99e Initial load
duke
parents:
diff changeset
48 CMS_nil = NoBits,
a61af66fc99e Initial load
duke
parents:
diff changeset
49 CMS_cms_wants_token = nth_bit(0),
a61af66fc99e Initial load
duke
parents:
diff changeset
50 CMS_cms_has_token = nth_bit(1),
a61af66fc99e Initial load
duke
parents:
diff changeset
51 CMS_vm_wants_token = nth_bit(2),
a61af66fc99e Initial load
duke
parents:
diff changeset
52 CMS_vm_has_token = nth_bit(3)
a61af66fc99e Initial load
duke
parents:
diff changeset
53 };
a61af66fc99e Initial load
duke
parents:
diff changeset
54
a61af66fc99e Initial load
duke
parents:
diff changeset
55 static int _CMS_flag;
a61af66fc99e Initial load
duke
parents:
diff changeset
56
a61af66fc99e Initial load
duke
parents:
diff changeset
57 static bool CMS_flag_is_set(int b) { return (_CMS_flag & b) != 0; }
a61af66fc99e Initial load
duke
parents:
diff changeset
58 static bool set_CMS_flag(int b) { return (_CMS_flag |= b) != 0; }
a61af66fc99e Initial load
duke
parents:
diff changeset
59 static bool clear_CMS_flag(int b) { return (_CMS_flag &= ~b) != 0; }
a61af66fc99e Initial load
duke
parents:
diff changeset
60 void sleepBeforeNextCycle();
a61af66fc99e Initial load
duke
parents:
diff changeset
61
a61af66fc99e Initial load
duke
parents:
diff changeset
62 // CMS thread should yield for a young gen collection, direct allocation,
a61af66fc99e Initial load
duke
parents:
diff changeset
63 // and iCMS activity.
a61af66fc99e Initial load
duke
parents:
diff changeset
64 static char _pad_1[64 - sizeof(jint)]; // prevent cache-line sharing
a61af66fc99e Initial load
duke
parents:
diff changeset
65 static volatile jint _pending_yields;
a61af66fc99e Initial load
duke
parents:
diff changeset
66 static volatile jint _pending_decrements; // decrements to _pending_yields
a61af66fc99e Initial load
duke
parents:
diff changeset
67 static char _pad_2[64 - sizeof(jint)]; // prevent cache-line sharing
a61af66fc99e Initial load
duke
parents:
diff changeset
68
a61af66fc99e Initial load
duke
parents:
diff changeset
69 // Tracing messages, enabled by CMSTraceThreadState.
a61af66fc99e Initial load
duke
parents:
diff changeset
70 static inline void trace_state(const char* desc);
a61af66fc99e Initial load
duke
parents:
diff changeset
71
a61af66fc99e Initial load
duke
parents:
diff changeset
72 static volatile bool _icms_enabled; // iCMS enabled?
a61af66fc99e Initial load
duke
parents:
diff changeset
73 static volatile bool _should_run; // iCMS may run
a61af66fc99e Initial load
duke
parents:
diff changeset
74 static volatile bool _should_stop; // iCMS should stop
a61af66fc99e Initial load
duke
parents:
diff changeset
75
a61af66fc99e Initial load
duke
parents:
diff changeset
76 // debugging
a61af66fc99e Initial load
duke
parents:
diff changeset
77 void verify_ok_to_terminate() const PRODUCT_RETURN;
a61af66fc99e Initial load
duke
parents:
diff changeset
78
a61af66fc99e Initial load
duke
parents:
diff changeset
79 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
80 // Constructor
a61af66fc99e Initial load
duke
parents:
diff changeset
81 ConcurrentMarkSweepThread(CMSCollector* collector);
a61af66fc99e Initial load
duke
parents:
diff changeset
82
a61af66fc99e Initial load
duke
parents:
diff changeset
83 static void makeSurrogateLockerThread(TRAPS);
a61af66fc99e Initial load
duke
parents:
diff changeset
84 static SurrogateLockerThread* slt() { return _slt; }
a61af66fc99e Initial load
duke
parents:
diff changeset
85
a61af66fc99e Initial load
duke
parents:
diff changeset
86 // Tester
a61af66fc99e Initial load
duke
parents:
diff changeset
87 bool is_ConcurrentGC_thread() const { return true; }
a61af66fc99e Initial load
duke
parents:
diff changeset
88
a61af66fc99e Initial load
duke
parents:
diff changeset
89 static void threads_do(ThreadClosure* tc);
a61af66fc99e Initial load
duke
parents:
diff changeset
90
a61af66fc99e Initial load
duke
parents:
diff changeset
91 // Printing
a61af66fc99e Initial load
duke
parents:
diff changeset
92 void print_on(outputStream* st) const;
a61af66fc99e Initial load
duke
parents:
diff changeset
93 void print() const { print_on(tty); }
a61af66fc99e Initial load
duke
parents:
diff changeset
94 static void print_all_on(outputStream* st);
a61af66fc99e Initial load
duke
parents:
diff changeset
95 static void print_all() { print_all_on(tty); }
a61af66fc99e Initial load
duke
parents:
diff changeset
96
a61af66fc99e Initial load
duke
parents:
diff changeset
97 // Returns the CMS Thread
a61af66fc99e Initial load
duke
parents:
diff changeset
98 static ConcurrentMarkSweepThread* cmst() { return _cmst; }
a61af66fc99e Initial load
duke
parents:
diff changeset
99 static CMSCollector* collector() { return _collector; }
a61af66fc99e Initial load
duke
parents:
diff changeset
100
a61af66fc99e Initial load
duke
parents:
diff changeset
101 // Create and start the CMS Thread, or stop it on shutdown
a61af66fc99e Initial load
duke
parents:
diff changeset
102 static ConcurrentMarkSweepThread* start(CMSCollector* collector);
a61af66fc99e Initial load
duke
parents:
diff changeset
103 static void stop();
a61af66fc99e Initial load
duke
parents:
diff changeset
104 static bool should_terminate() { return _should_terminate; }
a61af66fc99e Initial load
duke
parents:
diff changeset
105
a61af66fc99e Initial load
duke
parents:
diff changeset
106 // Synchronization using CMS token
a61af66fc99e Initial load
duke
parents:
diff changeset
107 static void synchronize(bool is_cms_thread);
a61af66fc99e Initial load
duke
parents:
diff changeset
108 static void desynchronize(bool is_cms_thread);
a61af66fc99e Initial load
duke
parents:
diff changeset
109 static bool vm_thread_has_cms_token() {
a61af66fc99e Initial load
duke
parents:
diff changeset
110 return CMS_flag_is_set(CMS_vm_has_token);
a61af66fc99e Initial load
duke
parents:
diff changeset
111 }
a61af66fc99e Initial load
duke
parents:
diff changeset
112 static bool cms_thread_has_cms_token() {
a61af66fc99e Initial load
duke
parents:
diff changeset
113 return CMS_flag_is_set(CMS_cms_has_token);
a61af66fc99e Initial load
duke
parents:
diff changeset
114 }
a61af66fc99e Initial load
duke
parents:
diff changeset
115 static bool vm_thread_wants_cms_token() {
a61af66fc99e Initial load
duke
parents:
diff changeset
116 return CMS_flag_is_set(CMS_vm_wants_token);
a61af66fc99e Initial load
duke
parents:
diff changeset
117 }
a61af66fc99e Initial load
duke
parents:
diff changeset
118 static bool cms_thread_wants_cms_token() {
a61af66fc99e Initial load
duke
parents:
diff changeset
119 return CMS_flag_is_set(CMS_cms_wants_token);
a61af66fc99e Initial load
duke
parents:
diff changeset
120 }
a61af66fc99e Initial load
duke
parents:
diff changeset
121
a61af66fc99e Initial load
duke
parents:
diff changeset
122 // Wait on CMS lock until the next synchronous GC
a61af66fc99e Initial load
duke
parents:
diff changeset
123 // or given timeout, whichever is earlier.
a61af66fc99e Initial load
duke
parents:
diff changeset
124 void wait_on_cms_lock(long t); // milliseconds
a61af66fc99e Initial load
duke
parents:
diff changeset
125
a61af66fc99e Initial load
duke
parents:
diff changeset
126 // The CMS thread will yield during the work portion of it's cycle
a61af66fc99e Initial load
duke
parents:
diff changeset
127 // only when requested to. Both synchronous and asychronous requests
a61af66fc99e Initial load
duke
parents:
diff changeset
128 // are provided. A synchronous request is used for young gen
a61af66fc99e Initial load
duke
parents:
diff changeset
129 // collections and direct allocations. The requesting thread increments
a61af66fc99e Initial load
duke
parents:
diff changeset
130 // pending_yields at the beginning of an operation, and decrements it when
a61af66fc99e Initial load
duke
parents:
diff changeset
131 // the operation is completed. The CMS thread yields when pending_yields
a61af66fc99e Initial load
duke
parents:
diff changeset
132 // is positive. An asynchronous request is used by iCMS in the stop_icms()
a61af66fc99e Initial load
duke
parents:
diff changeset
133 // operation. A single yield satisfies the outstanding asynch yield requests.
a61af66fc99e Initial load
duke
parents:
diff changeset
134 // The requesting thread increments both pending_yields and pending_decrements.
a61af66fc99e Initial load
duke
parents:
diff changeset
135 // After yielding, the CMS thread decrements both by the amount in
a61af66fc99e Initial load
duke
parents:
diff changeset
136 // pending_decrements.
a61af66fc99e Initial load
duke
parents:
diff changeset
137 // Note that, while "_pending_yields >= _pending_decrements" is an invariant,
a61af66fc99e Initial load
duke
parents:
diff changeset
138 // we cannot easily test that invariant, since the counters are manipulated via
a61af66fc99e Initial load
duke
parents:
diff changeset
139 // atomic instructions without explicit locking and we cannot read
a61af66fc99e Initial load
duke
parents:
diff changeset
140 // the two counters atomically together: one suggestion is to
a61af66fc99e Initial load
duke
parents:
diff changeset
141 // use (for example) 16-bit counters so as to be able to read the
a61af66fc99e Initial load
duke
parents:
diff changeset
142 // two counters atomically even on 32-bit platforms. Notice that
a61af66fc99e Initial load
duke
parents:
diff changeset
143 // the second assert in acknowledge_yield_request() does indeed
a61af66fc99e Initial load
duke
parents:
diff changeset
144 // check a form of the above invariant, albeit indirectly.
a61af66fc99e Initial load
duke
parents:
diff changeset
145
a61af66fc99e Initial load
duke
parents:
diff changeset
146 static void increment_pending_yields() {
a61af66fc99e Initial load
duke
parents:
diff changeset
147 Atomic::inc(&_pending_yields);
a61af66fc99e Initial load
duke
parents:
diff changeset
148 assert(_pending_yields >= 0, "can't be negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
149 }
a61af66fc99e Initial load
duke
parents:
diff changeset
150 static void decrement_pending_yields() {
a61af66fc99e Initial load
duke
parents:
diff changeset
151 Atomic::dec(&_pending_yields);
a61af66fc99e Initial load
duke
parents:
diff changeset
152 assert(_pending_yields >= 0, "can't be negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
153 }
a61af66fc99e Initial load
duke
parents:
diff changeset
154 static void asynchronous_yield_request() {
a61af66fc99e Initial load
duke
parents:
diff changeset
155 increment_pending_yields();
a61af66fc99e Initial load
duke
parents:
diff changeset
156 Atomic::inc(&_pending_decrements);
a61af66fc99e Initial load
duke
parents:
diff changeset
157 assert(_pending_decrements >= 0, "can't be negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
158 }
a61af66fc99e Initial load
duke
parents:
diff changeset
159 static void acknowledge_yield_request() {
a61af66fc99e Initial load
duke
parents:
diff changeset
160 jint decrement = _pending_decrements;
a61af66fc99e Initial load
duke
parents:
diff changeset
161 if (decrement > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
162 // Order important to preserve: _pending_yields >= _pending_decrements
a61af66fc99e Initial load
duke
parents:
diff changeset
163 Atomic::add(-decrement, &_pending_decrements);
a61af66fc99e Initial load
duke
parents:
diff changeset
164 Atomic::add(-decrement, &_pending_yields);
a61af66fc99e Initial load
duke
parents:
diff changeset
165 assert(_pending_decrements >= 0, "can't be negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
166 assert(_pending_yields >= 0, "can't be negative");
a61af66fc99e Initial load
duke
parents:
diff changeset
167 }
a61af66fc99e Initial load
duke
parents:
diff changeset
168 }
a61af66fc99e Initial load
duke
parents:
diff changeset
169 static bool should_yield() { return _pending_yields > 0; }
a61af66fc99e Initial load
duke
parents:
diff changeset
170
a61af66fc99e Initial load
duke
parents:
diff changeset
171 // CMS incremental mode.
a61af66fc99e Initial load
duke
parents:
diff changeset
172 static void start_icms(); // notify thread to start a quantum of work
a61af66fc99e Initial load
duke
parents:
diff changeset
173 static void stop_icms(); // request thread to stop working
a61af66fc99e Initial load
duke
parents:
diff changeset
174 void icms_wait(); // if asked to stop, wait until notified to start
a61af66fc99e Initial load
duke
parents:
diff changeset
175
a61af66fc99e Initial load
duke
parents:
diff changeset
176 // Incremental mode is enabled globally by the flag CMSIncrementalMode. It
a61af66fc99e Initial load
duke
parents:
diff changeset
177 // must also be enabled/disabled dynamically to allow foreground collections.
a61af66fc99e Initial load
duke
parents:
diff changeset
178 static inline void enable_icms() { _icms_enabled = true; }
a61af66fc99e Initial load
duke
parents:
diff changeset
179 static inline void disable_icms() { _icms_enabled = false; }
a61af66fc99e Initial load
duke
parents:
diff changeset
180 static inline void set_icms_enabled(bool val) { _icms_enabled = val; }
a61af66fc99e Initial load
duke
parents:
diff changeset
181 static inline bool icms_enabled() { return _icms_enabled; }
a61af66fc99e Initial load
duke
parents:
diff changeset
182 };
a61af66fc99e Initial load
duke
parents:
diff changeset
183
a61af66fc99e Initial load
duke
parents:
diff changeset
184 inline void ConcurrentMarkSweepThread::trace_state(const char* desc) {
a61af66fc99e Initial load
duke
parents:
diff changeset
185 if (CMSTraceThreadState) {
a61af66fc99e Initial load
duke
parents:
diff changeset
186 char buf[128];
a61af66fc99e Initial load
duke
parents:
diff changeset
187 TimeStamp& ts = gclog_or_tty->time_stamp();
a61af66fc99e Initial load
duke
parents:
diff changeset
188 if (!ts.is_updated()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
189 ts.update();
a61af66fc99e Initial load
duke
parents:
diff changeset
190 }
a61af66fc99e Initial load
duke
parents:
diff changeset
191 jio_snprintf(buf, sizeof(buf), " [%.3f: CMSThread %s] ",
a61af66fc99e Initial load
duke
parents:
diff changeset
192 ts.seconds(), desc);
a61af66fc99e Initial load
duke
parents:
diff changeset
193 buf[sizeof(buf) - 1] = '\0';
a61af66fc99e Initial load
duke
parents:
diff changeset
194 gclog_or_tty->print(buf);
a61af66fc99e Initial load
duke
parents:
diff changeset
195 }
a61af66fc99e Initial load
duke
parents:
diff changeset
196 }
a61af66fc99e Initial load
duke
parents:
diff changeset
197
a61af66fc99e Initial load
duke
parents:
diff changeset
198 // For scoped increment/decrement of yield requests
a61af66fc99e Initial load
duke
parents:
diff changeset
199 class CMSSynchronousYieldRequest: public StackObj {
a61af66fc99e Initial load
duke
parents:
diff changeset
200 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
201 CMSSynchronousYieldRequest() {
a61af66fc99e Initial load
duke
parents:
diff changeset
202 ConcurrentMarkSweepThread::increment_pending_yields();
a61af66fc99e Initial load
duke
parents:
diff changeset
203 }
a61af66fc99e Initial load
duke
parents:
diff changeset
204 ~CMSSynchronousYieldRequest() {
a61af66fc99e Initial load
duke
parents:
diff changeset
205 ConcurrentMarkSweepThread::decrement_pending_yields();
a61af66fc99e Initial load
duke
parents:
diff changeset
206 }
a61af66fc99e Initial load
duke
parents:
diff changeset
207 };
a61af66fc99e Initial load
duke
parents:
diff changeset
208
a61af66fc99e Initial load
duke
parents:
diff changeset
209 // Used to emit a warning in case of unexpectedly excessive
a61af66fc99e Initial load
duke
parents:
diff changeset
210 // looping (in "apparently endless loops") in CMS code.
a61af66fc99e Initial load
duke
parents:
diff changeset
211 class CMSLoopCountWarn: public StackObj {
a61af66fc99e Initial load
duke
parents:
diff changeset
212 private:
a61af66fc99e Initial load
duke
parents:
diff changeset
213 const char* _src;
a61af66fc99e Initial load
duke
parents:
diff changeset
214 const char* _msg;
a61af66fc99e Initial load
duke
parents:
diff changeset
215 const intx _threshold;
a61af66fc99e Initial load
duke
parents:
diff changeset
216 intx _ticks;
a61af66fc99e Initial load
duke
parents:
diff changeset
217
a61af66fc99e Initial load
duke
parents:
diff changeset
218 public:
a61af66fc99e Initial load
duke
parents:
diff changeset
219 inline CMSLoopCountWarn(const char* src, const char* msg,
a61af66fc99e Initial load
duke
parents:
diff changeset
220 const intx threshold) :
a61af66fc99e Initial load
duke
parents:
diff changeset
221 _src(src), _msg(msg), _threshold(threshold), _ticks(0) { }
a61af66fc99e Initial load
duke
parents:
diff changeset
222
a61af66fc99e Initial load
duke
parents:
diff changeset
223 inline void tick() {
a61af66fc99e Initial load
duke
parents:
diff changeset
224 _ticks++;
a61af66fc99e Initial load
duke
parents:
diff changeset
225 if (CMSLoopWarn && _ticks % _threshold == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
226 warning("%s has looped %d times %s", _src, _ticks, _msg);
a61af66fc99e Initial load
duke
parents:
diff changeset
227 }
a61af66fc99e Initial load
duke
parents:
diff changeset
228 }
a61af66fc99e Initial load
duke
parents:
diff changeset
229 };