xref: /aosp_15_r20/external/swiftshader/src/System/Synchronization.hpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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