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.internal.foreign;
 27 
 28 import jdk.incubator.foreign.ResourceScope;
 29 import jdk.internal.vm.annotation.ForceInline;
 30 
 31 import java.lang.ref.Cleaner;
 32 import java.lang.ref.Reference;
 33 
 34 /**
 35  * A confined scope, which features an owner thread. The liveness check features an additional
 36  * confinement check - that is, calling any operation on this scope from a thread other than the
 37  * owner thread will result in an exception. Because of this restriction, checking the liveness bit
 38  * can be performed in plain mode.
 39  */
 40 final class ConfinedScope extends ResourceScopeImpl {
 41 
 42     private boolean closed; // = false
 43     private int lockCount = 0;
 44     private final Thread owner;
 45 
 46     public ConfinedScope(Thread owner, Cleaner cleaner) {
 47         super(cleaner, new ConfinedResourceList());
 48         this.owner = owner;
 49     }
 50 
 51     @ForceInline
 52     public final void checkValidState() {
 53         if (owner != Thread.currentThread()) {
 54             throw new IllegalStateException("Attempted access outside owning thread");
 55         }
 56         if (closed) {
 57             throw new IllegalStateException("Already closed");
 58         }
 59     }
 60 
 61     @Override
 62     public boolean isAlive() {
 63         return !closed;
 64     }
 65 
 66     @Override
 67     public HandleImpl acquire() {
 68         checkValidState();
 69         lockCount++;
 70         return new ConfinedHandle();
 71     }
 72 
 73     void justClose() {
 74         this.checkValidState();
 75         if (lockCount == 0) {
 76             closed = true;
 77         } else {
 78             throw new IllegalStateException("Scope is acquired by " + lockCount + " locks");
 79         }
 80     }
 81 
 82     @Override
 83     public Thread ownerThread() {
 84         return owner;
 85     }
 86 
 87     /**
 88      * A confined resource list; no races are possible here.
 89      */
 90     static final class ConfinedResourceList extends ResourceList {
 91         @Override
 92         void add(ResourceCleanup cleanup) {
 93             if (fst != ResourceCleanup.CLOSED_LIST) {
 94                 cleanup.next = fst;
 95                 fst = cleanup;
 96             } else {
 97                 throw new IllegalStateException("Already closed!");
 98             }
 99         }
100 
101         @Override
102         void cleanup() {
103             if (fst != ResourceCleanup.CLOSED_LIST) {
104                 ResourceCleanup prev = fst;
105                 fst = ResourceCleanup.CLOSED_LIST;
106                 cleanup(prev);
107             } else {
108                 throw new IllegalStateException("Attempt to cleanup an already closed resource list");
109             }
110         }
111     }
112 
113     /**
114      * A confined resource scope handle; no races are possible here.
115      */
116     final class ConfinedHandle implements HandleImpl {
117         boolean released = false;
118 
119         @Override
120         public ResourceScopeImpl scope() {
121             return ConfinedScope.this;
122         }
123 
124         @Override
125         public void release() {
126             checkValidState(); // thread check
127             if (!released) {
128                 released = true;
129                 lockCount--;
130             }
131         }
132     }
133 }