1 /* 2 * Copyright (C) 2015 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 #ifndef ANDROID_GATE_H 18 #define ANDROID_GATE_H 19 20 #include <stdint.h> 21 #include <mutex> 22 23 namespace android { 24 25 // Gate is a synchronization object. 26 // 27 // Threads will pass if it is open. 28 // Threads will block (wait) if it is closed. 29 // 30 // When a gate is opened, all waiting threads will pass through. 31 // 32 // Since gate holds no external locks, consistency with external 33 // state needs to be handled elsewhere. 34 // 35 // We use mWaitCount to indicate the number of threads that have 36 // arrived at the gate via wait(). Each thread entering 37 // wait obtains a unique waitId (which is the current mWaitCount). 38 // This can be viewed as a sequence number. 39 // 40 // We use mPassCount to indicate the number of threads that have 41 // passed the gate. If the waitId is less than or equal to the mPassCount 42 // then that thread has passed the gate. An open gate sets mPassedCount 43 // to the current mWaitCount, allowing all prior threads to pass. 44 // 45 // See sync_timeline, sync_pt, etc. for graphics. 46 47 class Gate { 48 public: 49 Gate(bool open = false) : mOpen(open)50 mOpen(open), 51 mExit(false), 52 mWaitCount(0), 53 mPassCount(0) 54 { } 55 56 // waits for the gate to open, returns immediately if gate is already open. 57 // 58 // Do not hold a monitor lock while calling this. 59 // 60 // returns true if we passed the gate normally 61 // false if gate is terminated and we didn't pass the gate. wait()62 bool wait() { 63 std::unique_lock<std::mutex> l(mLock); 64 size_t waitId = ++mWaitCount; 65 if (mOpen) { 66 mPassCount = waitId; // let me through 67 } 68 while (!passedGate_l(waitId) && !mExit) { 69 mCondition.wait(l); 70 } 71 return passedGate_l(waitId); 72 } 73 74 // close the gate. closeGate()75 void closeGate() { 76 std::lock_guard<std::mutex> l(mLock); 77 mOpen = false; 78 mExit = false; 79 } 80 81 // open the gate. 82 // signal to all waiters it is okay to go. openGate()83 void openGate() { 84 std::lock_guard<std::mutex> l(mLock); 85 mOpen = true; 86 mExit = false; 87 if (waiters_l() > 0) { 88 mPassCount = mWaitCount; // allow waiting threads to go through 89 // unoptimized pthreads will wake thread to find we still hold lock. 90 mCondition.notify_all(); 91 } 92 } 93 94 // terminate (term has expired). 95 // all threads allowed to pass regardless of whether the gate is open or closed. terminate()96 void terminate() { 97 std::lock_guard<std::mutex> l(mLock); 98 mExit = true; 99 if (waiters_l() > 0) { 100 // unoptimized pthreads will wake thread to find we still hold lock. 101 mCondition.notify_all(); 102 } 103 } 104 isOpen()105 bool isOpen() { 106 std::lock_guard<std::mutex> l(mLock); 107 return mOpen; 108 } 109 110 // return how many waiters are at the gate. waiters()111 size_t waiters() { 112 std::lock_guard<std::mutex> l(mLock); 113 return waiters_l(); 114 } 115 116 private: 117 bool mOpen; 118 bool mExit; 119 size_t mWaitCount; // total number of threads that have called wait() 120 size_t mPassCount; // total number of threads passed the gate. 121 std::condition_variable mCondition; 122 std::mutex mLock; 123 124 // return how many waiters are at the gate. waiters_l()125 inline size_t waiters_l() { 126 return mWaitCount - mPassCount; 127 } 128 129 // return whether the waitId (from mWaitCount) has passed through the gate passedGate_l(size_t waitId)130 inline bool passedGate_l(size_t waitId) { 131 return (ssize_t)(waitId - mPassCount) <= 0; 132 } 133 }; 134 135 } // namespace android 136 137 #endif // ANDROID_GATE_H 138