1 /*
  2  * Copyright (c) 2021, 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 jdk.incubator.foreign;
 27 
 28 import jdk.internal.foreign.ResourceScopeImpl;
 29 
 30 import java.lang.invoke.MethodHandle;
 31 import java.lang.ref.Cleaner;
 32 import java.nio.channels.FileChannel;
 33 import java.nio.file.Path;
 34 import java.util.Objects;
 35 import java.util.Spliterator;
 36 
 37 /**
 38  * A resource scope manages the lifecycle of one or more resources. Resources (e.g. {@link MemorySegment}) associated
 39  * with a resource scope can only be accessed while the resource scope is <em>alive</em> (see {@link #isAlive()}),
 40  * and by the thread associated with the resource scope (if any).
 41  *
 42  * <h2>Explicit resource scopes</h2>
 43  *
 44  * Resource scopes obtained from {@link #newConfinedScope()}, {@link #newSharedScope()} support <em>deterministic deallocation</em>;
 45  * We call these resource scopes <em>explicit scopes</em>. Explicit resource scopes can be closed explicitly (see {@link ResourceScope#close()}).
 46  * When a resource scope is closed, it is no longer <em>alive</em> (see {@link #isAlive()}, and subsequent operations on
 47  * resources associated with that scope (e.g. attempting to access a {@link MemorySegment} instance) will fail with {@link IllegalStateException}.
 48  * <p>
 49  * Closing a resource scope will cause all the cleanup actions associated with that scope (see {@link #addCloseAction(Runnable)}) to be called.
 50  * Moreover, closing a resource scope might trigger the releasing of the underlying memory resources associated with said scope; for instance:
 51  * <ul>
 52  *     <li>closing the scope associated with a native memory segment results in <em>freeing</em> the native memory associated with it
 53  *     (see {@link MemorySegment#allocateNative(long, ResourceScope)}, or {@link SegmentAllocator#arenaAllocator(ResourceScope)})</li>
 54  *     <li>closing the scope associated with a mapped memory segment results in the backing memory-mapped file to be unmapped
 55  *     (see {@link MemorySegment#mapFile(Path, long, long, FileChannel.MapMode, ResourceScope)})</li>
 56  *     <li>closing the scope associated with an upcall stub results in releasing the stub
 57  *     (see {@link CLinker#upcallStub(MethodHandle, FunctionDescriptor, ResourceScope)}</li>
 58  * </ul>
 59  * <p>
 60  * Sometimes, explicit scopes can be associated with a {@link Cleaner} instance (see {@link #newConfinedScope(Cleaner)} and
 61  * {@link #newSharedScope(Cleaner)}). We call these resource scopes <em>managed</em> resource scopes. A managed resource scope
 62  * is closed automatically once the scope instance becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>.
 63  * <p>
 64  * Managed scopes can be useful to allow for predictable, deterministic resource deallocation, while still prevent accidental native memory leaks.
 65  * In case a managed resource scope is closed explicitly, no further action will be taken when the scope becomes unreachable;
 66  * that is, cleanup actions (see {@link #addCloseAction(Runnable)}) associated with a resource scope, whether managed or not,
 67  * are called <em>exactly once</em>.
 68  *
 69  * <h2>Implicit resource scopes</h2>
 70  *
 71  * Resource scopes obtained from {@link #newImplicitScope()} cannot be closed explicitly. We call these resource scopes
 72  * <em>implicit scopes</em>. Calling {@link #close()} on an implicit resource scope always results in an exception.
 73  * Resources associated with implicit scopes are released once the scope instance becomes
 74  * <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>.
 75  * <p>
 76  * An important implicit resource scope is the so called {@linkplain #globalScope() global scope}; the global scope is
 77  * an implicit scope that is guaranteed to never become <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>.
 78  * As a results, the global scope will never attempt to release resources associated with it. Such resources must, where
 79  * needed, be managed independently by clients.
 80  *
 81  * <h2><a id = "thread-confinement">Thread confinement</a></h2>
 82  *
 83  * Resource scopes can be further divided into two categories: <em>thread-confined</em> resource scopes, and <em>shared</em>
 84  * resource scopes.
 85  * <p>
 86  * Confined resource scopes (see {@link #newConfinedScope()}), support strong thread-confinement guarantees. Upon creation,
 87  * they are assigned an <em>owner thread</em>, typically the thread which initiated the creation operation (see {@link #ownerThread()}).
 88  * After creating a confined resource scope, only the owner thread will be allowed to directly manipulate the resources
 89  * associated with this resource scope. Any attempt to perform resource access from a thread other than the
 90  * owner thread will result in a runtime failure.
 91  * <p>
 92  * Shared resource scopes (see {@link #newSharedScope()} and {@link #newImplicitScope()}), on the other hand, have no owner thread;
 93  * as such resources associated with this shared resource scopes can be accessed by multiple threads.
 94  * This might be useful when multiple threads need to access the same resource concurrently (e.g. in the case of parallel processing).
 95  * For instance, a client might obtain a {@link Spliterator} from a shared segment, which can then be used to slice the
 96  * segment and allow multiple threads to work in parallel on disjoint segment slices. The following code can be used to sum
 97  * all int values in a memory segment in parallel:
 98  *
 99  * <blockquote><pre>{@code
100 SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_INT);
101 try (ResourceScope scope = ResourceScope.newSharedScope()) {
102     MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, scope);
103     VarHandle VH_int = SEQUENCE_LAYOUT.elementLayout().varHandle(int.class);
104     int sum = StreamSupport.stream(segment.spliterator(SEQUENCE_LAYOUT), true)
105         .mapToInt(s -> (int)VH_int.get(s.address()))
106         .sum();
107 }
108  * }</pre></blockquote>
109  *
110  * <p>
111  * Explicit shared resource scopes, while powerful, must be used with caution: if one or more threads accesses
112  * a resource associated with a shared scope while the scope is being closed from another thread, an exception might occur on both
113  * the accessing and the closing threads. Clients should refrain from attempting to close a shared resource scope repeatedly
114  * (e.g. keep calling {@link #close()} until no exception is thrown). Instead, clients of shared resource scopes
115  * should always ensure that proper synchronization mechanisms (e.g. using resource scope handles, see below) are put in place
116  * so that threads closing shared resource scopes can never race against threads accessing resources managed by same scopes.
117  *
118  * <h2>Resource scope handles</h2>
119  *
120  * Resource scopes can be made <em>non-closeable</em> by acquiring one or more resource scope <em>handles</em> (see
121  * {@link #acquire()}. A resource scope handle can be used to make sure that resources associated with a given resource scope
122  * (either explicit or implicit) cannot be released for a certain period of time - e.g. during a critical region of code
123  * involving one or more resources associated with the scope. For instance, an explicit resource scope can only be closed
124  * <em>after</em> all the handles acquired against that scope have been closed (see {@link Handle#close()}).
125  * This can be useful when clients need to perform a critical operation on a memory segment, during which they have
126  * to ensure that the segment will not be released; this can be done as follows:
127  *
128  * <blockquote><pre>{@code
129 MemorySegment segment = ...
130 ResourceScope.Handle segmentHandle = segment.scope().acquire()
131 try {
132    <critical operation on segment>
133 } finally {
134    segment.scope().release(segmentHandle);
135 }
136  * }</pre></blockquote>
137  *
138  * Acquiring implicit resource scopes is also possible, but it is often unnecessary: since resources associated with
139  * an implicit scope will only be released when the scope becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>,
140  * clients can use e.g. {@link java.lang.ref.Reference#reachabilityFence(Object)} to make sure that resources associated
141  * with implicit scopes are not released prematurely. That said, the above code snippet works (trivially) for implicit scopes too.
142  *
143  * @implSpec
144  * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
145  */
146 public sealed interface ResourceScope extends AutoCloseable permits ResourceScopeImpl {
147     /**
148      * Is this resource scope alive?
149      * @return true, if this resource scope is alive.
150      * @see ResourceScope#close()
151      */
152     boolean isAlive();
153 
154     /**
155      * The thread owning this resource scope.
156      * @return the thread owning this resource scope, or {@code null} if this resource scope is shared.
157      */
158     Thread ownerThread();
159 
160     /**
161      * Is this resource scope an <em>implicit scope</em>?
162      * @return true if this scope is an <em>implicit scope</em>.
163      * @see #newImplicitScope()
164      * @see #globalScope()
165      */
166     boolean isImplicit();
167 
168     /**
169      * Closes this resource scope. As a side-effect, if this operation completes without exceptions, this scope will be marked
170      * as <em>not alive</em>, and subsequent operations on resources associated with this scope will fail with {@link IllegalStateException}.
171      * Additionally, upon successful closure, all native resources associated with this resource scope will be released.
172      *
173      * @apiNote This operation is not idempotent; that is, closing an already closed resource scope <em>always</em> results in an
174      * exception being thrown. This reflects a deliberate design choice: resource scope state transitions should be
175      * manifest in the client code; a failure in any of these transitions reveals a bug in the underlying application
176      * logic.
177      *
178      * @throws IllegalStateException if one of the following condition is met:
179      * <ul>
180      *     <li>this resource scope is not <em>alive</em>
181      *     <li>this resource scope is confined, and this method is called from a thread other than the thread owning this resource scope</li>
182      *     <li>this resource scope is shared and a resource associated with this scope is accessed while this method is called</li>
183      *     <li>one or more handles (see {@link #acquire()}) associated with this resource scope have not been {@linkplain #release(Handle) released}</li>
184      * </ul>
185      * @throws UnsupportedOperationException if this resource scope is {@linkplain #isImplicit() implicit}.
186      */
187     void close();
188 
189     /**
190      * Add a custom cleanup action which will be executed when the resource scope is closed.
191      * The order in which custom cleanup actions are invoked once the scope is closed is unspecified.
192      * @param runnable the custom cleanup action to be associated with this scope.
193      * @throws IllegalStateException if this scope has already been closed.
194      */
195     void addCloseAction(Runnable runnable);
196 
197     /**
198      * Acquires a resource scope handle associated with this resource scope. An explicit resource scope cannot be
199      * {@linkplain #close() closed} until all the resource scope handles acquired from it have been {@linkplain #release(Handle)} released}.
200      * @return a resource scope handle.
201      */
202     Handle acquire();
203 
204     /**
205      * Release the provided resource scope handle. This method is idempotent, that is, releasing the same handle
206      * multiple times has no effect.
207      * @param handle the resource scope handle to be released.
208      * @throws IllegalArgumentException if the provided handle is not associated with this scope.
209      */
210     void release(Handle handle);
211 
212     /**
213      * An abstraction modelling a resource scope handle. A resource scope handle is typically {@linkplain #acquire() acquired} by clients
214      * in order to prevent an explicit resource scope from being closed while executing a certain operation.
215      * Once obtained, resource scope handles can be {@linkplain #release(Handle)} released}; an explicit resource scope can
216      * be closed only <em>after</em> all the resource scope handles acquired from it have been released.
217      */
218     sealed interface Handle permits ResourceScopeImpl.HandleImpl {
219 
220         /**
221          * Returns the resource scope associated with this handle.
222          * @return the resource scope associated with this handle.
223          */
224         ResourceScope scope();
225     }
226 
227     /**
228      * Create a new confined scope. The resulting scope is closeable, and is not managed by a {@link Cleaner}.
229      * @return a new confined scope.
230      */
231     static ResourceScope newConfinedScope() {
232         return ResourceScopeImpl.createConfined( null);
233     }
234 
235     /**
236      * Create a new confined scope managed by a {@link Cleaner}.
237      * @param cleaner the cleaner to be associated with the returned scope.
238      * @return a new confined scope, managed by {@code cleaner}.
239      * @throws NullPointerException if {@code cleaner == null}.
240      */
241     static ResourceScope newConfinedScope(Cleaner cleaner) {
242         Objects.requireNonNull(cleaner);
243         return ResourceScopeImpl.createConfined( cleaner);
244     }
245 
246     /**
247      * Create a new shared scope. The resulting scope is closeable, and is not managed by a {@link Cleaner}.
248      * @return a new shared scope.
249      */
250     static ResourceScope newSharedScope() {
251         return ResourceScopeImpl.createShared(null);
252     }
253 
254     /**
255      * Create a new shared scope managed by a {@link Cleaner}.
256      * @param cleaner the cleaner to be associated with the returned scope.
257      * @return a new shared scope, managed by {@code cleaner}.
258      * @throws NullPointerException if {@code cleaner == null}.
259      */
260     static ResourceScope newSharedScope(Cleaner cleaner) {
261         Objects.requireNonNull(cleaner);
262         return ResourceScopeImpl.createShared(cleaner);
263     }
264 
265     /**
266      * Create a new <em>implicit scope</em>. The implicit scope is a managed, shared, and non-closeable scope which only features
267      * <a href="ResourceScope.html#implicit-closure"><em>implicit closure</em></a>.
268      * Since implicit scopes can only be closed implicitly by the garbage collector, it is recommended that implicit
269      * scopes are only used in cases where deallocation performance is not a critical concern, to avoid unnecessary
270      * memory pressure.
271      *
272      * @return a new implicit scope.
273      */
274     static ResourceScope newImplicitScope() {
275         return ResourceScopeImpl.createImplicitScope();
276     }
277 
278     /**
279      * Returns an implicit scope which is assumed to be always alive.
280      * @return the global scope.
281      */
282     static ResourceScope globalScope() {
283         return ResourceScopeImpl.GLOBAL;
284     }
285 }