xref: /aosp_15_r20/external/deqp/framework/delibs/decpp/deThreadSafeRingBuffer.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 #ifndef _DETHREADSAFERINGBUFFER_HPP
2 #define _DETHREADSAFERINGBUFFER_HPP
3 /*-------------------------------------------------------------------------
4  * drawElements C++ Base Library
5  * -----------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Thread-safe ring buffer template.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "deDefs.hpp"
27 #include "deMutex.hpp"
28 #include "deSemaphore.hpp"
29 
30 #include <vector>
31 
32 namespace de
33 {
34 
35 void ThreadSafeRingBuffer_selfTest(void);
36 
37 /** Thread-safe ring buffer template. */
38 template <typename T>
39 class ThreadSafeRingBuffer
40 {
41 public:
42     ThreadSafeRingBuffer(size_t size);
~ThreadSafeRingBuffer(void)43     ~ThreadSafeRingBuffer(void)
44     {
45     }
46 
47     void pushFront(const T &elem);
48     bool tryPushFront(const T &elem);
49     T popBack(void);
50     bool tryPopBack(T &dst);
51 
52 protected:
53     void pushFrontInternal(const T &elem);
54     T popBackInternal(void);
55 
56     const size_t m_size;
57     std::vector<T> m_elements;
58 
59     size_t m_front;
60     size_t m_back;
61 
62     Mutex m_writeMutex;
63     Mutex m_readMutex;
64 
65     Semaphore m_fill;
66     Semaphore m_empty;
67 };
68 
69 // ThreadSafeRingBuffer implementation.
70 
71 template <typename T>
ThreadSafeRingBuffer(size_t size)72 ThreadSafeRingBuffer<T>::ThreadSafeRingBuffer(size_t size)
73     : m_size(size + 1)
74     , m_elements(m_size)
75     , m_front(0)
76     , m_back(0)
77     , m_fill(0)
78     , m_empty((int)size)
79 {
80     // Semaphores currently only support INT_MAX
81     DE_ASSERT(size > 0 && size < 0x7fffffff);
82 }
83 
84 template <typename T>
pushFrontInternal(const T & elem)85 inline void ThreadSafeRingBuffer<T>::pushFrontInternal(const T &elem)
86 {
87     m_elements[m_front] = elem;
88     m_front             = (m_front + 1) % m_size;
89 }
90 
91 template <typename T>
popBackInternal()92 inline T ThreadSafeRingBuffer<T>::popBackInternal()
93 {
94     const size_t ndx = m_back;
95     m_back           = (m_back + 1) % m_size;
96     return m_elements[ndx];
97 }
98 
99 template <typename T>
pushFront(const T & elem)100 void ThreadSafeRingBuffer<T>::pushFront(const T &elem)
101 {
102     m_writeMutex.lock();
103     m_empty.decrement();
104     pushFrontInternal(elem);
105     m_fill.increment();
106     m_writeMutex.unlock();
107 }
108 
109 template <typename T>
tryPushFront(const T & elem)110 bool ThreadSafeRingBuffer<T>::tryPushFront(const T &elem)
111 {
112     if (!m_writeMutex.tryLock())
113         return false;
114 
115     const bool success = m_empty.tryDecrement();
116 
117     if (success)
118     {
119         pushFrontInternal(elem);
120         m_fill.increment();
121     }
122 
123     m_writeMutex.unlock();
124     return success;
125 }
126 
127 template <typename T>
popBack()128 T ThreadSafeRingBuffer<T>::popBack()
129 {
130     m_readMutex.lock();
131     m_fill.decrement();
132     T elem = popBackInternal();
133     m_empty.increment();
134     m_readMutex.unlock();
135     return elem;
136 }
137 
138 template <typename T>
tryPopBack(T & dst)139 bool ThreadSafeRingBuffer<T>::tryPopBack(T &dst)
140 {
141     if (!m_readMutex.tryLock())
142         return false;
143 
144     bool success = m_fill.tryDecrement();
145 
146     if (success)
147     {
148         dst = popBackInternal();
149         m_empty.increment();
150     }
151 
152     m_readMutex.unlock();
153 
154     return success;
155 }
156 
157 } // namespace de
158 
159 #endif // _DETHREADSAFERINGBUFFER_HPP
160