9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.foreign;
27
28 import jdk.internal.foreign.MemorySessionImpl;
29 import jdk.internal.javac.PreviewFeature;
30 import jdk.internal.ref.CleanerFactory;
31
32 import java.lang.foreign.MemorySegment.Scope;
33
34 /**
35 * An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.
36 * <p>
37 * An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. All the segments allocated
38 * by the arena are associated with the arena scope. As such, the arena determines the temporal bounds
39 * of all the memory segments allocated by it.
40 * <p>
41 * Moreover, an arena also determines whether access to memory segments allocated by it should be
42 * {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads.
43 * An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients
44 * to obtain native segments.
45 * <p>
46 * The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
47 * features an <em>unbounded lifetime</em>. As such, native segments allocated with the global arena are always
48 * accessible and their backing regions of memory are never deallocated. Moreover, memory segments allocated with the
49 * global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
167 * return slicingAllocator.allocate(byteSize, byteAlignment);
168 * }
169 *
170 * public MemorySegment.Scope scope() {
171 * return arena.scope();
172 * }
173 *
174 * public void close() {
175 * arena.close();
176 * }
177 *
178 * }
179 * }
180 *
181 * In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining
182 * the timely deallocation guarantee provided by the underlying confined arena:
183 *
184 * {@snippet lang = java:
185 * try (Arena slicingArena = new SlicingArena(1000)) {
186 * for (int i = 0; i < 10; i++) {
187 * MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
188 * ...
189 * }
190 * } // all memory allocated is released here
191 * }
192 *
193 * @implSpec
194 * Implementations of this interface are thread-safe.
195 *
196 * @see MemorySegment
197 *
198 * @since 20
199 */
200 @PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
201 public interface Arena extends SegmentAllocator, AutoCloseable {
202
203 /**
204 * Creates a new arena that is managed, automatically, by the garbage collector.
205 * Segments allocated with the returned arena can be
206 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
207 * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
208 *
209 * @return a new arena that is managed, automatically, by the garbage collector.
210 */
211 static Arena ofAuto() {
212 return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
213 }
214
215 /**
216 * Obtains the global arena. Segments allocated with the global arena can be
217 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
218 * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
219 *
220 * @return the global arena.
221 */
222 static Arena global() {
223 class Holder {
224 static final Arena GLOBAL = MemorySessionImpl.GLOBAL.asArena();
225 }
226 return Holder.GLOBAL;
227 }
228
229 /**
230 * {@return a new confined arena} Segments allocated with the confined arena can be
231 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena,
232 * the arena's <em>owner thread</em>.
233 */
234 static Arena ofConfined() {
235 return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
236 }
237
238 /**
239 * {@return a new shared arena} Segments allocated with the global arena can be
240 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
241 */
242 static Arena ofShared() {
243 return MemorySessionImpl.createShared().asArena();
244 }
252 *
253 * @implSpec
254 * Implementations of this method must return a native segment featuring the requested size,
255 * and that is compatible with the provided alignment constraint. Furthermore, for any two segments
256 * {@code S1, S2} returned by this method, the following invariant must hold:
257 *
258 * {@snippet lang = java:
259 * S1.asOverlappingSlice(S2).isEmpty() == true
260 * }
261 *
262 * @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
263 * @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
264 * @return a new native memory segment.
265 * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0}, or if {@code byteAlignment}
266 * is not a power of 2.
267 * @throws IllegalStateException if this arena has already been {@linkplain #close() closed}.
268 * @throws WrongThreadException if this arena is confined, and this method is called from a thread
269 * other than the arena's owner thread.
270 */
271 @Override
272 default MemorySegment allocate(long byteSize, long byteAlignment) {
273 return ((MemorySessionImpl)scope()).allocate(byteSize, byteAlignment);
274 }
275
276 /**
277 * {@return the arena scope}
278 */
279 Scope scope();
280
281 /**
282 * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive},
283 * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
284 * segments obtained from this arena are also released.
285 *
286 * @apiNote This operation is not idempotent; that is, closing an already closed arena <em>always</em> results in an
287 * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
288 * in the underlying application logic.
289 *
290 * @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}.
291 * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is
292 * not supported.
293 *
294 * @see Scope#isAlive()
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.foreign;
27
28 import jdk.internal.foreign.MemorySessionImpl;
29 import jdk.internal.ref.CleanerFactory;
30
31 import java.lang.foreign.MemorySegment.Scope;
32
33 /**
34 * An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.
35 * <p>
36 * An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. All the segments allocated
37 * by the arena are associated with the arena scope. As such, the arena determines the temporal bounds
38 * of all the memory segments allocated by it.
39 * <p>
40 * Moreover, an arena also determines whether access to memory segments allocated by it should be
41 * {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads.
42 * An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients
43 * to obtain native segments.
44 * <p>
45 * The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
46 * features an <em>unbounded lifetime</em>. As such, native segments allocated with the global arena are always
47 * accessible and their backing regions of memory are never deallocated. Moreover, memory segments allocated with the
48 * global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
166 * return slicingAllocator.allocate(byteSize, byteAlignment);
167 * }
168 *
169 * public MemorySegment.Scope scope() {
170 * return arena.scope();
171 * }
172 *
173 * public void close() {
174 * arena.close();
175 * }
176 *
177 * }
178 * }
179 *
180 * In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining
181 * the timely deallocation guarantee provided by the underlying confined arena:
182 *
183 * {@snippet lang = java:
184 * try (Arena slicingArena = new SlicingArena(1000)) {
185 * for (int i = 0; i < 10; i++) {
186 * MemorySegment s = slicingArena.allocateFrom(JAVA_INT, 1, 2, 3, 4, 5);
187 * ...
188 * }
189 * } // all memory allocated is released here
190 * }
191 *
192 * @implSpec
193 * Implementations of this interface are thread-safe.
194 *
195 * @see MemorySegment
196 *
197 * @since 22
198 */
199 public interface Arena extends SegmentAllocator, AutoCloseable {
200
201 /**
202 * Creates a new arena that is managed, automatically, by the garbage collector.
203 * Segments allocated with the returned arena can be
204 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
205 * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
206 *
207 * @return a new arena that is managed, automatically, by the garbage collector.
208 */
209 static Arena ofAuto() {
210 return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
211 }
212
213 /**
214 * Obtains the global arena. Segments allocated with the global arena can be
215 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
216 * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
217 *
218 * @return the global arena.
219 */
220 static Arena global() {
221 class Holder {
222 static final Arena GLOBAL = MemorySessionImpl.createGlobal().asArena();
223 }
224 return Holder.GLOBAL;
225 }
226
227 /**
228 * {@return a new confined arena} Segments allocated with the confined arena can be
229 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena,
230 * the arena's <em>owner thread</em>.
231 */
232 static Arena ofConfined() {
233 return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
234 }
235
236 /**
237 * {@return a new shared arena} Segments allocated with the global arena can be
238 * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
239 */
240 static Arena ofShared() {
241 return MemorySessionImpl.createShared().asArena();
242 }
250 *
251 * @implSpec
252 * Implementations of this method must return a native segment featuring the requested size,
253 * and that is compatible with the provided alignment constraint. Furthermore, for any two segments
254 * {@code S1, S2} returned by this method, the following invariant must hold:
255 *
256 * {@snippet lang = java:
257 * S1.asOverlappingSlice(S2).isEmpty() == true
258 * }
259 *
260 * @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
261 * @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
262 * @return a new native memory segment.
263 * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0}, or if {@code byteAlignment}
264 * is not a power of 2.
265 * @throws IllegalStateException if this arena has already been {@linkplain #close() closed}.
266 * @throws WrongThreadException if this arena is confined, and this method is called from a thread
267 * other than the arena's owner thread.
268 */
269 @Override
270 MemorySegment allocate(long byteSize, long byteAlignment);
271
272 /**
273 * {@return the arena scope}
274 */
275 Scope scope();
276
277 /**
278 * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive},
279 * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
280 * segments obtained from this arena are also released.
281 *
282 * @apiNote This operation is not idempotent; that is, closing an already closed arena <em>always</em> results in an
283 * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
284 * in the underlying application logic.
285 *
286 * @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}.
287 * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is
288 * not supported.
289 *
290 * @see Scope#isAlive()
|