src/share/vm/jfr/recorder/storage/jfrBuffer.cpp

Wed, 17 Jun 2020 11:43:05 +0300

author
apetushkov
date
Wed, 17 Jun 2020 11:43:05 +0300
changeset 9928
d2c2cd90513e
parent 9858
b985cbb00e68
permissions
-rw-r--r--

8220293: Deadlock in JFR string pool
Reviewed-by: rehn, egahlin

apetushkov@9858 1 /*
apetushkov@9928 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
apetushkov@9858 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
apetushkov@9858 4 *
apetushkov@9858 5 * This code is free software; you can redistribute it and/or modify it
apetushkov@9858 6 * under the terms of the GNU General Public License version 2 only, as
apetushkov@9858 7 * published by the Free Software Foundation.
apetushkov@9858 8 *
apetushkov@9858 9 * This code is distributed in the hope that it will be useful, but WITHOUT
apetushkov@9858 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
apetushkov@9858 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
apetushkov@9858 12 * version 2 for more details (a copy is included in the LICENSE file that
apetushkov@9858 13 * accompanied this code).
apetushkov@9858 14 *
apetushkov@9858 15 * You should have received a copy of the GNU General Public License version
apetushkov@9858 16 * 2 along with this work; if not, write to the Free Software Foundation,
apetushkov@9858 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
apetushkov@9858 18 *
apetushkov@9858 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
apetushkov@9858 20 * or visit www.oracle.com if you need additional information or have any
apetushkov@9858 21 * questions.
apetushkov@9858 22 *
apetushkov@9858 23 */
apetushkov@9858 24
apetushkov@9858 25 #include "precompiled.hpp"
apetushkov@9858 26 #include "jfr/recorder/storage/jfrBuffer.hpp"
apetushkov@9858 27 #include "runtime/atomic.inline.hpp"
apetushkov@9858 28 #include "runtime/orderAccess.inline.hpp"
apetushkov@9858 29 #include "runtime/thread.inline.hpp"
apetushkov@9858 30 #include "jfr/recorder/jfrRecorder.hpp"
apetushkov@9858 31
apetushkov@9858 32 static const u1* const MUTEX_CLAIM = NULL;
apetushkov@9858 33
apetushkov@9858 34 JfrBuffer::JfrBuffer() : _next(NULL),
apetushkov@9858 35 _prev(NULL),
apetushkov@9858 36 _identity(NULL),
apetushkov@9858 37 _pos(NULL),
apetushkov@9858 38 _top(NULL),
apetushkov@9858 39 _flags(0),
apetushkov@9858 40 _header_size(0),
apetushkov@9858 41 _size(0) {}
apetushkov@9858 42
apetushkov@9858 43 bool JfrBuffer::initialize(size_t header_size, size_t size, const void* id /* NULL */) {
apetushkov@9858 44 _header_size = (u2)header_size;
apetushkov@9858 45 _size = (u4)(size / BytesPerWord);
apetushkov@9858 46 assert(_identity == NULL, "invariant");
apetushkov@9858 47 _identity = id;
apetushkov@9858 48 set_pos(start());
apetushkov@9858 49 set_top(start());
apetushkov@9858 50 assert(_next == NULL, "invariant");
apetushkov@9858 51 assert(free_size() == size, "invariant");
apetushkov@9858 52 assert(!transient(), "invariant");
apetushkov@9858 53 assert(!lease(), "invariant");
apetushkov@9858 54 assert(!retired(), "invariant");
apetushkov@9858 55 return true;
apetushkov@9858 56 }
apetushkov@9858 57
apetushkov@9858 58 void JfrBuffer::reinitialize() {
apetushkov@9858 59 assert(!lease(), "invariant");
apetushkov@9858 60 assert(!transient(), "invariant");
apetushkov@9858 61 set_pos(start());
apetushkov@9858 62 clear_retired();
apetushkov@9858 63 set_top(start());
apetushkov@9858 64 }
apetushkov@9858 65
apetushkov@9858 66 void JfrBuffer::concurrent_reinitialization() {
apetushkov@9858 67 concurrent_top();
apetushkov@9858 68 assert(!lease(), "invariant");
apetushkov@9858 69 assert(!transient(), "invariant");
apetushkov@9858 70 set_pos(start());
apetushkov@9858 71 set_concurrent_top(start());
apetushkov@9858 72 clear_retired();
apetushkov@9858 73 }
apetushkov@9858 74
apetushkov@9858 75 size_t JfrBuffer::discard() {
apetushkov@9858 76 size_t discard_size = unflushed_size();
apetushkov@9858 77 set_top(pos());
apetushkov@9858 78 return discard_size;
apetushkov@9858 79 }
apetushkov@9858 80
apetushkov@9858 81 const u1* JfrBuffer::stable_top() const {
apetushkov@9858 82 const u1* current_top;
apetushkov@9858 83 do {
apetushkov@9858 84 current_top = (const u1*)OrderAccess::load_ptr_acquire(&_top);
apetushkov@9858 85 } while (MUTEX_CLAIM == current_top);
apetushkov@9858 86 return current_top;
apetushkov@9858 87 }
apetushkov@9858 88
apetushkov@9858 89 const u1* JfrBuffer::top() const {
apetushkov@9858 90 return _top;
apetushkov@9858 91 }
apetushkov@9858 92
apetushkov@9858 93 void JfrBuffer::set_top(const u1* new_top) {
apetushkov@9858 94 _top = new_top;
apetushkov@9858 95 }
apetushkov@9858 96
apetushkov@9858 97 const u1* JfrBuffer::concurrent_top() const {
apetushkov@9858 98 do {
apetushkov@9858 99 const u1* current_top = stable_top();
apetushkov@9858 100 if (Atomic::cmpxchg_ptr((void*)MUTEX_CLAIM, &_top, (void*)current_top) == current_top) {
apetushkov@9858 101 return current_top;
apetushkov@9858 102 }
apetushkov@9858 103 } while (true);
apetushkov@9858 104 }
apetushkov@9858 105
apetushkov@9858 106 void JfrBuffer::set_concurrent_top(const u1* new_top) {
apetushkov@9858 107 assert(new_top != MUTEX_CLAIM, "invariant");
apetushkov@9858 108 assert(new_top <= end(), "invariant");
apetushkov@9858 109 assert(new_top >= start(), "invariant");
apetushkov@9858 110 assert(top() == MUTEX_CLAIM, "invariant");
apetushkov@9858 111 OrderAccess::release_store_ptr(&_top, (void*)new_top);
apetushkov@9858 112 }
apetushkov@9858 113
apetushkov@9858 114 size_t JfrBuffer::unflushed_size() const {
apetushkov@9858 115 return pos() - stable_top();
apetushkov@9858 116 }
apetushkov@9858 117
apetushkov@9858 118 void JfrBuffer::acquire(const void* id) {
apetushkov@9858 119 assert(id != NULL, "invariant");
apetushkov@9858 120 const void* current_id;
apetushkov@9858 121 do {
apetushkov@9858 122 current_id = OrderAccess::load_ptr_acquire(&_identity);
apetushkov@9858 123 } while (current_id != NULL || Atomic::cmpxchg_ptr((void*)id, &_identity, (void*)current_id) != current_id);
apetushkov@9858 124 }
apetushkov@9858 125
apetushkov@9858 126 bool JfrBuffer::try_acquire(const void* id) {
apetushkov@9858 127 assert(id != NULL, "invariant");
apetushkov@9858 128 const void* const current_id = OrderAccess::load_ptr_acquire(&_identity);
apetushkov@9858 129 return current_id == NULL && Atomic::cmpxchg_ptr((void*)id, &_identity, (void*)current_id) == current_id;
apetushkov@9858 130 }
apetushkov@9858 131
apetushkov@9858 132 void JfrBuffer::release() {
apetushkov@9858 133 OrderAccess::release_store_ptr(&_identity, (void*)NULL);
apetushkov@9858 134 }
apetushkov@9858 135
apetushkov@9858 136 void JfrBuffer::clear_identity() {
apetushkov@9858 137 _identity = NULL;
apetushkov@9858 138 }
apetushkov@9858 139
apetushkov@9928 140 bool JfrBuffer::acquired_by(const void* id) const {
apetushkov@9928 141 return identity() == id;
apetushkov@9928 142 }
apetushkov@9928 143
apetushkov@9928 144 bool JfrBuffer::acquired_by_self() const {
apetushkov@9928 145 return acquired_by(Thread::current());
apetushkov@9928 146 }
apetushkov@9928 147
apetushkov@9858 148 #ifdef ASSERT
apetushkov@9858 149 static bool validate_to(const JfrBuffer* const to, size_t size) {
apetushkov@9858 150 assert(to != NULL, "invariant");
apetushkov@9858 151 if (!JfrRecorder::is_shutting_down()) assert(to->acquired_by_self(), "invariant");
apetushkov@9858 152 assert(to->free_size() >= size, "invariant");
apetushkov@9858 153 return true;
apetushkov@9858 154 }
apetushkov@9858 155
apetushkov@9858 156 static bool validate_concurrent_this(const JfrBuffer* const t, size_t size) {
apetushkov@9858 157 assert(t->top() == MUTEX_CLAIM, "invariant");
apetushkov@9858 158 return true;
apetushkov@9858 159 }
apetushkov@9858 160
apetushkov@9858 161 static bool validate_this(const JfrBuffer* const t, size_t size) {
apetushkov@9858 162 assert(t->top() + size <= t->pos(), "invariant");
apetushkov@9858 163 return true;
apetushkov@9858 164 }
apetushkov@9858 165 #endif // ASSERT
apetushkov@9858 166
apetushkov@9858 167 void JfrBuffer::move(JfrBuffer* const to, size_t size) {
apetushkov@9858 168 assert(validate_to(to, size), "invariant");
apetushkov@9858 169 assert(validate_this(this, size), "invariant");
apetushkov@9858 170 const u1* current_top = top();
apetushkov@9858 171 assert(current_top != NULL, "invariant");
apetushkov@9858 172 memcpy(to->pos(), current_top, size);
apetushkov@9858 173 to->set_pos(size);
apetushkov@9858 174 to->release();
apetushkov@9858 175 set_top(current_top + size);
apetushkov@9858 176 }
apetushkov@9858 177
apetushkov@9858 178 void JfrBuffer::concurrent_move_and_reinitialize(JfrBuffer* const to, size_t size) {
apetushkov@9858 179 assert(validate_to(to, size), "invariant");
apetushkov@9858 180 const u1* current_top = concurrent_top();
apetushkov@9858 181 assert(validate_concurrent_this(this, size), "invariant");
apetushkov@9858 182 const size_t actual_size = MIN2(size, (size_t)(pos() - current_top));
apetushkov@9858 183 assert(actual_size <= size, "invariant");
apetushkov@9858 184 memcpy(to->pos(), current_top, actual_size);
apetushkov@9858 185 to->set_pos(actual_size);
apetushkov@9858 186 set_pos(start());
apetushkov@9858 187 to->release();
apetushkov@9858 188 set_concurrent_top(start());
apetushkov@9858 189 }
apetushkov@9858 190
apetushkov@9858 191 enum FLAG {
apetushkov@9858 192 RETIRED = 1,
apetushkov@9858 193 TRANSIENT = 2,
apetushkov@9858 194 LEASE = 4
apetushkov@9858 195 };
apetushkov@9858 196
apetushkov@9858 197 bool JfrBuffer::transient() const {
apetushkov@9858 198 return (u1)TRANSIENT == (_flags & (u1)TRANSIENT);
apetushkov@9858 199 }
apetushkov@9858 200
apetushkov@9858 201 void JfrBuffer::set_transient() {
apetushkov@9858 202 _flags |= (u1)TRANSIENT;
apetushkov@9858 203 assert(transient(), "invariant");
apetushkov@9858 204 }
apetushkov@9858 205
apetushkov@9858 206 void JfrBuffer::clear_transient() {
apetushkov@9858 207 if (transient()) {
apetushkov@9858 208 _flags ^= (u1)TRANSIENT;
apetushkov@9858 209 }
apetushkov@9858 210 assert(!transient(), "invariant");
apetushkov@9858 211 }
apetushkov@9858 212
apetushkov@9858 213 bool JfrBuffer::lease() const {
apetushkov@9858 214 return (u1)LEASE == (_flags & (u1)LEASE);
apetushkov@9858 215 }
apetushkov@9858 216
apetushkov@9858 217 void JfrBuffer::set_lease() {
apetushkov@9858 218 _flags |= (u1)LEASE;
apetushkov@9858 219 assert(lease(), "invariant");
apetushkov@9858 220 }
apetushkov@9858 221
apetushkov@9858 222 void JfrBuffer::clear_lease() {
apetushkov@9858 223 if (lease()) {
apetushkov@9858 224 _flags ^= (u1)LEASE;
apetushkov@9858 225 }
apetushkov@9858 226 assert(!lease(), "invariant");
apetushkov@9858 227 }
apetushkov@9858 228
apetushkov@9858 229 static u2 load_acquire_flags(const u2* const flags) {
apetushkov@9858 230 return OrderAccess::load_acquire((volatile jushort *)flags);
apetushkov@9858 231 }
apetushkov@9858 232
apetushkov@9858 233 static void release_store_flags(u2* const flags, u2 new_flags) {
apetushkov@9858 234 OrderAccess::release_store(flags, new_flags);
apetushkov@9858 235 }
apetushkov@9858 236
apetushkov@9858 237 bool JfrBuffer::retired() const {
apetushkov@9858 238 return (u1)RETIRED == (load_acquire_flags(&_flags) & (u1)RETIRED);
apetushkov@9858 239 }
apetushkov@9858 240
apetushkov@9858 241 void JfrBuffer::set_retired() {
apetushkov@9858 242 const u2 new_flags = load_acquire_flags(&_flags) | (u1)RETIRED;
apetushkov@9858 243 release_store_flags(&_flags, new_flags);
apetushkov@9858 244 }
apetushkov@9858 245
apetushkov@9858 246 void JfrBuffer::clear_retired() {
apetushkov@9858 247 u2 new_flags = load_acquire_flags(&_flags);
apetushkov@9858 248 if ((u1)RETIRED == (new_flags & (u1)RETIRED)) {
apetushkov@9858 249 new_flags ^= (u1)RETIRED;
apetushkov@9858 250 release_store_flags(&_flags, new_flags);
apetushkov@9858 251 }
apetushkov@9858 252 }

mercurial