Home | History | Annotate | Download | only in libaudiojni
      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) :
     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.
     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.
     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.
     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.
     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 
    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.
    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.
    125     inline size_t waiters_l() {
    126         return mWaitCount - mPassCount;
    127     }
    128 
    129     // return whether the waitId (from mWaitCount) has passed through the gate
    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