1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 /**
20  * Class that implements the condition variable locking paradigm.
21  *
22  * <p>
23  * This differs from the built-in java.lang.Object wait() and notify()
24  * in that this class contains the condition to wait on itself.  That means
25  * open(), close() and block() are sticky.  If open() is called before block(),
26  * block() will not block, and instead return immediately.
27  *
28  * <p>
29  * This class uses itself as the object to wait on, so if you wait()
30  * or notify() on a ConditionVariable, the results are undefined.
31  */
32 @android.ravenwood.annotation.RavenwoodKeepWholeClass
33 public class ConditionVariable
34 {
35     private volatile boolean mCondition;
36 
37     /**
38      * Create the ConditionVariable in the default closed state.
39      */
ConditionVariable()40     public ConditionVariable()
41     {
42         mCondition = false;
43     }
44 
45     /**
46      * Create the ConditionVariable with the given state.
47      *
48      * <p>
49      * Pass true for opened and false for closed.
50      */
ConditionVariable(boolean state)51     public ConditionVariable(boolean state)
52     {
53         mCondition = state;
54     }
55 
56     /**
57      * Open the condition, and release all threads that are blocked.
58      *
59      * <p>
60      * Any threads that later approach block() will not block unless close()
61      * is called.
62      */
open()63     public void open()
64     {
65         synchronized (this) {
66             boolean old = mCondition;
67             mCondition = true;
68             if (!old) {
69                 this.notifyAll();
70             }
71         }
72     }
73 
74     /**
75      * Reset the condition to the closed state.
76      *
77      * <p>
78      * Any threads that call block() will block until someone calls open.
79      */
close()80     public void close()
81     {
82         synchronized (this) {
83             mCondition = false;
84         }
85     }
86 
87     /**
88      * Block the current thread until the condition is opened.
89      *
90      * <p>
91      * If the condition is already opened, return immediately.
92      */
block()93     public void block()
94     {
95         synchronized (this) {
96             while (!mCondition) {
97                 try {
98                     this.wait();
99                 }
100                 catch (InterruptedException e) {
101                 }
102             }
103         }
104     }
105 
106     /**
107      * Block the current thread until the condition is opened or until
108      * timeoutMs milliseconds have passed.
109      *
110      * <p>
111      * If the condition is already opened, return immediately.
112      *
113      * @param timeoutMs the maximum time to wait in milliseconds.
114      *
115      * @return true if the condition was opened, false if the call returns
116      * because of the timeout.
117      */
block(long timeoutMs)118     public boolean block(long timeoutMs)
119     {
120         // Object.wait(0) means wait forever, to mimic this, we just
121         // call the other block() method in that case.  It simplifies
122         // this code for the common case.
123         if (timeoutMs != 0) {
124             synchronized (this) {
125                 long now = SystemClock.elapsedRealtime();
126                 long end = now + timeoutMs;
127                 while (!mCondition && now < end) {
128                     try {
129                         this.wait(end-now);
130                     }
131                     catch (InterruptedException e) {
132                     }
133                     now = SystemClock.elapsedRealtime();
134                 }
135                 return mCondition;
136             }
137         } else {
138             this.block();
139             return true;
140         }
141     }
142 }
143