1 /*
 2  * Copyright (c) 2020, 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.misc;
27 
28 import java.util.Set;
29 import java.util.concurrent.ConcurrentHashMap;
30 
31 /**
32  * A gate object to detect reentrancy. A thread that enters the gate must exit
33  * before it can enter again. Multiple threads can be "inside" at the same time.
34  * A set of threads to track those that are inside to avoid using ThreadLocals.
35  */
36 public class Gate {
37     private final Set<Thread> threads = ConcurrentHashMap.newKeySet();
38 
39     private Gate() { }
40 
41     /**
42      * Creates a new gate.
43      */
44     public static Gate create() {
45         return new Gate();
46     }
47 
48     /**
49      * Enters if not already inside. The current thread is added to the set of threads
50      * that are inside, if not already in the set.
51      * @return true if the current thread entered, false if already inside.
52      */
53     public boolean tryEnter() {
54         return threads.add(Thread.currentThread());
55     }
56 
57     /**
58      * Enter. The current thread is added to the set of threads that are inside.
59      * @throws IllegalStateException if current thread is already inside
60      */
61     public void enter() {
62         if (!tryEnter())
63             throw new IllegalStateException();
64     }
65 
66     /**
67      * Exit. The current thread is removed from the set of threads that are inside.
68      * @throws IllegalStateException if the current thread is not inside
69      */
70     public void exit() {
71         boolean removed = threads.remove(Thread.currentThread());
72         if (!removed)
73             throw new IllegalStateException();
74     }
75 
76     /**
77      * Returns true if the current thread is inside.
78      */
79     public boolean inside() {
80         return threads.contains(Thread.currentThread());
81     }
82 }