1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. 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 #include "jfr/recorder/storage/jfrBuffer.hpp" 27 #include "runtime/atomic.hpp" 28 #include "runtime/orderAccess.hpp" 29 #include "runtime/thread.inline.hpp" 30 31 static const u1* const MUTEX_CLAIM = NULL; 32 33 JfrBuffer::JfrBuffer() : _next(NULL), 34 _prev(NULL), 35 _identity(NULL), 36 _pos(NULL), 37 _top(NULL), 38 _flags(0), 39 _header_size(0), 40 _size(0) {} 41 42 bool JfrBuffer::initialize(size_t header_size, size_t size, const void* id /* NULL */) { 43 _header_size = (u2)header_size; 44 _size = (u4)(size / BytesPerWord); 45 assert(_identity == NULL, "invariant"); 46 _identity = id; 47 set_pos(start()); 48 set_top(start()); 49 assert(_next == NULL, "invariant"); 50 assert(free_size() == size, "invariant"); 51 assert(!transient(), "invariant"); 52 assert(!lease(), "invariant"); 53 assert(!retired(), "invariant"); 54 return true; 55 } 56 57 void JfrBuffer::reinitialize() { 58 assert(!lease(), "invariant"); 59 assert(!transient(), "invariant"); 60 set_pos(start()); 61 clear_retired(); 62 set_top(start()); 63 } 64 65 void JfrBuffer::concurrent_reinitialization() { 66 concurrent_top(); 67 assert(!lease(), "invariant"); 68 assert(!transient(), "invariant"); 69 set_pos(start()); 70 set_concurrent_top(start()); 71 clear_retired(); 72 } 73 74 size_t JfrBuffer::discard() { 75 size_t discard_size = unflushed_size(); 76 set_top(pos()); 77 return discard_size; 78 } 79 80 const u1* JfrBuffer::stable_top() const { 81 const u1* current_top; 82 do { 83 current_top = OrderAccess::load_acquire(&_top); 84 } while (MUTEX_CLAIM == current_top); 85 return current_top; 86 } 87 88 const u1* JfrBuffer::top() const { 89 return _top; 90 } 91 92 void JfrBuffer::set_top(const u1* new_top) { 93 _top = new_top; 94 } 95 96 const u1* JfrBuffer::concurrent_top() const { 97 do { 98 const u1* current_top = stable_top(); 99 if (Atomic::cmpxchg(MUTEX_CLAIM, &_top, current_top) == current_top) { 100 return current_top; 101 } 102 } while (true); 103 } 104 105 void JfrBuffer::set_concurrent_top(const u1* new_top) { 106 assert(new_top != MUTEX_CLAIM, "invariant"); 107 assert(new_top <= end(), "invariant"); 108 assert(new_top >= start(), "invariant"); 109 assert(top() == MUTEX_CLAIM, "invariant"); 110 OrderAccess::release_store(&_top, new_top); 111 } 112 113 size_t JfrBuffer::unflushed_size() const { 114 return pos() - stable_top(); 115 } 116 117 void JfrBuffer::acquire(const void* id) { 118 assert(id != NULL, "invariant"); 119 const void* current_id; 120 do { 121 current_id = OrderAccess::load_acquire(&_identity); 122 } while (current_id != NULL || Atomic::cmpxchg(id, &_identity, current_id) != current_id); 123 } 124 125 bool JfrBuffer::try_acquire(const void* id) { 126 assert(id != NULL, "invariant"); 127 const void* const current_id = OrderAccess::load_acquire(&_identity); 128 return current_id == NULL && Atomic::cmpxchg(id, &_identity, current_id) == current_id; 129 } 130 131 void JfrBuffer::release() { 132 OrderAccess::release_store(&_identity, (const void*)NULL); 133 } 134 135 void JfrBuffer::clear_identity() { 136 _identity = NULL; 137 } 138 139 #ifdef ASSERT 140 static bool validate_to(const JfrBuffer* const to, size_t size) { 141 assert(to != NULL, "invariant"); 142 assert(to->acquired_by_self(), "invariant"); 143 assert(to->free_size() >= size, "invariant"); 144 return true; 145 } 146 147 static bool validate_concurrent_this(const JfrBuffer* const t, size_t size) { 148 assert(t->top() == MUTEX_CLAIM, "invariant"); 149 return true; 150 } 151 152 static bool validate_this(const JfrBuffer* const t, size_t size) { 153 assert(t->top() + size <= t->pos(), "invariant"); 154 return true; 155 } 156 157 bool JfrBuffer::acquired_by_self() const { 158 return identity() == Thread::current(); 159 } 160 #endif // ASSERT 161 162 void JfrBuffer::move(JfrBuffer* const to, size_t size) { 163 assert(validate_to(to, size), "invariant"); 164 assert(validate_this(this, size), "invariant"); 165 const u1* current_top = top(); 166 assert(current_top != NULL, "invariant"); 167 memcpy(to->pos(), current_top, size); 168 to->set_pos(size); 169 to->release(); 170 set_top(current_top + size); 171 } 172 173 void JfrBuffer::concurrent_move_and_reinitialize(JfrBuffer* const to, size_t size) { 174 assert(validate_to(to, size), "invariant"); 175 const u1* current_top = concurrent_top(); 176 assert(validate_concurrent_this(this, size), "invariant"); 177 const size_t actual_size = MIN2(size, (size_t)(pos() - current_top)); 178 assert(actual_size <= size, "invariant"); 179 memcpy(to->pos(), current_top, actual_size); 180 to->set_pos(actual_size); 181 set_pos(start()); 182 to->release(); 183 set_concurrent_top(start()); 184 } 185 186 // flags 187 enum FLAG { 188 RETIRED = 1, 189 TRANSIENT = 2, 190 LEASE = 4 191 }; 192 193 bool JfrBuffer::transient() const { 194 return (u1)TRANSIENT == (_flags & (u1)TRANSIENT); 195 } 196 197 void JfrBuffer::set_transient() { 198 _flags |= (u1)TRANSIENT; 199 assert(transient(), "invariant"); 200 } 201 202 void JfrBuffer::clear_transient() { 203 if (transient()) { 204 _flags ^= (u1)TRANSIENT; 205 } 206 assert(!transient(), "invariant"); 207 } 208 209 bool JfrBuffer::lease() const { 210 return (u1)LEASE == (_flags & (u1)LEASE); 211 } 212 213 void JfrBuffer::set_lease() { 214 _flags |= (u1)LEASE; 215 assert(lease(), "invariant"); 216 } 217 218 void JfrBuffer::clear_lease() { 219 if (lease()) { 220 _flags ^= (u1)LEASE; 221 } 222 assert(!lease(), "invariant"); 223 } 224 225 static u2 load_acquire_flags(const u2* const flags) { 226 return OrderAccess::load_acquire(flags); 227 } 228 229 static void release_store_flags(u2* const flags, u2 new_flags) { 230 OrderAccess::release_store(flags, new_flags); 231 } 232 233 bool JfrBuffer::retired() const { 234 return (u1)RETIRED == (load_acquire_flags(&_flags) & (u1)RETIRED); 235 } 236 237 void JfrBuffer::set_retired() { 238 const u2 new_flags = load_acquire_flags(&_flags) | (u1)RETIRED; 239 release_store_flags(&_flags, new_flags); 240 } 241 242 void JfrBuffer::clear_retired() { 243 u2 new_flags = load_acquire_flags(&_flags); 244 if ((u1)RETIRED == (new_flags & (u1)RETIRED)) { 245 new_flags ^= (u1)RETIRED; 246 release_store_flags(&_flags, new_flags); 247 } 248 }