1 /*
  2  * Copyright (c) 2022, 2023, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  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.
 49  * {@snippet lang = java:
 50  * MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()'
 51  * ...
 52  * // segment is never deallocated!
 53  *}
 54  * <p>
 55  * Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena
 56  * which features a <em>bounded lifetime</em> that is managed, automatically, by the garbage collector. As such, the regions
 57  * of memory backing memory segments allocated with the automatic arena are deallocated at some unspecified time
 58  * <em>after</em> the automatic arena (and all the segments allocated by it) becomes
 59  * <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below:
 60  * {@snippet lang = java:
 61  * MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
 62  * ...
 63  * segment = null; // the segment region becomes available for deallocation after this point
 64  *}
 65  * Memory segments allocated with an automatic arena can also be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
 66  * <p>
 67  * Rather than leaving deallocation in the hands of the Java runtime, clients will often wish to exercise control over
 68  * the timing of deallocation for regions of memory that back memory segments. Two kinds of arenas support this,
 69  * namely {@linkplain #ofConfined() confined} and {@linkplain #ofShared() shared} arenas. They both feature
 70  * bounded lifetimes that are managed manually. For instance, the lifetime of a confined arena starts when the confined
 71  * arena is created, and ends when the confined arena is {@linkplain #close() closed}. As a result, the regions of memory
 72  * backing memory segments allocated with a confined arena are deallocated when the confined arena is closed.
 73  * When this happens, all the segments allocated with the confined arena are invalidated, and subsequent access
 74  * operations on these segments will fail {@link IllegalStateException}:
 75  *
 76  * {@snippet lang = java:
 77  * MemorySegment segment = null;
 78  * try (Arena arena = Arena.ofConfined()) { // @highlight regex='ofConfined()'
 79  *     segment = arena.allocate(100);
 80  *     ...
 81  * } // segment region deallocated here
 82  * segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException
 83  *}
 84  *
 85  * Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be accessed (and closed) by the
 86  * thread that created the arena. If access to a memory segment from multiple threads is required, clients can allocate
 87  * segments in a {@linkplain #ofShared() shared arena} instead.
 88  * <p>
 89  * The characteristics of the various arenas are summarized in the following table:
 90  *
 91  * <blockquote><table class="plain">
 92  * <caption style="display:none">Arenas characteristics</caption>
 93  * <thead>
 94  * <tr>
 95  *     <th scope="col">Kind</th>
 96  *     <th scope="col">Bounded lifetime</th>
 97  *     <th scope="col">Explicitly closeable</th>
 98  *     <th scope="col">Accessible from multiple threads</th>
 99  * </tr>
100  * </thead>
101  * <tbody>
102  * <tr><th scope="row" style="font-weight:normal">Global</th>
103  *     <td style="text-align:center;">No</td>
104  *     <td style="text-align:center;">No</td>
105  *     <td style="text-align:center;">Yes</td></tr>
106  * <tr><th scope="row" style="font-weight:normal">Automatic</th>
107  *     <td style="text-align:center;">Yes</td>
108  *     <td style="text-align:center;">No</td>
109  *     <td style="text-align:center;">Yes</td></tr>
110  * <tr><th scope="row" style="font-weight:normal">Confined</th>
111  *     <td style="text-align:center;">Yes</td>
112  *     <td style="text-align:center;">Yes</td>
113  *     <td style="text-align:center;">No</td></tr>
114  * <tr><th scope="row" style="font-weight:normal">Shared</th>
115  *     <td style="text-align:center;">Yes</td>
116  *     <td style="text-align:center;">Yes</td>
117  *     <td style="text-align:center;">Yes</td></tr>
118  * </tbody>
119  * </table></blockquote>
120  *
121  * <h2 id = "thread-confinement">Safety and thread-confinement</h2>
122  *
123  * Arenas provide strong temporal safety guarantees: a memory segment allocated by an arena cannot be accessed
124  * <em>after</em> the arena has been closed. The cost of providing this guarantee varies based on the
125  * number of threads that have access to the memory segments allocated by the arena. For instance, if an arena
126  * is always created and closed by one thread, and the memory segments allocated by the arena are always
127  * accessed by that same thread, then ensuring correctness is trivial.
128  * <p>
129  * Conversely, if an arena allocates segments that can be accessed by multiple threads, or if the arena can be closed
130  * by a thread other than the accessing thread, then ensuring correctness is much more complex. For example, a segment
131  * allocated with the arena might be accessed <em>while</em> another thread attempts, concurrently, to close the arena.
132  * To provide the strong temporal safety guarantee without forcing every client, even simple ones, to incur a performance
133  * impact, arenas are divided into <em>thread-confined</em> arenas, and <em>shared</em> arenas.
134  * <p>
135  * Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an
136  * <em>owner thread</em>, typically the thread which initiated the creation operation.
137  * The segments created by a confined arena can only be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed}
138  * by the owner thread. Moreover, any attempt to close the confined arena from a thread other than the owner thread will
139  * fail with {@link WrongThreadException}.
140  * <p>
141  * Shared arenas, on the other hand, have no owner thread. The segments created by a shared arena
142  * can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. This might be useful when
143  * multiple threads need to access the same memory segment concurrently (e.g. in the case of parallel processing).
144  * Moreover, a shared arena can be closed by any thread.
145  *
146  * <h2 id = "custom-arenas">Custom arenas</h2>
147  *
148  * Clients can define custom arenas to implement more efficient allocation strategies, or to have better control over
149  * when (and by whom) an arena can be closed. As an example, the following code defines a <em>slicing arena</em> that behaves
150  * like a confined arena (i.e., single-threaded access), but internally uses a
151  * {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to respond to allocation requests.
152  * When the slicing arena is closed, the underlying confined arena is also closed; this will invalidate all segments
153  * allocated with the slicing arena (since the scope of the slicing arena is the same as that of the underlying
154  * confined arena):
155  *
156  * {@snippet lang = java:
157  * class SlicingArena implements Arena {
158  *     final Arena arena = Arena.ofConfined();
159  *     final SegmentAllocator slicingAllocator;
160  *
161  *     SlicingArena(long size) {
162  *         slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
163  *     }
164  *
165  *     public MemorySegment allocate(long byteSize, long byteAlignment) {
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.GLOBAL.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     }
243 
244     /**
245      * Returns a native memory segment with the given size (in bytes) and alignment constraint (in bytes).
246      * The returned segment is associated with this {@linkplain #scope() arena scope}.
247      * The segment's {@link MemorySegment#address() address} is the starting address of the
248      * allocated off-heap region of memory backing the segment, and the address is
249      * aligned according the provided alignment constraint.
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()
291      *
292      * @throws IllegalStateException if the arena has already been closed.
293      * @throws IllegalStateException if a segment associated with this arena is being accessed concurrently, e.g.
294      * by a {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}.
295      * @throws WrongThreadException if this arena is confined, and this method is called from a thread
296      * other than the arena's owner thread.
297      * @throws UnsupportedOperationException if this arena cannot be closed explicitly.
298      */
299     @Override
300     void close();
301 
302 }