1/*
2 * Copyright (c) 2011, 2019, 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
31static const u1* const MUTEX_CLAIM = NULL;
32
33JfrBuffer::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
42bool 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
57void JfrBuffer::reinitialize() {
58 assert(!lease(), "invariant");
59 assert(!transient(), "invariant");
60 set_pos(start());
61 clear_retired();
62 set_top(start());
63}
64
65void 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
74size_t JfrBuffer::discard() {
75 size_t discard_size = unflushed_size();
76 set_top(pos());
77 return discard_size;
78}
79
80const 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
88const u1* JfrBuffer::top() const {
89 return _top;
90}
91
92void JfrBuffer::set_top(const u1* new_top) {
93 _top = new_top;
94}
95
96const 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
105void 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
113size_t JfrBuffer::unflushed_size() const {
114 return pos() - stable_top();
115}
116
117void 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
125bool 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
131void JfrBuffer::release() {
132 OrderAccess::release_store(&_identity, (const void*)NULL);
133}
134
135bool JfrBuffer::acquired_by(const void* id) const {
136 return identity() == id;
137}
138
139bool JfrBuffer::acquired_by_self() const {
140 return acquired_by(Thread::current());
141}
142
143#ifdef ASSERT
144static bool validate_to(const JfrBuffer* const to, size_t size) {
145 assert(to != NULL, "invariant");
146 assert(to->acquired_by_self(), "invariant");
147 assert(to->free_size() >= size, "invariant");
148 return true;
149}
150
151static bool validate_concurrent_this(const JfrBuffer* const t, size_t size) {
152 assert(t->top() == MUTEX_CLAIM, "invariant");
153 return true;
154}
155
156static bool validate_this(const JfrBuffer* const t, size_t size) {
157 assert(t->top() + size <= t->pos(), "invariant");
158 return true;
159}
160#endif // ASSERT
161
162void 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
173void 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
186enum FLAG {
187 RETIRED = 1,
188 TRANSIENT = 2,
189 LEASE = 4
190};
191
192bool JfrBuffer::transient() const {
193 return (u1)TRANSIENT == (_flags & (u1)TRANSIENT);
194}
195
196void JfrBuffer::set_transient() {
197 _flags |= (u1)TRANSIENT;
198 assert(transient(), "invariant");
199}
200
201void JfrBuffer::clear_transient() {
202 if (transient()) {
203 _flags ^= (u1)TRANSIENT;
204 }
205 assert(!transient(), "invariant");
206}
207
208bool JfrBuffer::lease() const {
209 return (u1)LEASE == (_flags & (u1)LEASE);
210}
211
212void JfrBuffer::set_lease() {
213 _flags |= (u1)LEASE;
214 assert(lease(), "invariant");
215}
216
217void JfrBuffer::clear_lease() {
218 if (lease()) {
219 _flags ^= (u1)LEASE;
220 }
221 assert(!lease(), "invariant");
222}
223
224static u2 load_acquire_flags(const u2* const flags) {
225 return OrderAccess::load_acquire(flags);
226}
227
228static void release_store_flags(u2* const flags, u2 new_flags) {
229 OrderAccess::release_store(flags, new_flags);
230}
231
232bool JfrBuffer::retired() const {
233 return (u1)RETIRED == (load_acquire_flags(&_flags) & (u1)RETIRED);
234}
235
236void JfrBuffer::set_retired() {
237 const u2 new_flags = load_acquire_flags(&_flags) | (u1)RETIRED;
238 release_store_flags(&_flags, new_flags);
239}
240
241void JfrBuffer::clear_retired() {
242 u2 new_flags = load_acquire_flags(&_flags);
243 if ((u1)RETIRED == (new_flags & (u1)RETIRED)) {
244 new_flags ^= (u1)RETIRED;
245 release_store_flags(&_flags, new_flags);
246 }
247}
248