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_WRITERS_JFRSTORAGEADAPTER_HPP
26#define SHARE_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
27
28#include "jfr/utilities/jfrAllocation.hpp"
29
30class Thread;
31
32//
33// The adapters present writers with a uniform interface over storage.
34//
35// Adapter policy
36//
37// StorageType* storage();
38// const u1* start() const;
39// const u1* pos();
40// const u1* end() const;
41// void commit(u1* position);
42// bool flush(size_t used, size_t requested);
43// void release();
44//
45
46template <typename Flush>
47class Adapter {
48 public:
49 typedef typename Flush::Type StorageType;
50 Adapter(StorageType* storage, Thread* thread) : _storage(storage), _thread(thread) {}
51 Adapter(Thread* thread) : _storage(NULL), _thread(thread) {}
52
53 void set_storage(StorageType* storage) {
54 _storage = storage;
55 }
56
57 StorageType* storage() {
58 return _storage;
59 }
60
61 const u1* start() const {
62 assert(_storage != NULL, "invariant");
63 return _storage->start();
64 }
65
66 u1* pos() {
67 assert(_storage != NULL, "invariant");
68 return _storage->pos();
69 }
70
71 const u1* end() const {
72 assert(_storage != NULL, "invariant");
73 return _storage->end();
74 }
75
76 void commit(u1* position) {
77 assert(_storage != NULL, "invariant");
78 _storage->set_pos(position);
79 }
80
81 bool flush(size_t used, size_t requested) {
82 assert(_thread != NULL, "invariant");
83 Flush f(_storage, used, requested, _thread);
84 _storage = f.result();
85 return _storage != NULL;
86 }
87
88 void release() {
89 if (_storage != NULL && _storage->lease()) {
90 // This flush call will return the lease
91 // of a temporary storage area.
92 // Since the requested size is 0,
93 // the flush implementation will accomodate
94 // that 'size' request in the
95 // original thread local storage,
96 // by implication restoring the original
97 // in the process of returning a lease.
98 flush(0, 0);
99 }
100 }
101
102 private:
103 StorageType* _storage;
104 Thread* _thread;
105};
106
107template <size_t DEFAULT_SIZE = K>
108class MallocAdapter {
109 private:
110 u1* _start;
111 u1* _pos;
112 u1* _end;
113 size_t _initial_size;
114 bool _has_ownership;
115
116 bool allocate(size_t size);
117 void deallocate();
118
119 public:
120 typedef u1 StorageType;
121 MallocAdapter(u1* storage, Thread* thread);
122 MallocAdapter(u1* storage, size_t size);
123 MallocAdapter(Thread* thread);
124 ~MallocAdapter();
125
126 StorageType* storage() { return _start; }
127 const u1* start() const { return _start; }
128 u1* pos() { return _pos; }
129 void commit(u1* position) { _pos = position; }
130 const u1* end() const { return _end; }
131 void release() {}
132 bool flush(size_t used, size_t requested);
133};
134
135template <size_t DEFAULT_SIZE>
136MallocAdapter<DEFAULT_SIZE>::MallocAdapter(u1* storage, size_t size) :
137 _start(storage),
138 _pos(storage),
139 _end(storage + size),
140 _initial_size(size),
141 _has_ownership(false) {
142}
143
144template <size_t DEFAULT_SIZE>
145MallocAdapter<DEFAULT_SIZE> ::MallocAdapter(u1* storage, Thread* thread) :
146 _start(storage),
147 _pos(storage),
148 _end(storage),
149 _initial_size(0),
150 _has_ownership(false) {
151}
152
153template <size_t DEFAULT_SIZE>
154MallocAdapter<DEFAULT_SIZE>::MallocAdapter(Thread* thread) :
155 _start(NULL),
156 _pos(NULL),
157 _end(NULL),
158 _initial_size(DEFAULT_SIZE),
159 _has_ownership(true) {
160 allocate(DEFAULT_SIZE);
161}
162
163template <size_t DEFAULT_SIZE>
164MallocAdapter<DEFAULT_SIZE>::~MallocAdapter() {
165 if (_has_ownership) {
166 deallocate();
167 }
168}
169
170template <size_t DEFAULT_SIZE>
171bool MallocAdapter<DEFAULT_SIZE>::allocate(size_t size) {
172 if (NULL == _start) {
173 _start = JfrCHeapObj::new_array<u1>(size);
174 if (_start) {
175 _pos = _start;
176 _end = _start + size;
177 _initial_size = size;
178 }
179 }
180 return _start != NULL;
181}
182
183template <size_t DEFAULT_SIZE>
184void MallocAdapter<DEFAULT_SIZE>::deallocate() {
185 if (_start != NULL) {
186 JfrCHeapObj::free(_start, (size_t)(_end - _start));
187 }
188}
189
190template <size_t DEFAULT_SIZE>
191bool MallocAdapter<DEFAULT_SIZE>::flush(size_t used, size_t requested) {
192 if (!_has_ownership) {
193 // can't just realloc a storage that we don't own
194 return false;
195 }
196 assert(_start != NULL, "invariant");
197 assert(used <= (size_t)(_end - _pos), "invariant");
198 assert(_pos + used <= _end, "invariant");
199 const size_t previous_storage_size = _end - _start;
200 const size_t new_storage_size = used + requested + (previous_storage_size * 2);
201 u1* const new_storage = JfrCHeapObj::new_array<u1>(new_storage_size);
202 if (!new_storage) {
203 return false;
204 }
205 const size_t previous_pos_offset = _pos - _start;
206 // migrate in-flight data
207 memcpy(new_storage, _start, previous_pos_offset + used);
208 JfrCHeapObj::free(_start, previous_storage_size);
209 _start = new_storage;
210 _pos = _start + previous_pos_offset;
211 _end = _start + new_storage_size;
212 return true;
213}
214
215class NoOwnershipAdapter {
216 private:
217 u1* _start;
218 u1* _pos;
219 u1* _end;
220 size_t _size;
221
222 public:
223 typedef u1 StorageType;
224 NoOwnershipAdapter(u1* storage, size_t size) : _start(storage), _pos(storage), _end(storage + size), _size(size) {}
225 NoOwnershipAdapter(u1* storage, Thread* thread) : _start(storage), _pos(storage), _end(storage), _size(0) {
226 ShouldNotCallThis();
227 }
228 NoOwnershipAdapter(Thread* thread) : _start(NULL), _pos(NULL), _end(NULL), _size(0) {
229 ShouldNotCallThis();
230 }
231 StorageType* storage() { return _start; }
232 const u1* start() const { return _start; }
233 u1* pos() { return _pos; }
234 void commit(u1* position) { _pos = position; }
235 const u1* end() const { return _end; }
236 void release() {}
237 bool flush(size_t used, size_t requested) {
238 // don't flush/expand a buffer that is not our own
239 return false;
240 }
241};
242
243#endif // SHARE_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
244