1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Wed Apr 27 01:25:04 2016 +0800 1.3 @@ -0,0 +1,281 @@ 1.4 +/* 1.5 + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPTHREAD_HPP 1.29 +#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPTHREAD_HPP 1.30 + 1.31 +#include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" 1.32 +#include "gc_implementation/shared/concurrentGCThread.hpp" 1.33 +#include "runtime/thread.inline.hpp" 1.34 + 1.35 +class ConcurrentMarkSweepGeneration; 1.36 +class CMSCollector; 1.37 + 1.38 +// The Concurrent Mark Sweep GC Thread 1.39 +class ConcurrentMarkSweepThread: public ConcurrentGCThread { 1.40 + friend class VMStructs; 1.41 + friend class ConcurrentMarkSweepGeneration; // XXX should remove friendship 1.42 + friend class CMSCollector; 1.43 + public: 1.44 + virtual void run(); 1.45 + 1.46 + private: 1.47 + static ConcurrentMarkSweepThread* _cmst; 1.48 + static CMSCollector* _collector; 1.49 + static SurrogateLockerThread* _slt; 1.50 + static SurrogateLockerThread::SLT_msg_type _sltBuffer; 1.51 + static Monitor* _sltMonitor; 1.52 + 1.53 + static bool _should_terminate; 1.54 + 1.55 + enum CMS_flag_type { 1.56 + CMS_nil = NoBits, 1.57 + CMS_cms_wants_token = nth_bit(0), 1.58 + CMS_cms_has_token = nth_bit(1), 1.59 + CMS_vm_wants_token = nth_bit(2), 1.60 + CMS_vm_has_token = nth_bit(3) 1.61 + }; 1.62 + 1.63 + static int _CMS_flag; 1.64 + 1.65 + static bool CMS_flag_is_set(int b) { return (_CMS_flag & b) != 0; } 1.66 + static bool set_CMS_flag(int b) { return (_CMS_flag |= b) != 0; } 1.67 + static bool clear_CMS_flag(int b) { return (_CMS_flag &= ~b) != 0; } 1.68 + void sleepBeforeNextCycle(); 1.69 + 1.70 + // CMS thread should yield for a young gen collection, direct allocation, 1.71 + // and iCMS activity. 1.72 + static char _pad_1[64 - sizeof(jint)]; // prevent cache-line sharing 1.73 + static volatile jint _pending_yields; 1.74 + static volatile jint _pending_decrements; // decrements to _pending_yields 1.75 + static char _pad_2[64 - sizeof(jint)]; // prevent cache-line sharing 1.76 + 1.77 + // Tracing messages, enabled by CMSTraceThreadState. 1.78 + static inline void trace_state(const char* desc); 1.79 + 1.80 + static volatile int _icms_disabled; // a counter to track #iCMS disable & enable 1.81 + static volatile bool _should_run; // iCMS may run 1.82 + static volatile bool _should_stop; // iCMS should stop 1.83 + 1.84 + // debugging 1.85 + void verify_ok_to_terminate() const PRODUCT_RETURN; 1.86 + 1.87 + public: 1.88 + // Constructor 1.89 + ConcurrentMarkSweepThread(CMSCollector* collector); 1.90 + 1.91 + static void makeSurrogateLockerThread(TRAPS); 1.92 + static SurrogateLockerThread* slt() { return _slt; } 1.93 + 1.94 + // Tester 1.95 + bool is_ConcurrentGC_thread() const { return true; } 1.96 + 1.97 + static void threads_do(ThreadClosure* tc); 1.98 + 1.99 + // Printing 1.100 + void print_on(outputStream* st) const; 1.101 + void print() const { print_on(tty); } 1.102 + static void print_all_on(outputStream* st); 1.103 + static void print_all() { print_all_on(tty); } 1.104 + 1.105 + // Returns the CMS Thread 1.106 + static ConcurrentMarkSweepThread* cmst() { return _cmst; } 1.107 + static CMSCollector* collector() { return _collector; } 1.108 + 1.109 + // Create and start the CMS Thread, or stop it on shutdown 1.110 + static ConcurrentMarkSweepThread* start(CMSCollector* collector); 1.111 + static void stop(); 1.112 + static bool should_terminate() { return _should_terminate; } 1.113 + 1.114 + // Synchronization using CMS token 1.115 + static void synchronize(bool is_cms_thread); 1.116 + static void desynchronize(bool is_cms_thread); 1.117 + static bool vm_thread_has_cms_token() { 1.118 + return CMS_flag_is_set(CMS_vm_has_token); 1.119 + } 1.120 + static bool cms_thread_has_cms_token() { 1.121 + return CMS_flag_is_set(CMS_cms_has_token); 1.122 + } 1.123 + static bool vm_thread_wants_cms_token() { 1.124 + return CMS_flag_is_set(CMS_vm_wants_token); 1.125 + } 1.126 + static bool cms_thread_wants_cms_token() { 1.127 + return CMS_flag_is_set(CMS_cms_wants_token); 1.128 + } 1.129 + 1.130 + // Wait on CMS lock until the next synchronous GC 1.131 + // or given timeout, whichever is earlier. A timeout value 1.132 + // of 0 indicates that there is no upper bound on the wait time. 1.133 + // A concurrent full gc request terminates the wait. 1.134 + void wait_on_cms_lock(long t_millis); 1.135 + 1.136 + // Wait on CMS lock until the next synchronous GC 1.137 + // or given timeout, whichever is earlier. A timeout value 1.138 + // of 0 indicates that there is no upper bound on the wait time. 1.139 + // A concurrent full gc request terminates the wait. 1.140 + void wait_on_cms_lock_for_scavenge(long t_millis); 1.141 + 1.142 + // The CMS thread will yield during the work portion of its cycle 1.143 + // only when requested to. Both synchronous and asychronous requests 1.144 + // are provided: 1.145 + // (1) A synchronous request is used for young gen collections and 1.146 + // for direct allocations. The requesting thread increments 1.147 + // _pending_yields at the beginning of an operation, and decrements 1.148 + // _pending_yields when that operation is completed. 1.149 + // In turn, the CMS thread yields when _pending_yields is positive, 1.150 + // and continues to yield until the value reverts to 0. 1.151 + // (2) An asynchronous request, on the other hand, is used by iCMS 1.152 + // for the stop_icms() operation. A single yield satisfies all of 1.153 + // the outstanding asynch yield requests, of which there may 1.154 + // occasionally be several in close succession. To accomplish 1.155 + // this, an asynch-requesting thread atomically increments both 1.156 + // _pending_yields and _pending_decrements. An asynchr requesting 1.157 + // thread does not wait and "acknowledge" completion of an operation 1.158 + // and deregister the request, like the synchronous version described 1.159 + // above does. In turn, after yielding, the CMS thread decrements both 1.160 + // _pending_yields and _pending_decrements by the value seen in 1.161 + // _pending_decrements before the decrement. 1.162 + // NOTE: The above scheme is isomorphic to having two request counters, 1.163 + // one for async requests and one for sync requests, and for the CMS thread 1.164 + // to check the sum of the two counters to decide whether it should yield 1.165 + // and to clear only the async counter when it yields. However, it turns out 1.166 + // to be more efficient for CMS code to just check a single counter 1.167 + // _pending_yields that holds the sum (of both sync and async requests), and 1.168 + // a second counter _pending_decrements that only holds the async requests, 1.169 + // for greater efficiency, since in a typical CMS run, there are many more 1.170 + // pontential (i.e. static) yield points than there are actual 1.171 + // (i.e. dynamic) yields because of requests, which are few and far between. 1.172 + // 1.173 + // Note that, while "_pending_yields >= _pending_decrements" is an invariant, 1.174 + // we cannot easily test that invariant, since the counters are manipulated via 1.175 + // atomic instructions without explicit locking and we cannot read 1.176 + // the two counters atomically together: one suggestion is to 1.177 + // use (for example) 16-bit counters so as to be able to read the 1.178 + // two counters atomically even on 32-bit platforms. Notice that 1.179 + // the second assert in acknowledge_yield_request() below does indeed 1.180 + // check a form of the above invariant, albeit indirectly. 1.181 + 1.182 + static void increment_pending_yields() { 1.183 + Atomic::inc(&_pending_yields); 1.184 + assert(_pending_yields >= 0, "can't be negative"); 1.185 + } 1.186 + static void decrement_pending_yields() { 1.187 + Atomic::dec(&_pending_yields); 1.188 + assert(_pending_yields >= 0, "can't be negative"); 1.189 + } 1.190 + static void asynchronous_yield_request() { 1.191 + assert(CMSIncrementalMode, "Currently only used w/iCMS"); 1.192 + increment_pending_yields(); 1.193 + Atomic::inc(&_pending_decrements); 1.194 + assert(_pending_decrements >= 0, "can't be negative"); 1.195 + } 1.196 + static void acknowledge_yield_request() { 1.197 + jint decrement = _pending_decrements; 1.198 + if (decrement > 0) { 1.199 + assert(CMSIncrementalMode, "Currently only used w/iCMS"); 1.200 + // Order important to preserve: _pending_yields >= _pending_decrements 1.201 + Atomic::add(-decrement, &_pending_decrements); 1.202 + Atomic::add(-decrement, &_pending_yields); 1.203 + assert(_pending_decrements >= 0, "can't be negative"); 1.204 + assert(_pending_yields >= 0, "can't be negative"); 1.205 + } 1.206 + } 1.207 + static bool should_yield() { return _pending_yields > 0; } 1.208 + 1.209 + // CMS incremental mode. 1.210 + static void start_icms(); // notify thread to start a quantum of work 1.211 + static void stop_icms(); // request thread to stop working 1.212 + void icms_wait(); // if asked to stop, wait until notified to start 1.213 + 1.214 + // Incremental mode is enabled globally by the flag CMSIncrementalMode. It 1.215 + // must also be enabled/disabled dynamically to allow foreground collections. 1.216 +#define ICMS_ENABLING_ASSERT \ 1.217 + assert((CMSIncrementalMode && _icms_disabled >= 0) || \ 1.218 + (!CMSIncrementalMode && _icms_disabled <= 0), "Error") 1.219 + 1.220 + static inline void enable_icms() { 1.221 + ICMS_ENABLING_ASSERT; 1.222 + Atomic::dec(&_icms_disabled); 1.223 + } 1.224 + static inline void disable_icms() { 1.225 + ICMS_ENABLING_ASSERT; 1.226 + Atomic::inc(&_icms_disabled); 1.227 + } 1.228 + static inline bool icms_is_disabled() { 1.229 + ICMS_ENABLING_ASSERT; 1.230 + return _icms_disabled > 0; 1.231 + } 1.232 + static inline bool icms_is_enabled() { 1.233 + return !icms_is_disabled(); 1.234 + } 1.235 +}; 1.236 + 1.237 +inline void ConcurrentMarkSweepThread::trace_state(const char* desc) { 1.238 + if (CMSTraceThreadState) { 1.239 + char buf[128]; 1.240 + TimeStamp& ts = gclog_or_tty->time_stamp(); 1.241 + if (!ts.is_updated()) { 1.242 + ts.update(); 1.243 + } 1.244 + jio_snprintf(buf, sizeof(buf), " [%.3f: CMSThread %s] ", 1.245 + ts.seconds(), desc); 1.246 + buf[sizeof(buf) - 1] = '\0'; 1.247 + gclog_or_tty->print("%s", buf); 1.248 + } 1.249 +} 1.250 + 1.251 +// For scoped increment/decrement of (synchronous) yield requests 1.252 +class CMSSynchronousYieldRequest: public StackObj { 1.253 + public: 1.254 + CMSSynchronousYieldRequest() { 1.255 + ConcurrentMarkSweepThread::increment_pending_yields(); 1.256 + } 1.257 + ~CMSSynchronousYieldRequest() { 1.258 + ConcurrentMarkSweepThread::decrement_pending_yields(); 1.259 + } 1.260 +}; 1.261 + 1.262 +// Used to emit a warning in case of unexpectedly excessive 1.263 +// looping (in "apparently endless loops") in CMS code. 1.264 +class CMSLoopCountWarn: public StackObj { 1.265 + private: 1.266 + const char* _src; 1.267 + const char* _msg; 1.268 + const intx _threshold; 1.269 + intx _ticks; 1.270 + 1.271 + public: 1.272 + inline CMSLoopCountWarn(const char* src, const char* msg, 1.273 + const intx threshold) : 1.274 + _src(src), _msg(msg), _threshold(threshold), _ticks(0) { } 1.275 + 1.276 + inline void tick() { 1.277 + _ticks++; 1.278 + if (CMSLoopWarn && _ticks % _threshold == 0) { 1.279 + warning("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg); 1.280 + } 1.281 + } 1.282 +}; 1.283 + 1.284 +#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPTHREAD_HPP