1/*
2 * Copyright (c) 2016, 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#ifndef SHARE_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
26#define SHARE_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
27
28#include "jfr/recorder/storage/jfrMemorySpace.hpp"
29
30template <typename T, template <typename> class RetrievalType, typename Callback>
31JfrMemorySpace<T, RetrievalType, Callback>::
32JfrMemorySpace(size_t min_elem_size, size_t limit_size, size_t cache_count, Callback* callback) :
33 _free(),
34 _full(),
35 _min_elem_size(min_elem_size),
36 _limit_size(limit_size),
37 _cache_count(cache_count),
38 _callback(callback) {}
39
40template <typename T, template <typename> class RetrievalType, typename Callback>
41JfrMemorySpace<T, RetrievalType, Callback>::~JfrMemorySpace() {
42 Iterator full_iter(_full);
43 while (full_iter.has_next()) {
44 Type* t = full_iter.next();
45 _full.remove(t);
46 deallocate(t);
47 }
48 Iterator free_iter(_free);
49 while (free_iter.has_next()) {
50 Type* t = free_iter.next();
51 _free.remove(t);
52 deallocate(t);
53 }
54}
55
56template <typename T, template <typename> class RetrievalType, typename Callback>
57bool JfrMemorySpace<T, RetrievalType, Callback>::initialize() {
58 assert(_min_elem_size % os::vm_page_size() == 0, "invariant");
59 assert(_limit_size % os::vm_page_size() == 0, "invariant");
60 // pre-allocate cache elements
61 for (size_t i = 0; i < _cache_count; ++i) {
62 Type* const t = allocate(_min_elem_size);
63 if (t == NULL) {
64 return false;
65 }
66 insert_free_head(t);
67 }
68 assert(_free.count() == _cache_count, "invariant");
69 return true;
70}
71
72template <typename T, template <typename> class RetrievalType, typename Callback>
73inline void JfrMemorySpace<T, RetrievalType, Callback>::release_full(T* t) {
74 assert(is_locked(), "invariant");
75 assert(t != NULL, "invariant");
76 assert(_full.in_list(t), "invariant");
77 remove_full(t);
78 assert(!_full.in_list(t), "invariant");
79 if (t->transient()) {
80 deallocate(t);
81 return;
82 }
83 assert(t->empty(), "invariant");
84 assert(!t->retired(), "invariant");
85 assert(t->identity() == NULL, "invariant");
86 if (should_populate_cache()) {
87 assert(!_free.in_list(t), "invariant");
88 insert_free_head(t);
89 } else {
90 deallocate(t);
91 }
92}
93
94template <typename T, template <typename> class RetrievalType, typename Callback>
95inline void JfrMemorySpace<T, RetrievalType, Callback>::release_free(T* t) {
96 assert(is_locked(), "invariant");
97 assert(t != NULL, "invariant");
98 assert(_free.in_list(t), "invariant");
99 if (t->transient()) {
100 remove_free(t);
101 assert(!_free.in_list(t), "invariant");
102 deallocate(t);
103 return;
104 }
105 assert(t->empty(), "invariant");
106 assert(!t->retired(), "invariant");
107 assert(t->identity() == NULL, "invariant");
108 if (!should_populate_cache()) {
109 remove_free(t);
110 assert(!_free.in_list(t), "invariant");
111 deallocate(t);
112 }
113}
114
115template <typename T, template <typename> class RetrievalType, typename Callback>
116template <typename IteratorCallback, typename IteratorType>
117inline void JfrMemorySpace<T, RetrievalType, Callback>
118::iterate(IteratorCallback& callback, bool full, jfr_iter_direction direction) {
119 IteratorType iterator(full ? _full : _free, direction);
120 while (iterator.has_next()) {
121 callback.process(iterator.next());
122 }
123}
124
125template <typename Mspace>
126inline size_t size_adjustment(size_t size, Mspace* mspace) {
127 assert(mspace != NULL, "invariant");
128 static const size_t min_elem_size = mspace->min_elem_size();
129 if (size < min_elem_size) {
130 size = min_elem_size;
131 }
132 return size;
133}
134
135template <typename Mspace>
136inline typename Mspace::Type* mspace_allocate(size_t size, Mspace* mspace) {
137 return mspace->allocate(size_adjustment(size, mspace));
138}
139
140template <typename Mspace>
141inline typename Mspace::Type* mspace_allocate_acquired(size_t size, Mspace* mspace, Thread* thread) {
142 typename Mspace::Type* const t = mspace_allocate(size, mspace);
143 if (t == NULL) return NULL;
144 t->acquire(thread);
145 return t;
146}
147
148template <typename Mspace>
149inline typename Mspace::Type* mspace_allocate_transient(size_t size, Mspace* mspace, Thread* thread) {
150 typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread);
151 if (t == NULL) return NULL;
152 assert(t->acquired_by_self(), "invariant");
153 t->set_transient();
154 return t;
155}
156
157template <typename Mspace>
158inline typename Mspace::Type* mspace_allocate_transient_lease(size_t size, Mspace* mspace, Thread* thread) {
159 typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
160 if (t == NULL) return NULL;
161 assert(t->acquired_by_self(), "invariant");
162 assert(t->transient(), "invaiant");
163 t->set_lease();
164 return t;
165}
166
167template <typename Mspace>
168inline typename Mspace::Type* mspace_allocate_to_full(size_t size, Mspace* mspace, Thread* thread) {
169 assert(mspace->is_locked(), "invariant");
170 typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread);
171 if (t == NULL) return NULL;
172 mspace->insert_full_head(t);
173 return t;
174}
175
176template <typename Mspace>
177inline typename Mspace::Type* mspace_allocate_transient_to_full(size_t size, Mspace* mspace, Thread* thread) {
178 typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
179 if (t == NULL) return NULL;
180 MspaceLock<Mspace> lock(mspace);
181 mspace->insert_full_head(t);
182 return t;
183}
184
185template <typename Mspace>
186inline typename Mspace::Type* mspace_allocate_transient_lease_to_full(size_t size, Mspace* mspace, Thread* thread) {
187 typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread);
188 if (t == NULL) return NULL;
189 assert(t->acquired_by_self(), "invariant");
190 assert(t->transient(), "invaiant");
191 assert(t->lease(), "invariant");
192 MspaceLock<Mspace> lock(mspace);
193 mspace->insert_full_head(t);
194 return t;
195}
196
197template <typename Mspace>
198inline typename Mspace::Type* mspace_allocate_transient_lease_to_free(size_t size, Mspace* mspace, Thread* thread) {
199 typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread);
200 if (t == NULL) return NULL;
201 assert(t->acquired_by_self(), "invariant");
202 assert(t->transient(), "invaiant");
203 assert(t->lease(), "invariant");
204 MspaceLock<Mspace> lock(mspace);
205 mspace->insert_free_head(t);
206 return t;
207}
208
209template <typename Mspace>
210inline typename Mspace::Type* mspace_get_free(size_t size, Mspace* mspace, Thread* thread) {
211 return mspace->get(size, thread);
212}
213
214template <typename Mspace>
215inline typename Mspace::Type* mspace_get_free_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) {
216 assert(size <= mspace->min_elem_size(), "invariant");
217 for (size_t i = 0; i < retry_count; ++i) {
218 typename Mspace::Type* const t = mspace_get_free(size, mspace, thread);
219 if (t != NULL) {
220 return t;
221 }
222 }
223 return NULL;
224}
225
226template <typename Mspace>
227inline typename Mspace::Type* mspace_get_free_with_detach(size_t size, Mspace* mspace, Thread* thread) {
228 typename Mspace::Type* t = mspace_get_free(size, mspace, thread);
229 if (t != NULL) {
230 mspace->remove_free(t);
231 }
232 return t;
233}
234
235template <typename Mspace>
236inline typename Mspace::Type* mspace_get_free_to_full(size_t size, Mspace* mspace, Thread* thread) {
237 assert(size <= mspace->min_elem_size(), "invariant");
238 assert(mspace->is_locked(), "invariant");
239 typename Mspace::Type* t = mspace_get_free(size, mspace, thread);
240 if (t == NULL) {
241 return NULL;
242 }
243 assert(t->acquired_by_self(), "invariant");
244 move_to_head(t, mspace->free(), mspace->full());
245 return t;
246}
247
248template <typename Mspace>
249inline typename Mspace::Type* mspace_get_to_full(size_t size, Mspace* mspace, Thread* thread) {
250 size = size_adjustment(size, mspace);
251 MspaceLock<Mspace> lock(mspace);
252 if (size <= mspace->min_elem_size()) {
253 typename Mspace::Type* const t = mspace_get_free_to_full(size, mspace, thread);
254 if (t != NULL) {
255 return t;
256 }
257 }
258 return mspace_allocate_to_full(size, mspace, thread);
259}
260
261template <typename Mspace>
262inline typename Mspace::Type* mspace_get_free_lease_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) {
263 typename Mspace::Type* t = mspace_get_free_with_retry(size, mspace, retry_count, thread);
264 if (t != NULL) {
265 t->set_lease();
266 }
267 return t;
268}
269
270template <typename Mspace>
271inline typename Mspace::Type* mspace_get_lease(size_t size, Mspace* mspace, Thread* thread) {
272 typename Mspace::Type* t;
273 t = mspace_get_free_lease(size, mspace, thread);
274 if (t != NULL) {
275 assert(t->acquired_by_self(), "invariant");
276 assert(t->lease(), "invariant");
277 return t;
278 }
279 t = mspace_allocate_transient_to_full(size, mspace, thread);
280 if (t != NULL) {
281 t->set_lease();
282 }
283 return t;
284}
285
286template <typename Mspace>
287inline void mspace_release_full(typename Mspace::Type* t, Mspace* mspace) {
288 assert(t != NULL, "invariant");
289 assert(t->unflushed_size() == 0, "invariant");
290 assert(mspace != NULL, "invariant");
291 assert(mspace->is_locked(), "invariant");
292 mspace->release_full(t);
293}
294
295template <typename Mspace>
296inline void mspace_release_free(typename Mspace::Type* t, Mspace* mspace) {
297 assert(t != NULL, "invariant");
298 assert(t->unflushed_size() == 0, "invariant");
299 assert(mspace != NULL, "invariant");
300 assert(mspace->is_locked(), "invariant");
301 mspace->release_free(t);
302}
303
304template <typename Mspace>
305inline void mspace_release_full_critical(typename Mspace::Type* t, Mspace* mspace) {
306 MspaceLock<Mspace> lock(mspace);
307 mspace_release_full(t, mspace);
308}
309
310template <typename Mspace>
311inline void mspace_release_free_critical(typename Mspace::Type* t, Mspace* mspace) {
312 MspaceLock<Mspace> lock(mspace);
313 mspace_release_free(t, mspace);
314}
315
316template <typename List>
317inline void move_to_head(typename List::Node* t, List& from, List& to) {
318 assert(from.in_list(t), "invariant");
319 to.prepend(from.remove(t));
320}
321
322template <typename Processor, typename Mspace, typename Iterator>
323inline void process_free_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
324 mspace->template iterate<Processor, Iterator>(processor, false, direction);
325}
326
327template <typename Processor, typename Mspace, typename Iterator>
328inline void process_full_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
329 mspace->template iterate<Processor, Iterator>(processor, true, direction);
330}
331
332template <typename Processor, typename Mspace>
333inline void process_full_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
334 assert(mspace != NULL, "invariant");
335 if (mspace->is_full_empty()) return;
336 process_full_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction);
337}
338
339template <typename Processor, typename Mspace>
340inline void process_free_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
341 assert(mspace != NULL, "invariant");
342 assert(mspace->has_free(), "invariant");
343 process_free_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction);
344}
345
346template <typename Mspace>
347inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) {
348 assert(t != NULL, "invariant");
349 // assumes some means of exclusive access to t
350 if (t->transient()) {
351 if (_release_full) {
352 mspace_release_full_critical(t, _mspace);
353 } else {
354 mspace_release_free_critical(t, _mspace);
355 }
356 return true;
357 }
358 t->reinitialize();
359 assert(t->empty(), "invariant");
360 assert(!t->retired(), "invariant");
361 t->release(); // publish
362 return true;
363}
364
365#ifdef ASSERT
366template <typename T>
367inline void assert_migration_state(const T* old, const T* new_buffer, size_t used, size_t requested) {
368 assert(old != NULL, "invariant");
369 assert(new_buffer != NULL, "invariant");
370 assert(old->pos() >= old->start(), "invariant");
371 assert(old->pos() + used <= old->end(), "invariant");
372 assert(new_buffer->free_size() >= (used + requested), "invariant");
373}
374#endif // ASSERT
375
376template <typename T>
377inline void migrate_outstanding_writes(const T* old, T* new_buffer, size_t used, size_t requested) {
378 DEBUG_ONLY(assert_migration_state(old, new_buffer, used, requested);)
379 if (used > 0) {
380 memcpy(new_buffer->pos(), old->pos(), used);
381 }
382}
383
384#endif // SHARE_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
385