| 1 | /* |
| 2 | * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_SERVICES_THREADSERVICE_HPP |
| 26 | #define SHARE_SERVICES_THREADSERVICE_HPP |
| 27 | |
| 28 | #include "classfile/javaClasses.hpp" |
| 29 | #include "runtime/handles.hpp" |
| 30 | #include "runtime/init.hpp" |
| 31 | #include "runtime/jniHandles.hpp" |
| 32 | #include "runtime/objectMonitor.hpp" |
| 33 | #include "runtime/perfData.hpp" |
| 34 | #include "runtime/safepoint.hpp" |
| 35 | #include "runtime/thread.hpp" |
| 36 | #include "runtime/threadSMR.hpp" |
| 37 | #include "services/management.hpp" |
| 38 | |
| 39 | class OopClosure; |
| 40 | class ThreadDumpResult; |
| 41 | class ThreadStackTrace; |
| 42 | class ThreadSnapshot; |
| 43 | class StackFrameInfo; |
| 44 | class ThreadConcurrentLocks; |
| 45 | class DeadlockCycle; |
| 46 | |
| 47 | // VM monitoring and management support for the thread and |
| 48 | // synchronization subsystem |
| 49 | // |
| 50 | // Thread contention monitoring is disabled by default. |
| 51 | // When enabled, the VM will begin measuring the accumulated |
| 52 | // elapsed time a thread blocked on synchronization. |
| 53 | // |
| 54 | class ThreadService : public AllStatic { |
| 55 | private: |
| 56 | // These counters could be moved to Threads class |
| 57 | static PerfCounter* _total_threads_count; |
| 58 | static PerfVariable* _live_threads_count; |
| 59 | static PerfVariable* _peak_threads_count; |
| 60 | static PerfVariable* _daemon_threads_count; |
| 61 | |
| 62 | // These 2 counters are like the above thread counts, but are |
| 63 | // atomically decremented in ThreadService::current_thread_exiting instead of |
| 64 | // ThreadService::remove_thread, so that the thread count is updated before |
| 65 | // Thread.join() returns. |
| 66 | static volatile int _atomic_threads_count; |
| 67 | static volatile int _atomic_daemon_threads_count; |
| 68 | |
| 69 | static bool _thread_monitoring_contention_enabled; |
| 70 | static bool _thread_cpu_time_enabled; |
| 71 | static bool _thread_allocated_memory_enabled; |
| 72 | |
| 73 | // Need to keep the list of thread dump result that |
| 74 | // keep references to Method* since thread dump can be |
| 75 | // requested by multiple threads concurrently. |
| 76 | static ThreadDumpResult* _threaddump_list; |
| 77 | |
| 78 | static void decrement_thread_counts(JavaThread* jt, bool daemon); |
| 79 | |
| 80 | public: |
| 81 | static void init(); |
| 82 | static void add_thread(JavaThread* thread, bool daemon); |
| 83 | static void remove_thread(JavaThread* thread, bool daemon); |
| 84 | static void current_thread_exiting(JavaThread* jt, bool daemon); |
| 85 | |
| 86 | static bool set_thread_monitoring_contention(bool flag); |
| 87 | static bool is_thread_monitoring_contention() { return _thread_monitoring_contention_enabled; } |
| 88 | |
| 89 | static bool set_thread_cpu_time_enabled(bool flag); |
| 90 | static bool is_thread_cpu_time_enabled() { return _thread_cpu_time_enabled; } |
| 91 | |
| 92 | static bool set_thread_allocated_memory_enabled(bool flag); |
| 93 | static bool is_thread_allocated_memory_enabled() { return _thread_allocated_memory_enabled; } |
| 94 | |
| 95 | static jlong get_total_thread_count() { return _total_threads_count->get_value(); } |
| 96 | static jlong get_peak_thread_count() { return _peak_threads_count->get_value(); } |
| 97 | static jlong get_live_thread_count() { return _atomic_threads_count; } |
| 98 | static jlong get_daemon_thread_count() { return _atomic_daemon_threads_count; } |
| 99 | |
| 100 | // Support for thread dump |
| 101 | static void add_thread_dump(ThreadDumpResult* dump); |
| 102 | static void remove_thread_dump(ThreadDumpResult* dump); |
| 103 | |
| 104 | static Handle get_current_contended_monitor(JavaThread* thread); |
| 105 | |
| 106 | // This function is called by JVM_DumpThreads. |
| 107 | static Handle dump_stack_traces(GrowableArray<instanceHandle>* threads, |
| 108 | int num_threads, TRAPS); |
| 109 | |
| 110 | static void reset_peak_thread_count(); |
| 111 | static void reset_contention_count_stat(JavaThread* thread); |
| 112 | static void reset_contention_time_stat(JavaThread* thread); |
| 113 | |
| 114 | static DeadlockCycle* find_deadlocks_at_safepoint(ThreadsList * t_list, bool object_monitors_only); |
| 115 | |
| 116 | // GC support |
| 117 | static void oops_do(OopClosure* f); |
| 118 | static void metadata_do(void f(Metadata*)); |
| 119 | }; |
| 120 | |
| 121 | // Per-thread Statistics for synchronization |
| 122 | class ThreadStatistics : public CHeapObj<mtInternal> { |
| 123 | private: |
| 124 | // The following contention statistics are only updated by |
| 125 | // the thread owning these statistics when contention occurs. |
| 126 | |
| 127 | jlong _contended_enter_count; |
| 128 | elapsedTimer _contended_enter_timer; |
| 129 | jlong _monitor_wait_count; |
| 130 | elapsedTimer _monitor_wait_timer; |
| 131 | jlong _sleep_count; |
| 132 | elapsedTimer _sleep_timer; |
| 133 | |
| 134 | |
| 135 | // These two reset flags are set to true when another thread |
| 136 | // requests to reset the statistics. The actual statistics |
| 137 | // are reset when the thread contention occurs and attempts |
| 138 | // to update the statistics. |
| 139 | bool _count_pending_reset; |
| 140 | bool _timer_pending_reset; |
| 141 | |
| 142 | // Keep accurate times for potentially recursive class operations |
| 143 | int _perf_recursion_counts[6]; |
| 144 | elapsedTimer _perf_timers[6]; |
| 145 | |
| 146 | // utility functions |
| 147 | void check_and_reset_count() { |
| 148 | if (!_count_pending_reset) return; |
| 149 | _contended_enter_count = 0; |
| 150 | _monitor_wait_count = 0; |
| 151 | _sleep_count = 0; |
| 152 | _count_pending_reset = 0; |
| 153 | } |
| 154 | void check_and_reset_timer() { |
| 155 | if (!_timer_pending_reset) return; |
| 156 | _contended_enter_timer.reset(); |
| 157 | _monitor_wait_timer.reset(); |
| 158 | _sleep_timer.reset(); |
| 159 | _timer_pending_reset = 0; |
| 160 | } |
| 161 | |
| 162 | public: |
| 163 | ThreadStatistics(); |
| 164 | |
| 165 | jlong contended_enter_count() { return (_count_pending_reset ? 0 : _contended_enter_count); } |
| 166 | jlong contended_enter_ticks() { return (_timer_pending_reset ? 0 : _contended_enter_timer.active_ticks()); } |
| 167 | jlong monitor_wait_count() { return (_count_pending_reset ? 0 : _monitor_wait_count); } |
| 168 | jlong monitor_wait_ticks() { return (_timer_pending_reset ? 0 : _monitor_wait_timer.active_ticks()); } |
| 169 | jlong sleep_count() { return (_count_pending_reset ? 0 : _sleep_count); } |
| 170 | jlong sleep_ticks() { return (_timer_pending_reset ? 0 : _sleep_timer.active_ticks()); } |
| 171 | |
| 172 | void monitor_wait() { check_and_reset_count(); _monitor_wait_count++; } |
| 173 | void monitor_wait_begin() { check_and_reset_timer(); _monitor_wait_timer.start(); } |
| 174 | void monitor_wait_end() { _monitor_wait_timer.stop(); check_and_reset_timer(); } |
| 175 | |
| 176 | void thread_sleep() { check_and_reset_count(); _sleep_count++; } |
| 177 | void thread_sleep_begin() { check_and_reset_timer(); _sleep_timer.start(); } |
| 178 | void thread_sleep_end() { _sleep_timer.stop(); check_and_reset_timer(); } |
| 179 | |
| 180 | void contended_enter() { check_and_reset_count(); _contended_enter_count++; } |
| 181 | void contended_enter_begin() { check_and_reset_timer(); _contended_enter_timer.start(); } |
| 182 | void contended_enter_end() { _contended_enter_timer.stop(); check_and_reset_timer(); } |
| 183 | |
| 184 | void reset_count_stat() { _count_pending_reset = true; } |
| 185 | void reset_time_stat() { _timer_pending_reset = true; } |
| 186 | |
| 187 | int* perf_recursion_counts_addr() { return _perf_recursion_counts; } |
| 188 | elapsedTimer* perf_timers_addr() { return _perf_timers; } |
| 189 | }; |
| 190 | |
| 191 | // Thread snapshot to represent the thread state and statistics |
| 192 | class ThreadSnapshot : public CHeapObj<mtInternal> { |
| 193 | private: |
| 194 | // This JavaThread* is protected by being stored in objects that are |
| 195 | // protected by a ThreadsListSetter (ThreadDumpResult). |
| 196 | JavaThread* _thread; |
| 197 | oop _threadObj; |
| 198 | java_lang_Thread::ThreadStatus _thread_status; |
| 199 | |
| 200 | bool _is_ext_suspended; |
| 201 | bool _is_in_native; |
| 202 | |
| 203 | jlong _contended_enter_ticks; |
| 204 | jlong _contended_enter_count; |
| 205 | jlong _monitor_wait_ticks; |
| 206 | jlong _monitor_wait_count; |
| 207 | jlong _sleep_ticks; |
| 208 | jlong _sleep_count; |
| 209 | oop _blocker_object; |
| 210 | oop _blocker_object_owner; |
| 211 | |
| 212 | ThreadStackTrace* _stack_trace; |
| 213 | ThreadConcurrentLocks* _concurrent_locks; |
| 214 | ThreadSnapshot* _next; |
| 215 | |
| 216 | // ThreadSnapshot instances should only be created via |
| 217 | // ThreadDumpResult::add_thread_snapshot. |
| 218 | friend class ThreadDumpResult; |
| 219 | ThreadSnapshot() : _thread(NULL), _threadObj(NULL), |
| 220 | _blocker_object(NULL), _blocker_object_owner(NULL), |
| 221 | _stack_trace(NULL), _concurrent_locks(NULL), _next(NULL) {}; |
| 222 | void initialize(ThreadsList * t_list, JavaThread* thread); |
| 223 | |
| 224 | public: |
| 225 | ~ThreadSnapshot(); |
| 226 | |
| 227 | java_lang_Thread::ThreadStatus thread_status() { return _thread_status; } |
| 228 | |
| 229 | oop threadObj() const { return _threadObj; } |
| 230 | |
| 231 | void set_next(ThreadSnapshot* n) { _next = n; } |
| 232 | |
| 233 | bool is_ext_suspended() { return _is_ext_suspended; } |
| 234 | bool is_in_native() { return _is_in_native; } |
| 235 | |
| 236 | jlong contended_enter_count() { return _contended_enter_count; } |
| 237 | jlong contended_enter_ticks() { return _contended_enter_ticks; } |
| 238 | jlong monitor_wait_count() { return _monitor_wait_count; } |
| 239 | jlong monitor_wait_ticks() { return _monitor_wait_ticks; } |
| 240 | jlong sleep_count() { return _sleep_count; } |
| 241 | jlong sleep_ticks() { return _sleep_ticks; } |
| 242 | |
| 243 | |
| 244 | oop blocker_object() { return _blocker_object; } |
| 245 | oop blocker_object_owner() { return _blocker_object_owner; } |
| 246 | |
| 247 | ThreadSnapshot* next() const { return _next; } |
| 248 | ThreadStackTrace* get_stack_trace() { return _stack_trace; } |
| 249 | ThreadConcurrentLocks* get_concurrent_locks() { return _concurrent_locks; } |
| 250 | |
| 251 | void dump_stack_at_safepoint(int max_depth, bool with_locked_monitors); |
| 252 | void set_concurrent_locks(ThreadConcurrentLocks* l) { _concurrent_locks = l; } |
| 253 | void oops_do(OopClosure* f); |
| 254 | void metadata_do(void f(Metadata*)); |
| 255 | }; |
| 256 | |
| 257 | class ThreadStackTrace : public CHeapObj<mtInternal> { |
| 258 | private: |
| 259 | JavaThread* _thread; |
| 260 | int _depth; // number of stack frames added |
| 261 | bool _with_locked_monitors; |
| 262 | GrowableArray<StackFrameInfo*>* _frames; |
| 263 | GrowableArray<oop>* _jni_locked_monitors; |
| 264 | |
| 265 | public: |
| 266 | |
| 267 | ThreadStackTrace(JavaThread* thread, bool with_locked_monitors); |
| 268 | ~ThreadStackTrace(); |
| 269 | |
| 270 | JavaThread* thread() { return _thread; } |
| 271 | StackFrameInfo* stack_frame_at(int i) { return _frames->at(i); } |
| 272 | int get_stack_depth() { return _depth; } |
| 273 | |
| 274 | void add_stack_frame(javaVFrame* jvf); |
| 275 | void dump_stack_at_safepoint(int max_depth); |
| 276 | Handle allocate_fill_stack_trace_element_array(TRAPS); |
| 277 | void oops_do(OopClosure* f); |
| 278 | void metadata_do(void f(Metadata*)); |
| 279 | GrowableArray<oop>* jni_locked_monitors() { return _jni_locked_monitors; } |
| 280 | int num_jni_locked_monitors() { return (_jni_locked_monitors != NULL ? _jni_locked_monitors->length() : 0); } |
| 281 | |
| 282 | bool is_owned_monitor_on_stack(oop object); |
| 283 | void add_jni_locked_monitor(oop object) { _jni_locked_monitors->append(object); } |
| 284 | }; |
| 285 | |
| 286 | // StackFrameInfo for keeping Method* and bci during |
| 287 | // stack walking for later construction of StackTraceElement[] |
| 288 | // Java instances |
| 289 | class StackFrameInfo : public CHeapObj<mtInternal> { |
| 290 | private: |
| 291 | Method* _method; |
| 292 | int _bci; |
| 293 | GrowableArray<oop>* _locked_monitors; // list of object monitors locked by this frame |
| 294 | // We need to save the mirrors in the backtrace to keep the class |
| 295 | // from being unloaded while we still have this stack trace. |
| 296 | oop _class_holder; |
| 297 | |
| 298 | public: |
| 299 | |
| 300 | StackFrameInfo(javaVFrame* jvf, bool with_locked_monitors); |
| 301 | ~StackFrameInfo() { |
| 302 | if (_locked_monitors != NULL) { |
| 303 | delete _locked_monitors; |
| 304 | } |
| 305 | }; |
| 306 | Method* method() const { return _method; } |
| 307 | int bci() const { return _bci; } |
| 308 | void oops_do(OopClosure* f); |
| 309 | void metadata_do(void f(Metadata*)); |
| 310 | |
| 311 | int num_locked_monitors() { return (_locked_monitors != NULL ? _locked_monitors->length() : 0); } |
| 312 | GrowableArray<oop>* locked_monitors() { return _locked_monitors; } |
| 313 | |
| 314 | void print_on(outputStream* st) const; |
| 315 | }; |
| 316 | |
| 317 | class ThreadConcurrentLocks : public CHeapObj<mtInternal> { |
| 318 | private: |
| 319 | GrowableArray<instanceOop>* _owned_locks; |
| 320 | ThreadConcurrentLocks* _next; |
| 321 | // This JavaThread* is protected in one of two different ways |
| 322 | // depending on the usage of the ThreadConcurrentLocks object: |
| 323 | // 1) by being stored in objects that are only allocated and used at a |
| 324 | // safepoint (ConcurrentLocksDump), or 2) by being stored in objects |
| 325 | // that are protected by a ThreadsListSetter (ThreadSnapshot inside |
| 326 | // ThreadDumpResult). |
| 327 | JavaThread* _thread; |
| 328 | public: |
| 329 | ThreadConcurrentLocks(JavaThread* thread); |
| 330 | ~ThreadConcurrentLocks(); |
| 331 | |
| 332 | void add_lock(instanceOop o); |
| 333 | void set_next(ThreadConcurrentLocks* n) { _next = n; } |
| 334 | ThreadConcurrentLocks* next() { return _next; } |
| 335 | JavaThread* java_thread() { return _thread; } |
| 336 | GrowableArray<instanceOop>* owned_locks() { return _owned_locks; } |
| 337 | void oops_do(OopClosure* f); |
| 338 | }; |
| 339 | |
| 340 | class ConcurrentLocksDump : public StackObj { |
| 341 | private: |
| 342 | ThreadConcurrentLocks* _map; |
| 343 | ThreadConcurrentLocks* _last; // Last ThreadConcurrentLocks in the map |
| 344 | bool _retain_map_on_free; |
| 345 | |
| 346 | void build_map(GrowableArray<oop>* aos_objects); |
| 347 | void add_lock(JavaThread* thread, instanceOop o); |
| 348 | |
| 349 | public: |
| 350 | ConcurrentLocksDump(bool retain_map_on_free) : _map(NULL), _last(NULL), _retain_map_on_free(retain_map_on_free) { |
| 351 | assert(SafepointSynchronize::is_at_safepoint(), "Must be constructed at a safepoint." ); |
| 352 | }; |
| 353 | ConcurrentLocksDump() : _map(NULL), _last(NULL), _retain_map_on_free(false) { |
| 354 | assert(SafepointSynchronize::is_at_safepoint(), "Must be constructed at a safepoint." ); |
| 355 | }; |
| 356 | ~ConcurrentLocksDump(); |
| 357 | |
| 358 | void dump_at_safepoint(); |
| 359 | ThreadConcurrentLocks* thread_concurrent_locks(JavaThread* thread); |
| 360 | void print_locks_on(JavaThread* t, outputStream* st); |
| 361 | }; |
| 362 | |
| 363 | class ThreadDumpResult : public StackObj { |
| 364 | private: |
| 365 | int _num_threads; |
| 366 | int _num_snapshots; |
| 367 | ThreadSnapshot* _snapshots; |
| 368 | ThreadSnapshot* _last; |
| 369 | ThreadDumpResult* _next; |
| 370 | ThreadsListSetter _setter; // Helper to set hazard ptr in the originating thread |
| 371 | // which protects the JavaThreads in _snapshots. |
| 372 | |
| 373 | void link_thread_snapshot(ThreadSnapshot* ts); |
| 374 | |
| 375 | public: |
| 376 | ThreadDumpResult(); |
| 377 | ThreadDumpResult(int num_threads); |
| 378 | ~ThreadDumpResult(); |
| 379 | |
| 380 | ThreadSnapshot* add_thread_snapshot(); |
| 381 | ThreadSnapshot* add_thread_snapshot(JavaThread* thread); |
| 382 | |
| 383 | void set_next(ThreadDumpResult* next) { _next = next; } |
| 384 | ThreadDumpResult* next() { return _next; } |
| 385 | int num_threads() { return _num_threads; } |
| 386 | int num_snapshots() { return _num_snapshots; } |
| 387 | ThreadSnapshot* snapshots() { return _snapshots; } |
| 388 | void set_t_list() { _setter.set(); } |
| 389 | ThreadsList* t_list(); |
| 390 | bool t_list_has_been_set() { return _setter.is_set(); } |
| 391 | void oops_do(OopClosure* f); |
| 392 | void metadata_do(void f(Metadata*)); |
| 393 | }; |
| 394 | |
| 395 | class DeadlockCycle : public CHeapObj<mtInternal> { |
| 396 | private: |
| 397 | bool _is_deadlock; |
| 398 | GrowableArray<JavaThread*>* _threads; |
| 399 | DeadlockCycle* _next; |
| 400 | public: |
| 401 | DeadlockCycle(); |
| 402 | ~DeadlockCycle(); |
| 403 | |
| 404 | DeadlockCycle* next() { return _next; } |
| 405 | void set_next(DeadlockCycle* d) { _next = d; } |
| 406 | void add_thread(JavaThread* t) { _threads->append(t); } |
| 407 | void reset() { _is_deadlock = false; _threads->clear(); } |
| 408 | void set_deadlock(bool value) { _is_deadlock = value; } |
| 409 | bool is_deadlock() { return _is_deadlock; } |
| 410 | int num_threads() { return _threads->length(); } |
| 411 | GrowableArray<JavaThread*>* threads() { return _threads; } |
| 412 | void print_on_with(ThreadsList * t_list, outputStream* st) const; |
| 413 | }; |
| 414 | |
| 415 | // Utility class to get list of java threads. |
| 416 | class ThreadsListEnumerator : public StackObj { |
| 417 | private: |
| 418 | GrowableArray<instanceHandle>* _threads_array; |
| 419 | public: |
| 420 | ThreadsListEnumerator(Thread* cur_thread, |
| 421 | bool include_jvmti_agent_threads = false, |
| 422 | bool include_jni_attaching_threads = true); |
| 423 | int num_threads() { return _threads_array->length(); } |
| 424 | instanceHandle get_threadObj(int index) { return _threads_array->at(index); } |
| 425 | }; |
| 426 | |
| 427 | |
| 428 | // abstract utility class to set new thread states, and restore previous after the block exits |
| 429 | class JavaThreadStatusChanger : public StackObj { |
| 430 | private: |
| 431 | java_lang_Thread::ThreadStatus _old_state; |
| 432 | JavaThread* _java_thread; |
| 433 | bool _is_alive; |
| 434 | |
| 435 | void save_old_state(JavaThread* java_thread) { |
| 436 | _java_thread = java_thread; |
| 437 | _is_alive = is_alive(java_thread); |
| 438 | if (is_alive()) { |
| 439 | _old_state = java_lang_Thread::get_thread_status(_java_thread->threadObj()); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | public: |
| 444 | static void set_thread_status(JavaThread* java_thread, |
| 445 | java_lang_Thread::ThreadStatus state) { |
| 446 | java_lang_Thread::set_thread_status(java_thread->threadObj(), state); |
| 447 | } |
| 448 | |
| 449 | void set_thread_status(java_lang_Thread::ThreadStatus state) { |
| 450 | if (is_alive()) { |
| 451 | set_thread_status(_java_thread, state); |
| 452 | } |
| 453 | } |
| 454 | |
| 455 | JavaThreadStatusChanger(JavaThread* java_thread, |
| 456 | java_lang_Thread::ThreadStatus state) : _old_state(java_lang_Thread::NEW) { |
| 457 | save_old_state(java_thread); |
| 458 | set_thread_status(state); |
| 459 | } |
| 460 | |
| 461 | JavaThreadStatusChanger(JavaThread* java_thread) : _old_state(java_lang_Thread::NEW) { |
| 462 | save_old_state(java_thread); |
| 463 | } |
| 464 | |
| 465 | ~JavaThreadStatusChanger() { |
| 466 | set_thread_status(_old_state); |
| 467 | } |
| 468 | |
| 469 | static bool is_alive(JavaThread* java_thread) { |
| 470 | return java_thread != NULL && java_thread->threadObj() != NULL; |
| 471 | } |
| 472 | |
| 473 | bool is_alive() { |
| 474 | return _is_alive; |
| 475 | } |
| 476 | }; |
| 477 | |
| 478 | // Change status to waiting on an object (timed or indefinite) |
| 479 | class JavaThreadInObjectWaitState : public JavaThreadStatusChanger { |
| 480 | private: |
| 481 | ThreadStatistics* _stat; |
| 482 | bool _active; |
| 483 | |
| 484 | public: |
| 485 | JavaThreadInObjectWaitState(JavaThread *java_thread, bool timed) : |
| 486 | JavaThreadStatusChanger(java_thread, |
| 487 | timed ? java_lang_Thread::IN_OBJECT_WAIT_TIMED : java_lang_Thread::IN_OBJECT_WAIT) { |
| 488 | if (is_alive()) { |
| 489 | _stat = java_thread->get_thread_stat(); |
| 490 | _active = ThreadService::is_thread_monitoring_contention(); |
| 491 | _stat->monitor_wait(); |
| 492 | if (_active) { |
| 493 | _stat->monitor_wait_begin(); |
| 494 | } |
| 495 | } else { |
| 496 | _active = false; |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | ~JavaThreadInObjectWaitState() { |
| 501 | if (_active) { |
| 502 | _stat->monitor_wait_end(); |
| 503 | } |
| 504 | } |
| 505 | }; |
| 506 | |
| 507 | // Change status to parked (timed or indefinite) |
| 508 | class JavaThreadParkedState : public JavaThreadStatusChanger { |
| 509 | private: |
| 510 | ThreadStatistics* _stat; |
| 511 | bool _active; |
| 512 | |
| 513 | public: |
| 514 | JavaThreadParkedState(JavaThread *java_thread, bool timed) : |
| 515 | JavaThreadStatusChanger(java_thread, |
| 516 | timed ? java_lang_Thread::PARKED_TIMED : java_lang_Thread::PARKED) { |
| 517 | if (is_alive()) { |
| 518 | _stat = java_thread->get_thread_stat(); |
| 519 | _active = ThreadService::is_thread_monitoring_contention(); |
| 520 | _stat->monitor_wait(); |
| 521 | if (_active) { |
| 522 | _stat->monitor_wait_begin(); |
| 523 | } |
| 524 | } else { |
| 525 | _active = false; |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | ~JavaThreadParkedState() { |
| 530 | if (_active) { |
| 531 | _stat->monitor_wait_end(); |
| 532 | } |
| 533 | } |
| 534 | }; |
| 535 | |
| 536 | // Change status to blocked on (re-)entering a synchronization block |
| 537 | class JavaThreadBlockedOnMonitorEnterState : public JavaThreadStatusChanger { |
| 538 | private: |
| 539 | ThreadStatistics* _stat; |
| 540 | bool _active; |
| 541 | |
| 542 | static bool contended_enter_begin(JavaThread *java_thread) { |
| 543 | set_thread_status(java_thread, java_lang_Thread::BLOCKED_ON_MONITOR_ENTER); |
| 544 | ThreadStatistics* stat = java_thread->get_thread_stat(); |
| 545 | stat->contended_enter(); |
| 546 | bool active = ThreadService::is_thread_monitoring_contention(); |
| 547 | if (active) { |
| 548 | stat->contended_enter_begin(); |
| 549 | } |
| 550 | return active; |
| 551 | } |
| 552 | |
| 553 | public: |
| 554 | // java_thread is waiting thread being blocked on monitor reenter. |
| 555 | // Current thread is the notifying thread which holds the monitor. |
| 556 | static bool wait_reenter_begin(JavaThread *java_thread, ObjectMonitor *obj_m) { |
| 557 | assert((java_thread != NULL), "Java thread should not be null here" ); |
| 558 | bool active = false; |
| 559 | if (is_alive(java_thread)) { |
| 560 | active = contended_enter_begin(java_thread); |
| 561 | } |
| 562 | return active; |
| 563 | } |
| 564 | |
| 565 | static void wait_reenter_end(JavaThread *java_thread, bool active) { |
| 566 | if (active) { |
| 567 | java_thread->get_thread_stat()->contended_enter_end(); |
| 568 | } |
| 569 | set_thread_status(java_thread, java_lang_Thread::RUNNABLE); |
| 570 | } |
| 571 | |
| 572 | JavaThreadBlockedOnMonitorEnterState(JavaThread *java_thread, ObjectMonitor *obj_m) : |
| 573 | JavaThreadStatusChanger(java_thread), _stat(NULL), _active(false) { |
| 574 | assert((java_thread != NULL), "Java thread should not be null here" ); |
| 575 | // Change thread status and collect contended enter stats for monitor contended |
| 576 | // enter done for external java world objects and it is contended. All other cases |
| 577 | // like for vm internal objects and for external objects which are not contended |
| 578 | // thread status is not changed and contended enter stat is not collected. |
| 579 | _active = false; |
| 580 | if (is_alive() && obj_m->contentions() > 0) { |
| 581 | _stat = java_thread->get_thread_stat(); |
| 582 | _active = contended_enter_begin(java_thread); |
| 583 | } |
| 584 | } |
| 585 | |
| 586 | ~JavaThreadBlockedOnMonitorEnterState() { |
| 587 | if (_active) { |
| 588 | _stat->contended_enter_end(); |
| 589 | } |
| 590 | } |
| 591 | }; |
| 592 | |
| 593 | // Change status to sleeping |
| 594 | class JavaThreadSleepState : public JavaThreadStatusChanger { |
| 595 | private: |
| 596 | ThreadStatistics* _stat; |
| 597 | bool _active; |
| 598 | public: |
| 599 | JavaThreadSleepState(JavaThread *java_thread) : |
| 600 | JavaThreadStatusChanger(java_thread, java_lang_Thread::SLEEPING) { |
| 601 | if (is_alive()) { |
| 602 | _stat = java_thread->get_thread_stat(); |
| 603 | _active = ThreadService::is_thread_monitoring_contention(); |
| 604 | _stat->thread_sleep(); |
| 605 | if (_active) { |
| 606 | _stat->thread_sleep_begin(); |
| 607 | } |
| 608 | } else { |
| 609 | _active = false; |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | ~JavaThreadSleepState() { |
| 614 | if (_active) { |
| 615 | _stat->thread_sleep_end(); |
| 616 | } |
| 617 | } |
| 618 | }; |
| 619 | |
| 620 | #endif // SHARE_SERVICES_THREADSERVICE_HPP |
| 621 | |