1 /*
2  * Copyright (C) 2016 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_HIDL_SYNCHRONIZED_QUEUE_H
18 #define ANDROID_HIDL_SYNCHRONIZED_QUEUE_H
19 
20 #include <condition_variable>
21 #include <mutex>
22 #include <queue>
23 #include <thread>
24 
25 namespace android {
26 namespace hardware {
27 namespace details {
28 /* Threadsafe queue.
29  */
30 template <typename T>
31 struct SynchronizedQueue {
32     SynchronizedQueue(size_t limit);
33 
34     /* Gets an item from the front of the queue.
35      *
36      * Blocks until the item is available.
37      */
38     T wait_pop();
39 
40     /* Puts an item onto the end of the queue.
41      */
42     bool push(const T& item);
43 
44     /* Gets the size of the array.
45      */
46     size_t size();
47 
lockSynchronizedQueue48     std::unique_lock<std::mutex> lock() {
49         return std::unique_lock<std::mutex>(mMutex);
50     }
51 
isInitializedLockedSynchronizedQueue52     bool isInitializedLocked() {
53         return mInitialized;
54     }
setInitializedLockedSynchronizedQueue55     void setInitializedLocked(bool isInitialized) {
56         mInitialized = isInitialized;
57     }
58 
59 private:
60     std::condition_variable mCondition;
61     std::mutex mMutex;
62     std::queue<T> mQueue;
63     const size_t mQueueLimit;
64     bool mInitialized = false;
65 };
66 
67 template <typename T>
SynchronizedQueue(size_t limit)68 SynchronizedQueue<T>::SynchronizedQueue(size_t limit) : mQueueLimit(limit) {
69 }
70 
71 template <typename T>
wait_pop()72 T SynchronizedQueue<T>::wait_pop() {
73     std::unique_lock<std::mutex> lock(mMutex);
74 
75     mCondition.wait(lock, [this]{
76         return !this->mQueue.empty();
77     });
78 
79     T item = mQueue.front();
80     mQueue.pop();
81 
82     return item;
83 }
84 
85 template <typename T>
push(const T & item)86 bool SynchronizedQueue<T>::push(const T &item) {
87     bool success;
88     {
89         std::unique_lock<std::mutex> lock(mMutex);
90         if (mQueue.size() < mQueueLimit) {
91             mQueue.push(item);
92             success = true;
93         } else {
94             success = false;
95         }
96     }
97 
98     mCondition.notify_one();
99     return success;
100 }
101 
102 template <typename T>
size()103 size_t SynchronizedQueue<T>::size() {
104     std::unique_lock<std::mutex> lock(mMutex);
105 
106     return mQueue.size();
107 }
108 
109 } // namespace details
110 } // namespace hardware
111 } // namespace android
112 
113 #endif // ANDROID_HIDL_SYNCHRONIZED_QUEUE_H
114