8212827: GlobalCounter should support nested critical sections
Summary: Support nested critical sections.
Reviewed-by: eosterlund, rehn, tschatzl
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_UTILITIES_SINGLEWRITERSYNCHRONIZER_HPP
#define SHARE_UTILITIES_SINGLEWRITERSYNCHRONIZER_HPP
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
#include "runtime/semaphore.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
// Synchronization primitive inspired by RCU.
//
// Any number of threads may enter critical sections associated with a
// synchronizer object. One (at a time) other thread may wait for the
// completion of all critical sections for the synchronizer object
// that were extant when the wait was initiated. Usage is that there
// is some state that can be accessed either before or after some
// change. An accessing thread performs the access within a critical
// section. A writer thread performs the state change, and then waits
// for critical sections to complete, thereby ensuring there are no
// threads in a critical section that might have seen the old state.
//
// Generally, GlobalCounter should be used instead of this class, as
// GlobalCounter has measurably better performance and doesn't have
// the single writer at a time restriction. Use this only in
// situations where GlobalCounter won't work for some reason.
class SingleWriterSynchronizer {
volatile uint _enter;
volatile uint _exit[2];
volatile uint _waiting_for;
Semaphore _wakeup;
DEBUG_ONLY(volatile uint _writers;)
// Noncopyable.
SingleWriterSynchronizer(const SingleWriterSynchronizer&);
SingleWriterSynchronizer& operator=(const SingleWriterSynchronizer&);
public:
SingleWriterSynchronizer();
// Enter a critical section for this synchronizer. Entering a
// critical section never blocks. While in a critical section, a
// thread should avoid blocking, or even take a long time. In
// particular, a thread must never safepoint while in a critical
// section.
// Precondition: The current thread must not already be in a
// critical section for this synchronizer.
inline uint enter();
// Exit a critical section for this synchronizer.
// Precondition: enter_value must be the result of the corresponding
// enter() for the critical section.
inline void exit(uint enter_value);
// Wait until all threads currently in a critical section for this
// synchronizer have exited their critical section. Threads that
// enter a critical section after the synchronization has started
// are not considered in the wait.
// Precondition: No other thread may be synchronizing on this
// synchronizer.
void synchronize();
// RAII class for managing enter/exit pairs.
class CriticalSection;
};
inline uint SingleWriterSynchronizer::enter() {
return Atomic::add(2u, &_enter);
}
inline void SingleWriterSynchronizer::exit(uint enter_value) {
uint exit_value = Atomic::add(2u, &_exit[enter_value & 1]);
// If this exit completes a synchronize request, wakeup possibly
// waiting synchronizer. Read of _waiting_for must follow the _exit
// update.
if (exit_value == _waiting_for) {
_wakeup.signal();
}
}
class SingleWriterSynchronizer::CriticalSection : public StackObj {
SingleWriterSynchronizer* _synchronizer;
uint _enter_value;
public:
// Enter synchronizer's critical section.
explicit CriticalSection(SingleWriterSynchronizer* synchronizer) :
_synchronizer(synchronizer),
_enter_value(synchronizer->enter())
{}
// Exit synchronizer's critical section.
~CriticalSection() {
_synchronizer->exit(_enter_value);
}
};
#endif // SHARE_UTILITIES_SINGLEWRITERSYNCHRONIZER_HPP