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 public class ConditionVariable
33 {
34     private volatile boolean mCondition;
35 
36     /**
37      * Create the ConditionVariable in the default closed state.
38      */
ConditionVariable()39     public ConditionVariable()
40     {
41         mCondition = false;
42     }
43 
44     /**
45      * Create the ConditionVariable with the given state.
46      *
47      * <p>
48      * Pass true for opened and false for closed.
49      */
ConditionVariable(boolean state)50     public ConditionVariable(boolean state)
51     {
52         mCondition = state;
53     }
54 
55     /**
56      * Open the condition, and release all threads that are blocked.
57      *
58      * <p>
59      * Any threads that later approach block() will not block unless close()
60      * is called.
61      */
open()62     public void open()
63     {
64         synchronized (this) {
65             boolean old = mCondition;
66             mCondition = true;
67             if (!old) {
68                 this.notifyAll();
69             }
70         }
71     }
72 
73     /**
74      * Reset the condition to the closed state.
75      *
76      * <p>
77      * Any threads that call block() will block until someone calls open.
78      */
close()79     public void close()
80     {
81         synchronized (this) {
82             mCondition = false;
83         }
84     }
85 
86     /**
87      * Block the current thread until the condition is opened.
88      *
89      * <p>
90      * If the condition is already opened, return immediately.
91      */
block()92     public void block()
93     {
94         synchronized (this) {
95             while (!mCondition) {
96                 try {
97                     this.wait();
98                 }
99                 catch (InterruptedException e) {
100                 }
101             }
102         }
103     }
104 
105     /**
106      * Block the current thread until the condition is opened or until
107      * timeoutMs milliseconds have passed.
108      *
109      * <p>
110      * If the condition is already opened, return immediately.
111      *
112      * @param timeoutMs the maximum time to wait in milliseconds.
113      *
114      * @return true if the condition was opened, false if the call returns
115      * because of the timeout.
116      */
block(long timeoutMs)117     public boolean block(long timeoutMs)
118     {
119         // Object.wait(0) means wait forever, to mimic this, we just
120         // call the other block() method in that case.  It simplifies
121         // this code for the common case.
122         if (timeoutMs != 0) {
123             synchronized (this) {
124                 long now = SystemClock.elapsedRealtime();
125                 long end = now + timeoutMs;
126                 while (!mCondition && now < end) {
127                     try {
128                         this.wait(end-now);
129                     }
130                     catch (InterruptedException e) {
131                     }
132                     now = SystemClock.elapsedRealtime();
133                 }
134                 return mCondition;
135             }
136         } else {
137             this.block();
138             return true;
139         }
140     }
141 }
142