jdk
1/*
2* Copyright (c) 2019, Red Hat, Inc. 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#include "precompiled.hpp"26
27#include "runtime/os.hpp"28
29#include "gc/shenandoah/shenandoahLock.hpp"30#include "runtime/atomic.hpp"31#include "runtime/interfaceSupport.inline.hpp"32#include "runtime/javaThread.hpp"33#include "runtime/os.inline.hpp"34
35void ShenandoahLock::contended_lock(bool allow_block_for_safepoint) {36Thread* thread = Thread::current();37if (allow_block_for_safepoint && thread->is_Java_thread()) {38contended_lock_internal<true>(JavaThread::cast(thread));39} else {40contended_lock_internal<false>(nullptr);41}42}
43
44template<bool ALLOW_BLOCK>45void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) {46assert(!ALLOW_BLOCK || java_thread != nullptr, "Must have a Java thread when allowing block.");47// Spin this much, but only on multi-processor systems.48int ctr = os::is_MP() ? 0xFF : 0;49// Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread.50while (Atomic::load(&_state) == locked ||51Atomic::cmpxchg(&_state, unlocked, locked) != unlocked) {52if (ctr > 0 && !SafepointSynchronize::is_synchronizing()) {53// Lightly contended, spin a little if no safepoint is pending.54SpinPause();55ctr--;56} else if (ALLOW_BLOCK) {57ThreadBlockInVM block(java_thread);58if (SafepointSynchronize::is_synchronizing()) {59// If safepoint is pending, we want to block and allow safepoint to proceed.60// Normally, TBIVM above would block us in its destructor.61//62// But that blocking only happens when TBIVM knows the thread poll is armed.63// There is a window between announcing a safepoint and arming the thread poll64// during which trying to continuously enter TBIVM is counter-productive.65// Under high contention, we may end up going in circles thousands of times.66// To avoid it, we wait here until local poll is armed and then proceed67// to TBVIM exit for blocking. We do not SpinPause, but yield to let68// VM thread to arm the poll sooner.69while (SafepointSynchronize::is_synchronizing() &&70!SafepointMechanism::local_poll_armed(java_thread)) {71os::naked_yield();72}73} else {74os::naked_yield();75}76} else {77os::naked_yield();78}79}80}
81
82ShenandoahSimpleLock::ShenandoahSimpleLock() {83assert(os::mutex_init_done(), "Too early!");84}
85
86void ShenandoahSimpleLock::lock() {87_lock.lock();88}
89
90void ShenandoahSimpleLock::unlock() {91_lock.unlock();92}
93
94ShenandoahReentrantLock::ShenandoahReentrantLock() :95ShenandoahSimpleLock(), _owner(nullptr), _count(0) {96assert(os::mutex_init_done(), "Too early!");97}
98
99ShenandoahReentrantLock::~ShenandoahReentrantLock() {100assert(_count == 0, "Unbalance");101}
102
103void ShenandoahReentrantLock::lock() {104Thread* const thread = Thread::current();105Thread* const owner = Atomic::load(&_owner);106
107if (owner != thread) {108ShenandoahSimpleLock::lock();109Atomic::store(&_owner, thread);110}111
112_count++;113}
114
115void ShenandoahReentrantLock::unlock() {116assert(owned_by_self(), "Invalid owner");117assert(_count > 0, "Invalid count");118
119_count--;120
121if (_count == 0) {122Atomic::store(&_owner, (Thread*)nullptr);123ShenandoahSimpleLock::unlock();124}125}
126
127bool ShenandoahReentrantLock::owned_by_self() const {128Thread* const thread = Thread::current();129Thread* const owner = Atomic::load(&_owner);130return owner == thread;131}
132