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
30namespace de
31{
32
33void ThreadSafeRingBuffer_selfTest (void);
34
35/** Thread-safe ring buffer template. */
36template <typename T>
37class ThreadSafeRingBuffer
38{
39public:
40				ThreadSafeRingBuffer	(int size);
41				~ThreadSafeRingBuffer	(void) {}
42
43	void		pushFront				(const T& elem);
44	bool		tryPushFront			(const T& elem);
45	T			popBack					(void);
46	bool		tryPopBack				(T& dst);
47
48protected:
49	void		pushFrontInternal		(const T& elem);
50	T			popBackInternal			(void);
51
52	int			m_front;
53	int			m_back;
54	T*			m_buffer;
55	int			m_size;
56
57	Mutex		m_writeMutex;
58	Mutex		m_readMutex;
59
60	Semaphore	m_fill;
61	Semaphore	m_empty;
62};
63
64// ThreadSafeRingBuffer implementation.
65
66template <typename T>
67ThreadSafeRingBuffer<T>::ThreadSafeRingBuffer (int size)
68	: m_front		(0)
69	, m_back		(0)
70	, m_size		(size+1)
71	, m_fill		(0)
72	, m_empty		(size)
73{
74	DE_ASSERT(size > 0);
75	m_buffer = new T[m_size];
76}
77
78template <typename T>
79inline void ThreadSafeRingBuffer<T>::pushFrontInternal (const T& elem)
80{
81	m_buffer[m_front] = elem;
82	m_front = (m_front + 1) % m_size;
83}
84
85template <typename T>
86inline T ThreadSafeRingBuffer<T>::popBackInternal ()
87{
88	int ndx = m_back;
89	m_back = (m_back + 1) % m_size;
90	return m_buffer[ndx];
91}
92
93template <typename T>
94void ThreadSafeRingBuffer<T>::pushFront (const T& elem)
95{
96	m_writeMutex.lock();
97	m_empty.decrement();
98	pushFrontInternal(elem);
99	m_fill.increment();
100	m_writeMutex.unlock();
101}
102
103template <typename T>
104bool ThreadSafeRingBuffer<T>::tryPushFront (const T& elem)
105{
106	if (!m_writeMutex.tryLock())
107		return false;
108	bool success = m_empty.tryDecrement();
109	if (success)
110	{
111		pushFrontInternal(elem);
112		m_fill.increment();
113	}
114	m_writeMutex.unlock();
115	return success;
116}
117
118template <typename T>
119T ThreadSafeRingBuffer<T>::popBack ()
120{
121	m_readMutex.lock();
122	m_fill.decrement();
123	T elem = popBackInternal();
124	m_empty.increment();
125	m_readMutex.unlock();
126	return elem;
127}
128
129template <typename T>
130bool ThreadSafeRingBuffer<T>::tryPopBack (T& dst)
131{
132	if (!m_readMutex.tryLock())
133		return false;
134
135	bool success = m_fill.tryDecrement();
136
137	if (success)
138	{
139		dst = popBackInternal();
140		m_empty.increment();
141	}
142
143	m_readMutex.unlock();
144
145	return success;
146}
147
148} // de
149
150#endif // _DETHREADSAFERINGBUFFER_HPP
151