< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/SharedScope.java

Print this page

  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.misc.ScopedMemoryAccess;

 30 
 31 import java.lang.invoke.MethodHandles;
 32 import java.lang.invoke.VarHandle;
 33 import java.lang.ref.Cleaner;
 34 import java.lang.ref.Reference;
 35 import java.util.concurrent.atomic.AtomicBoolean;
 36 
 37 /**
 38  * A shared scope, which can be shared across multiple threads. Closing a shared scope has to ensure that
 39  * (i) only one thread can successfully close a scope (e.g. in a close vs. close race) and that
 40  * (ii) no other thread is accessing the memory associated with this scope while the segment is being
 41  * closed. To ensure the former condition, a CAS is performed on the liveness bit. Ensuring the latter
 42  * is trickier, and require a complex synchronization protocol (see {@link jdk.internal.misc.ScopedMemoryAccess}).
 43  * Since it is the responsibility of the closing thread to make sure that no concurrent access is possible,
 44  * checking the liveness bit upon access can be performed in plain mode, as in the confined case.
 45  */
 46 class SharedScope extends ResourceScopeImpl {
 47 
 48     private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
 49 
 50     private static final int ALIVE = 0;
 51     private static final int CLOSING = -1;
 52     private static final int CLOSED = -2;
 53     private static final int MAX_FORKS = Integer.MAX_VALUE;
 54 
 55     private int state = ALIVE;
 56 
 57     private static final VarHandle STATE;
 58 
 59     static {
 60         try {
 61             STATE = MethodHandles.lookup().findVarHandle(jdk.internal.foreign.SharedScope.class, "state", int.class);
 62         } catch (Throwable ex) {
 63             throw new ExceptionInInitializerError(ex);
 64         }
 65     }
 66 
 67     SharedScope(Cleaner cleaner) {
 68         super(cleaner, new SharedResourceList());
 69     }
 70 
 71     @Override
 72     public Thread ownerThread() {
 73         return null;
 74     }
 75 
 76     @Override
 77     public void checkValidState() {
 78         if (state < ALIVE) {
 79             throw ScopedAccessError.INSTANCE;
 80         }
 81     }
 82 
 83     @Override
 84     public HandleImpl acquire() {

 85         int value;
 86         do {
 87             value = (int) STATE.getVolatile(this);
 88             if (value < ALIVE) {
 89                 //segment is not alive!
 90                 throw new IllegalStateException("Already closed");
 91             } else if (value == MAX_FORKS) {
 92                 //overflow
 93                 throw new IllegalStateException("Segment acquire limit exceeded");
 94             }
 95         } while (!STATE.compareAndSet(this, value, value + 1));
 96         return new SharedHandle();












 97     }
 98 
 99     void justClose() {
100         int prevState = (int) STATE.compareAndExchange(this, ALIVE, CLOSING);
101         if (prevState < 0) {
102             throw new IllegalStateException("Already closed");
103         } else if (prevState != ALIVE) {
104             throw new IllegalStateException("Scope is acquired by " + prevState + " locks");
105         }
106         boolean success = SCOPED_MEMORY_ACCESS.closeScope(this);
107         STATE.setVolatile(this, success ? CLOSED : ALIVE);
108         if (!success) {
109             throw new IllegalStateException("Cannot close while another thread is accessing the segment");
110         }
111     }
112 
113     @Override
114     public boolean isAlive() {
115         return (int) STATE.getVolatile(this) != CLOSED;
116     }
117 
118     /**
119      * A shared resource list; this implementation has to handle add vs. add races, as well as add vs. cleanup races.
120      */
121     static class SharedResourceList extends ResourceList {
122 
123         static final VarHandle FST;
124 

150             // At this point we are only interested about add vs. close races - not close vs. close
151             // (because MemoryScope::justClose ensured that this thread won the race to close the scope).
152             // So, the only "bad" thing that could happen is that some other thread adds to this list
153             // while we're closing it.
154             if (FST.getAcquire(this) != ResourceCleanup.CLOSED_LIST) {
155                 //ok now we're really closing down
156                 ResourceCleanup prev = null;
157                 while (true) {
158                     prev = (ResourceCleanup) FST.getAcquire(this);
159                     // no need to check for DUMMY, since only one thread can get here!
160                     if (FST.weakCompareAndSetRelease(this, prev, ResourceCleanup.CLOSED_LIST)) {
161                         break;
162                     }
163                 }
164                 cleanup(prev);
165             } else {
166                 throw new IllegalStateException("Attempt to cleanup an already closed resource list");
167             }
168         }
169     }
170 
171     /**
172      * A shared resource scope handle; this implementation has to handle close vs. close races.
173      */
174     class SharedHandle implements HandleImpl {
175         final AtomicBoolean released = new AtomicBoolean(false);
176 
177         @Override
178         public ResourceScopeImpl scope() {
179             return SharedScope.this;
180         }
181 
182         @Override
183         public void release() {
184             if (released.compareAndSet(false, true)) {
185                 int value;
186                 do {
187                     value = (int) STATE.getVolatile(jdk.internal.foreign.SharedScope.this);
188                     if (value <= ALIVE) {
189                         //cannot get here - we can't close segment twice
190                         throw new IllegalStateException("Already closed");
191                     }
192                 } while (!STATE.compareAndSet(jdk.internal.foreign.SharedScope.this, value, value - 1));
193             }
194         }
195     }
196 }

  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.internal.misc.ScopedMemoryAccess;
 29 import jdk.internal.vm.annotation.ForceInline;
 30 
 31 import java.lang.invoke.MethodHandles;
 32 import java.lang.invoke.VarHandle;
 33 import java.lang.ref.Cleaner;


 34 
 35 /**
 36  * A shared scope, which can be shared across multiple threads. Closing a shared scope has to ensure that
 37  * (i) only one thread can successfully close a scope (e.g. in a close vs. close race) and that
 38  * (ii) no other thread is accessing the memory associated with this scope while the segment is being
 39  * closed. To ensure the former condition, a CAS is performed on the liveness bit. Ensuring the latter
 40  * is trickier, and require a complex synchronization protocol (see {@link jdk.internal.misc.ScopedMemoryAccess}).
 41  * Since it is the responsibility of the closing thread to make sure that no concurrent access is possible,
 42  * checking the liveness bit upon access can be performed in plain mode, as in the confined case.
 43  */
 44 class SharedScope extends ResourceScopeImpl {
 45 
 46     private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
 47 
 48     private static final int ALIVE = 0;
 49     private static final int CLOSING = -1;
 50     private static final int CLOSED = -2;

 51 
 52     private int state = ALIVE;
 53 
 54     private static final VarHandle STATE;
 55 
 56     static {
 57         try {
 58             STATE = MethodHandles.lookup().findVarHandle(jdk.internal.foreign.SharedScope.class, "state", int.class);
 59         } catch (Throwable ex) {
 60             throw new ExceptionInInitializerError(ex);
 61         }
 62     }
 63 
 64     SharedScope(Cleaner cleaner) {
 65         super(new SharedResourceList(), cleaner);
 66     }
 67 
 68     @Override
 69     public Thread ownerThread() {
 70         return null;
 71     }
 72 
 73     @Override
 74     public void checkValidState() {
 75         if (state < ALIVE) {
 76             throw ScopedAccessError.INSTANCE;
 77         }
 78     }
 79 
 80     @Override
 81     @ForceInline
 82     public void acquire0() {
 83         int value;
 84         do {
 85             value = (int) STATE.getVolatile(this);
 86             if (value < ALIVE) {
 87                 //segment is not alive!
 88                 throw new IllegalStateException("Already closed");
 89             } else if (value == MAX_FORKS) {
 90                 //overflow
 91                 throw new IllegalStateException("Scope keep alive limit exceeded");
 92             }
 93         } while (!STATE.compareAndSet(this, value, value + 1));
 94     }
 95 
 96     @Override
 97     @ForceInline
 98     public void release0() {
 99         int value;
100         do {
101             value = (int) STATE.getVolatile(jdk.internal.foreign.SharedScope.this);
102             if (value <= ALIVE) {
103                 //cannot get here - we can't close segment twice
104                 throw new IllegalStateException("Already closed");
105             }
106         } while (!STATE.compareAndSet(jdk.internal.foreign.SharedScope.this, value, value - 1));
107     }
108 
109     void justClose() {
110         int prevState = (int) STATE.compareAndExchange(this, ALIVE, CLOSING);
111         if (prevState < 0) {
112             throw new IllegalStateException("Already closed");
113         } else if (prevState != ALIVE) {
114             throw new IllegalStateException("Scope is kept alive by " + prevState + " scopes");
115         }
116         boolean success = SCOPED_MEMORY_ACCESS.closeScope(this);
117         STATE.setVolatile(this, success ? CLOSED : ALIVE);
118         if (!success) {
119             throw new IllegalStateException("Cannot close while another thread is accessing the segment");
120         }
121     }
122 
123     @Override
124     public boolean isAlive() {
125         return (int) STATE.getVolatile(this) != CLOSED;
126     }
127 
128     /**
129      * A shared resource list; this implementation has to handle add vs. add races, as well as add vs. cleanup races.
130      */
131     static class SharedResourceList extends ResourceList {
132 
133         static final VarHandle FST;
134 

160             // At this point we are only interested about add vs. close races - not close vs. close
161             // (because MemoryScope::justClose ensured that this thread won the race to close the scope).
162             // So, the only "bad" thing that could happen is that some other thread adds to this list
163             // while we're closing it.
164             if (FST.getAcquire(this) != ResourceCleanup.CLOSED_LIST) {
165                 //ok now we're really closing down
166                 ResourceCleanup prev = null;
167                 while (true) {
168                     prev = (ResourceCleanup) FST.getAcquire(this);
169                     // no need to check for DUMMY, since only one thread can get here!
170                     if (FST.weakCompareAndSetRelease(this, prev, ResourceCleanup.CLOSED_LIST)) {
171                         break;
172                     }
173                 }
174                 cleanup(prev);
175             } else {
176                 throw new IllegalStateException("Attempt to cleanup an already closed resource list");
177             }
178         }
179     }


























180 }
< prev index next >