/* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "precompiled.hpp" #include "runtime/atomic.hpp" #include "runtime/globalSynchronizer.hpp" #include "runtime/thread.inline.hpp" #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif volatile int GlobalSynchronizer::_global_serialized_memory_version = 0; volatile int GlobalSynchronizer::_latest_global_serialized_memory_version = 0; int GlobalSynchronizer::global_serialized_memory_version() { return _global_serialized_memory_version; } GlobalSynchronizer::GlobalSynchronizer(UrgencyLevel start_urgency, UrgencyLevel max_urgency) : _current_urgency(start_urgency), _max_urgency(max_urgency) { assert(max_urgency >= start_urgency, "sanity"); assert(start_urgency >= UrgencyLevel1 && start_urgency <= UrgencyLevelMax, "sanity"); } GlobalSynchronizer::~GlobalSynchronizer() { } void GlobalSynchronizer::start_synchronizing() { assert(ThreadLocalSafepoints, "sanity"); _local_serialized_memory_version = Atomic::add(1, &_global_serialized_memory_version); } bool GlobalSynchronizer::increase_urgency() { if (_current_urgency + 1 < _max_urgency) { _current_urgency = (UrgencyLevel)(int(_current_urgency) + 1); return true; } else { return false; } } void GlobalSynchronizer::maximize_urgency() { _current_urgency = _max_urgency; } void GlobalSynchronizer::threads_do(ThreadClosure *cl) { Threads::java_threads_do_fast(cl, Thread::current()); } class GSHasFinishedThreadClosure : public ThreadClosure { private: int _needed_version; int _min_agreed_version; bool _check_thread_state; public: GSHasFinishedThreadClosure(int version, bool check_thread_state) : _needed_version(version), _min_agreed_version(INT_MAX), _check_thread_state(check_thread_state) {} virtual void do_thread(Thread *thread) { JavaThread *jthread = reinterpret_cast(thread); int thread_version = jthread->serialized_memory_version(); if (thread_version < _needed_version) { if (!jthread->is_online_vm()) _min_agreed_version = MIN(_needed_version, _min_agreed_version); else if (_check_thread_state && !jthread->is_online_os()) _min_agreed_version = MIN(_needed_version, _min_agreed_version); else _min_agreed_version = MIN(thread_version, _min_agreed_version); } else { _min_agreed_version = MIN(thread_version, _min_agreed_version); } } bool did_synchronize() { return _min_agreed_version >= _needed_version; } void fixup_global_version() { int global_version = GlobalSynchronizer::_latest_global_serialized_memory_version; if (global_version < _min_agreed_version) { (void) Atomic::cmpxchg(_min_agreed_version, &GlobalSynchronizer::_latest_global_serialized_memory_version, global_version); } } }; class GSSetYieldpointThreadClosure : public ThreadClosure { const int _target_version; const bool _force_yields; public: GSSetYieldpointThreadClosure(bool force_yields, int target_version) : _force_yields(force_yields), _target_version(target_version) {} virtual void do_thread(Thread *thread) { JavaThread *const jthread = (JavaThread*)thread; if (jthread->serialized_memory_version() >= _target_version) return; if (_force_yields) jthread->set_force_yield(); jthread->set_yieldpoint(true); } }; bool GlobalSynchronizer::try_synchronize() { Thread *thread = Thread::current(); if (thread->is_Java_thread()) { JavaThread *jthread = reinterpret_cast(thread); jthread->update_serialized_memory_version(); } if (_latest_global_serialized_memory_version >= _local_serialized_memory_version) { return true; } GSHasFinishedThreadClosure cl(_local_serialized_memory_version, /* check_thread_state */ _current_urgency >= UrgencyLevel2); threads_do(&cl); if (cl.did_synchronize()) { cl.fixup_global_version(); return true; } switch (_current_urgency) { case UrgencyLevel3: case UrgencyLevel4: { GSSetYieldpointThreadClosure cl(false, _local_serialized_memory_version); threads_do(&cl); return false; } default: return false; } } void GlobalSynchronizer::synchronize() { while (!try_synchronize()) os::naked_yield(); }