1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker // This file contains a number of synchronization primitives for concurrency.
16*03ce13f7SAndroid Build Coastguard Worker //
17*03ce13f7SAndroid Build Coastguard Worker // You may be tempted to change this code to unlock the mutex before calling
18*03ce13f7SAndroid Build Coastguard Worker // std::condition_variable::notify_[one,all]. Please read
19*03ce13f7SAndroid Build Coastguard Worker // https://issuetracker.google.com/issues/133135427 before making this sort of
20*03ce13f7SAndroid Build Coastguard Worker // change.
21*03ce13f7SAndroid Build Coastguard Worker
22*03ce13f7SAndroid Build Coastguard Worker #ifndef sw_Synchronization_hpp
23*03ce13f7SAndroid Build Coastguard Worker #define sw_Synchronization_hpp
24*03ce13f7SAndroid Build Coastguard Worker
25*03ce13f7SAndroid Build Coastguard Worker #include "Debug.hpp"
26*03ce13f7SAndroid Build Coastguard Worker
27*03ce13f7SAndroid Build Coastguard Worker #include <assert.h>
28*03ce13f7SAndroid Build Coastguard Worker #include <chrono>
29*03ce13f7SAndroid Build Coastguard Worker #include <condition_variable>
30*03ce13f7SAndroid Build Coastguard Worker #include <queue>
31*03ce13f7SAndroid Build Coastguard Worker
32*03ce13f7SAndroid Build Coastguard Worker #include "marl/event.h"
33*03ce13f7SAndroid Build Coastguard Worker #include "marl/mutex.h"
34*03ce13f7SAndroid Build Coastguard Worker #include "marl/waitgroup.h"
35*03ce13f7SAndroid Build Coastguard Worker
36*03ce13f7SAndroid Build Coastguard Worker namespace sw {
37*03ce13f7SAndroid Build Coastguard Worker
38*03ce13f7SAndroid Build Coastguard Worker // CountedEvent is an event that is signalled when the internal counter is
39*03ce13f7SAndroid Build Coastguard Worker // decremented and reaches zero.
40*03ce13f7SAndroid Build Coastguard Worker // The counter is incremented with calls to add() and decremented with calls to
41*03ce13f7SAndroid Build Coastguard Worker // done().
42*03ce13f7SAndroid Build Coastguard Worker class CountedEvent
43*03ce13f7SAndroid Build Coastguard Worker {
44*03ce13f7SAndroid Build Coastguard Worker public:
45*03ce13f7SAndroid Build Coastguard Worker // Constructs the CountedEvent with the initial signalled state set to the
46*03ce13f7SAndroid Build Coastguard Worker // provided value.
CountedEvent(bool signalled=false)47*03ce13f7SAndroid Build Coastguard Worker CountedEvent(bool signalled = false)
48*03ce13f7SAndroid Build Coastguard Worker : ev(marl::Event::Mode::Manual, signalled)
49*03ce13f7SAndroid Build Coastguard Worker {}
50*03ce13f7SAndroid Build Coastguard Worker
51*03ce13f7SAndroid Build Coastguard Worker // add() increments the internal counter.
52*03ce13f7SAndroid Build Coastguard Worker // add() must not be called when the event is already signalled.
add() const53*03ce13f7SAndroid Build Coastguard Worker void add() const
54*03ce13f7SAndroid Build Coastguard Worker {
55*03ce13f7SAndroid Build Coastguard Worker ASSERT(!ev.isSignalled());
56*03ce13f7SAndroid Build Coastguard Worker wg.add();
57*03ce13f7SAndroid Build Coastguard Worker }
58*03ce13f7SAndroid Build Coastguard Worker
59*03ce13f7SAndroid Build Coastguard Worker // done() decrements the internal counter, signalling the event if the new
60*03ce13f7SAndroid Build Coastguard Worker // counter value is zero.
61*03ce13f7SAndroid Build Coastguard Worker // done() must not be called when the event is already signalled.
done() const62*03ce13f7SAndroid Build Coastguard Worker void done() const
63*03ce13f7SAndroid Build Coastguard Worker {
64*03ce13f7SAndroid Build Coastguard Worker ASSERT(!ev.isSignalled());
65*03ce13f7SAndroid Build Coastguard Worker if(wg.done())
66*03ce13f7SAndroid Build Coastguard Worker {
67*03ce13f7SAndroid Build Coastguard Worker ev.signal();
68*03ce13f7SAndroid Build Coastguard Worker }
69*03ce13f7SAndroid Build Coastguard Worker }
70*03ce13f7SAndroid Build Coastguard Worker
71*03ce13f7SAndroid Build Coastguard Worker // reset() clears the signal state.
72*03ce13f7SAndroid Build Coastguard Worker // done() must not be called when the internal counter is non-zero.
reset() const73*03ce13f7SAndroid Build Coastguard Worker void reset() const
74*03ce13f7SAndroid Build Coastguard Worker {
75*03ce13f7SAndroid Build Coastguard Worker ev.clear();
76*03ce13f7SAndroid Build Coastguard Worker }
77*03ce13f7SAndroid Build Coastguard Worker
78*03ce13f7SAndroid Build Coastguard Worker // signalled() returns the current signal state.
signalled() const79*03ce13f7SAndroid Build Coastguard Worker bool signalled() const
80*03ce13f7SAndroid Build Coastguard Worker {
81*03ce13f7SAndroid Build Coastguard Worker return ev.isSignalled();
82*03ce13f7SAndroid Build Coastguard Worker }
83*03ce13f7SAndroid Build Coastguard Worker
84*03ce13f7SAndroid Build Coastguard Worker // wait() waits until the event is signalled.
wait() const85*03ce13f7SAndroid Build Coastguard Worker void wait() const
86*03ce13f7SAndroid Build Coastguard Worker {
87*03ce13f7SAndroid Build Coastguard Worker ev.wait();
88*03ce13f7SAndroid Build Coastguard Worker }
89*03ce13f7SAndroid Build Coastguard Worker
90*03ce13f7SAndroid Build Coastguard Worker // wait() waits until the event is signalled or the timeout is reached.
91*03ce13f7SAndroid Build Coastguard Worker // If the timeout was reached, then wait() return false.
92*03ce13f7SAndroid Build Coastguard Worker template<class CLOCK, class DURATION>
wait(const std::chrono::time_point<CLOCK,DURATION> & timeout) const93*03ce13f7SAndroid Build Coastguard Worker bool wait(const std::chrono::time_point<CLOCK, DURATION> &timeout) const
94*03ce13f7SAndroid Build Coastguard Worker {
95*03ce13f7SAndroid Build Coastguard Worker return ev.wait_until(timeout);
96*03ce13f7SAndroid Build Coastguard Worker }
97*03ce13f7SAndroid Build Coastguard Worker
98*03ce13f7SAndroid Build Coastguard Worker // event() returns the internal marl event.
event()99*03ce13f7SAndroid Build Coastguard Worker const marl::Event &event() { return ev; }
100*03ce13f7SAndroid Build Coastguard Worker
101*03ce13f7SAndroid Build Coastguard Worker private:
102*03ce13f7SAndroid Build Coastguard Worker const marl::WaitGroup wg;
103*03ce13f7SAndroid Build Coastguard Worker const marl::Event ev;
104*03ce13f7SAndroid Build Coastguard Worker };
105*03ce13f7SAndroid Build Coastguard Worker
106*03ce13f7SAndroid Build Coastguard Worker // Chan is a thread-safe FIFO queue of type T.
107*03ce13f7SAndroid Build Coastguard Worker // Chan takes its name after Golang's chan.
108*03ce13f7SAndroid Build Coastguard Worker template<typename T>
109*03ce13f7SAndroid Build Coastguard Worker class Chan
110*03ce13f7SAndroid Build Coastguard Worker {
111*03ce13f7SAndroid Build Coastguard Worker public:
112*03ce13f7SAndroid Build Coastguard Worker Chan();
113*03ce13f7SAndroid Build Coastguard Worker
114*03ce13f7SAndroid Build Coastguard Worker // take returns the next item in the chan, blocking until an item is
115*03ce13f7SAndroid Build Coastguard Worker // available.
116*03ce13f7SAndroid Build Coastguard Worker T take();
117*03ce13f7SAndroid Build Coastguard Worker
118*03ce13f7SAndroid Build Coastguard Worker // tryTake returns a <T, bool> pair.
119*03ce13f7SAndroid Build Coastguard Worker // If the chan is not empty, then the next item and true are returned.
120*03ce13f7SAndroid Build Coastguard Worker // If the chan is empty, then a default-initialized T and false are returned.
121*03ce13f7SAndroid Build Coastguard Worker std::pair<T, bool> tryTake();
122*03ce13f7SAndroid Build Coastguard Worker
123*03ce13f7SAndroid Build Coastguard Worker // put places an item into the chan, blocking if the chan is bounded and
124*03ce13f7SAndroid Build Coastguard Worker // full.
125*03ce13f7SAndroid Build Coastguard Worker void put(const T &v);
126*03ce13f7SAndroid Build Coastguard Worker
127*03ce13f7SAndroid Build Coastguard Worker // Returns the number of items in the chan.
128*03ce13f7SAndroid Build Coastguard Worker // Note: that this may change as soon as the function returns, so should
129*03ce13f7SAndroid Build Coastguard Worker // only be used for debugging.
130*03ce13f7SAndroid Build Coastguard Worker size_t count();
131*03ce13f7SAndroid Build Coastguard Worker
132*03ce13f7SAndroid Build Coastguard Worker private:
133*03ce13f7SAndroid Build Coastguard Worker marl::mutex mutex;
134*03ce13f7SAndroid Build Coastguard Worker std::queue<T> queue GUARDED_BY(mutex);
135*03ce13f7SAndroid Build Coastguard Worker std::condition_variable added;
136*03ce13f7SAndroid Build Coastguard Worker };
137*03ce13f7SAndroid Build Coastguard Worker
138*03ce13f7SAndroid Build Coastguard Worker template<typename T>
Chan()139*03ce13f7SAndroid Build Coastguard Worker Chan<T>::Chan()
140*03ce13f7SAndroid Build Coastguard Worker {}
141*03ce13f7SAndroid Build Coastguard Worker
142*03ce13f7SAndroid Build Coastguard Worker template<typename T>
take()143*03ce13f7SAndroid Build Coastguard Worker T Chan<T>::take()
144*03ce13f7SAndroid Build Coastguard Worker {
145*03ce13f7SAndroid Build Coastguard Worker marl::lock lock(mutex);
146*03ce13f7SAndroid Build Coastguard Worker // Wait for item to be added.
147*03ce13f7SAndroid Build Coastguard Worker lock.wait(added, [this]() REQUIRES(mutex) { return queue.size() > 0; });
148*03ce13f7SAndroid Build Coastguard Worker T out = queue.front();
149*03ce13f7SAndroid Build Coastguard Worker queue.pop();
150*03ce13f7SAndroid Build Coastguard Worker return out;
151*03ce13f7SAndroid Build Coastguard Worker }
152*03ce13f7SAndroid Build Coastguard Worker
153*03ce13f7SAndroid Build Coastguard Worker template<typename T>
tryTake()154*03ce13f7SAndroid Build Coastguard Worker std::pair<T, bool> Chan<T>::tryTake()
155*03ce13f7SAndroid Build Coastguard Worker {
156*03ce13f7SAndroid Build Coastguard Worker marl::lock lock(mutex);
157*03ce13f7SAndroid Build Coastguard Worker if(queue.size() == 0)
158*03ce13f7SAndroid Build Coastguard Worker {
159*03ce13f7SAndroid Build Coastguard Worker return std::make_pair(T{}, false);
160*03ce13f7SAndroid Build Coastguard Worker }
161*03ce13f7SAndroid Build Coastguard Worker T out = queue.front();
162*03ce13f7SAndroid Build Coastguard Worker queue.pop();
163*03ce13f7SAndroid Build Coastguard Worker return std::make_pair(out, true);
164*03ce13f7SAndroid Build Coastguard Worker }
165*03ce13f7SAndroid Build Coastguard Worker
166*03ce13f7SAndroid Build Coastguard Worker template<typename T>
put(const T & item)167*03ce13f7SAndroid Build Coastguard Worker void Chan<T>::put(const T &item)
168*03ce13f7SAndroid Build Coastguard Worker {
169*03ce13f7SAndroid Build Coastguard Worker marl::lock lock(mutex);
170*03ce13f7SAndroid Build Coastguard Worker queue.push(item);
171*03ce13f7SAndroid Build Coastguard Worker added.notify_one();
172*03ce13f7SAndroid Build Coastguard Worker }
173*03ce13f7SAndroid Build Coastguard Worker
174*03ce13f7SAndroid Build Coastguard Worker template<typename T>
count()175*03ce13f7SAndroid Build Coastguard Worker size_t Chan<T>::count()
176*03ce13f7SAndroid Build Coastguard Worker {
177*03ce13f7SAndroid Build Coastguard Worker marl::lock lock(mutex);
178*03ce13f7SAndroid Build Coastguard Worker return queue.size();
179*03ce13f7SAndroid Build Coastguard Worker }
180*03ce13f7SAndroid Build Coastguard Worker
181*03ce13f7SAndroid Build Coastguard Worker } // namespace sw
182*03ce13f7SAndroid Build Coastguard Worker
183*03ce13f7SAndroid Build Coastguard Worker #endif // sw_Synchronization_hpp
184