--- /dev/null 2019-01-28 17:47:47.000000000 +0800 +++ new/src/share/vm/jfr/recorder/storage/jfrBuffer.cpp 2019-01-28 17:47:47.000000000 +0800 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2011, 2019, 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 "jfr/recorder/storage/jfrBuffer.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.inline.hpp" +#include "runtime/thread.inline.hpp" + +static const u1* const MUTEX_CLAIM = NULL; + +JfrBuffer::JfrBuffer() : _next(NULL), + _prev(NULL), + _identity(NULL), + _pos(NULL), + _top(NULL), + _flags(0), + _header_size(0), + _size(0) {} + +bool JfrBuffer::initialize(size_t header_size, size_t size, const void* id /* NULL */) { + _header_size = (u2)header_size; + _size = (u4)(size / BytesPerWord); + assert(_identity == NULL, "invariant"); + _identity = id; + set_pos(start()); + set_top(start()); + assert(_next == NULL, "invariant"); + assert(free_size() == size, "invariant"); + assert(!transient(), "invariant"); + assert(!lease(), "invariant"); + assert(!retired(), "invariant"); + return true; +} + +void JfrBuffer::reinitialize() { + assert(!lease(), "invariant"); + assert(!transient(), "invariant"); + set_pos(start()); + set_top(start()); + clear_retired(); +} + +void JfrBuffer::concurrent_reinitialization() { + concurrent_top(); + assert(!lease(), "invariant"); + assert(!transient(), "invariant"); + set_pos(start()); + set_concurrent_top(start()); // StoreStore + clear_retired(); +} + +size_t JfrBuffer::discard() { + size_t discard_size = unflushed_size(); + set_top(pos()); + return discard_size; +} + +const u1* JfrBuffer::stable_top() const { + const u1* current_top; + do { + current_top = (const u1*)OrderAccess::load_ptr_acquire((void*)&_top); + } while (MUTEX_CLAIM == current_top); + return current_top; +} + +void JfrBuffer::clear_flags() { + clear_retired(); +} + +const u1* JfrBuffer::top() const { + return _top; +} + +void JfrBuffer::set_top(const u1* new_top) { + _top = new_top; +} + +const u1* JfrBuffer::concurrent_top() const { + do { + const u1* current_top = stable_top(); + if ((const u1*)Atomic::cmpxchg_ptr((void*)MUTEX_CLAIM, (void*)&_top, (void*)current_top) == current_top) { + return current_top; + } + } while (true); +} + +void JfrBuffer::set_concurrent_top(const u1* new_top) { + assert(new_top != MUTEX_CLAIM, "invariant"); + assert(new_top <= end(), "invariant"); + assert(new_top >= start(), "invariant"); + assert(top() == MUTEX_CLAIM, "invariant"); + OrderAccess::storestore(); + set_top(new_top); +} + +size_t JfrBuffer::unflushed_size() const { + return pos() - stable_top(); +} + +void JfrBuffer::acquire(const void* id) { + assert(id != NULL, "invariant"); + const void* current_id; + do { + current_id = OrderAccess::load_ptr_acquire(&_identity); + } while (current_id != NULL || Atomic::cmpxchg_ptr(const_cast(id), (void*)&_identity, const_cast(current_id)) != current_id); +} + +bool JfrBuffer::try_acquire(const void* id) { + assert(id != NULL, "invariant"); + const void* const current_id = OrderAccess::load_ptr_acquire(&_identity); + return current_id == NULL && Atomic::cmpxchg_ptr(const_cast(id), (void*)&_identity, const_cast(current_id)) == current_id; +} + +void JfrBuffer::release() { + OrderAccess::storestore(); + clear_identity(); +} + +void JfrBuffer::clear_identity() { + _identity = NULL; +} + +#ifdef ASSERT +static bool validate_to(const JfrBuffer* const to, size_t size) { + assert(to != NULL, "invariant"); + assert(to->acquired_by_self(), "invariant"); + assert(to->free_size() >= size, "invariant"); + return true; +} + +static bool validate_concurrent_this(const JfrBuffer* const t, size_t size) { + assert(t->top() == MUTEX_CLAIM, "invariant"); + return true; +} + +static bool validate_this(const JfrBuffer* const t, size_t size) { + assert(t->top() + size <= t->pos(), "invariant"); + return true; +} + +bool JfrBuffer::acquired_by_self() const { + return identity() == Thread::current(); +} +#endif // ASSERT + +void JfrBuffer::move(JfrBuffer* const to, size_t size) { + assert(validate_to(to, size), "invariant"); + assert(validate_this(this, size), "invariant"); + const u1* current_top = top(); + assert(current_top != NULL, "invariant"); + memcpy(to->pos(), current_top, size); + to->set_pos(size); + to->release(); // StoreStore + set_top(current_top + size); +} + +void JfrBuffer::concurrent_move_and_reinitialize(JfrBuffer* const to, size_t size) { + assert(validate_to(to, size), "invariant"); + const u1* current_top = concurrent_top(); + assert(validate_concurrent_this(this, size), "invariant"); + const size_t actual_size = MIN2(size, (size_t)(pos() - current_top)); + assert(actual_size <= size, "invariant"); + memcpy(to->pos(), current_top, actual_size); + to->set_pos(actual_size); + set_pos(start()); + to->release(); // StoreStore + clear_retired(); + set_top(start()); +} + +// flags +enum FLAG { + RETIRED = 1, + TRANSIENT = 2, + LEASE = 4 +}; + +bool JfrBuffer::transient() const { + return (u1)TRANSIENT == (_flags & (u1)TRANSIENT); +} + +void JfrBuffer::set_transient() { + _flags |= (u1)TRANSIENT; + assert(transient(), "invariant"); +} + +void JfrBuffer::clear_transient() { + if (transient()) { + _flags ^= (u1)TRANSIENT; + } + assert(!transient(), "invariant"); +} + +bool JfrBuffer::lease() const { + return (u1)LEASE == (_flags & (u1)LEASE); +} + +void JfrBuffer::set_lease() { + _flags |= (u1)LEASE; + assert(lease(), "invariant"); +} + +void JfrBuffer::clear_lease() { + if (lease()) { + _flags ^= (u1)LEASE; + } + assert(!lease(), "invariant"); +} + +bool JfrBuffer::retired() const { + return (u1)RETIRED == (_flags & (u1)RETIRED); +} + +void JfrBuffer::set_retired() { + _flags |= (u1)RETIRED; + assert(retired(), "invariant"); +} + +void JfrBuffer::clear_retired() { + if (retired()) { + _flags ^= (u1)RETIRED; + } + assert(!retired(), "invariant"); +}