1 /*
2  * Copyright (C) 2019 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_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
18 #define android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
19 
20 #include <log/log.h>
21 
22 #include <condition_variable>
23 #include <deque>
24 #include <list>
25 #include <mutex>
26 
27 namespace android {
28 namespace hardware {
29 namespace gnss {
30 namespace common {
31 
32 /*
33  * Producer/consumer queue for storing/retrieving callback events from GNSS HAL.
34  */
35 template <class T>
36 class GnssCallbackEventQueue {
37   public:
GnssCallbackEventQueue(const std::string & name)38     GnssCallbackEventQueue(const std::string& name) : name_(name), called_count_(0){};
~GnssCallbackEventQueue()39     ~GnssCallbackEventQueue() { reset(); }
40 
41     /* Adds callback event to the end of the queue. */
42     void store(const T& event);
43 
44     /*
45      * Removes the callack event at the front of the queue, stores it in event parameter
46      * and returns true. Returns false on timeout and event is not populated.
47      */
48     bool retrieve(T& event, int timeout_seconds);
49 
50     /*
51      * Removes parameter count number of callack events at the front of the queue, stores
52      * them in event_list parameter and returns the number of events retrieved. Waits up to
53      * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
54      * items retrieved which will be less than count.
55      */
56     int retrieve(std::list<T>& event_list, int count, int timeout_seconds);
57 
58     /* Returns the number of events pending to be retrieved from the callback event queue. */
59     int size() const;
60 
61     /* Returns the number of callback events received since last reset(). */
62     int calledCount() const;
63 
64     /* Clears the callback event queue and resets the calledCount() to 0. */
65     void reset();
66 
67   private:
68     GnssCallbackEventQueue(const GnssCallbackEventQueue&) = delete;
69     GnssCallbackEventQueue& operator=(const GnssCallbackEventQueue&) = delete;
70 
71     std::string name_;
72     int called_count_;
73     mutable std::recursive_mutex mtx_;
74     std::condition_variable_any cv_;
75     std::deque<T> events_;
76 };
77 
78 template <class T>
store(const T & event)79 void GnssCallbackEventQueue<T>::store(const T& event) {
80     std::unique_lock<std::recursive_mutex> lock(mtx_);
81     events_.push_back(event);
82     ++called_count_;
83     lock.unlock();
84     cv_.notify_all();
85 }
86 
87 template <class T>
retrieve(T & event,int timeout_seconds)88 bool GnssCallbackEventQueue<T>::retrieve(T& event, int timeout_seconds) {
89     std::unique_lock<std::recursive_mutex> lock(mtx_);
90     cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
91     if (events_.empty()) {
92         return false;
93     }
94     event = events_.front();
95     events_.pop_front();
96     return true;
97 }
98 
99 template <class T>
retrieve(std::list<T> & event_list,int count,int timeout_seconds)100 int GnssCallbackEventQueue<T>::retrieve(std::list<T>& event_list, int count, int timeout_seconds) {
101     for (int i = 0; i < count; ++i) {
102         T event;
103         if (!retrieve(event, timeout_seconds)) {
104             return i;
105         }
106         event_list.push_back(event);
107     }
108 
109     return count;
110 }
111 
112 template <class T>
size()113 int GnssCallbackEventQueue<T>::size() const {
114     std::unique_lock<std::recursive_mutex> lock(mtx_);
115     return events_.size();
116 }
117 
118 template <class T>
calledCount()119 int GnssCallbackEventQueue<T>::calledCount() const {
120     std::unique_lock<std::recursive_mutex> lock(mtx_);
121     return called_count_;
122 }
123 
124 template <class T>
reset()125 void GnssCallbackEventQueue<T>::reset() {
126     std::unique_lock<std::recursive_mutex> lock(mtx_);
127     if (!events_.empty()) {
128         ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
129               name_.c_str());
130     }
131     events_.clear();
132     called_count_ = 0;
133 }
134 
135 }  // namespace common
136 }  // namespace gnss
137 }  // namespace hardware
138 }  // namespace android
139 
140 #endif  // android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
141