The Pedigree Project  0.1
RingBuffer.h
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #ifndef RINGBUFFER_H
21 #define RINGBUFFER_H
22 
23 #include "pedigree/kernel/LockGuard.h"
24 #include "pedigree/kernel/compiler.h"
25 #include "pedigree/kernel/process/ConditionVariable.h"
26 #include "pedigree/kernel/process/Mutex.h"
27 #include "pedigree/kernel/processor/types.h"
28 #include "pedigree/kernel/time/Time.h"
29 #include "pedigree/kernel/utilities/List.h"
30 #include "pedigree/kernel/utilities/new"
31 
32 #ifdef THREADS
33 #include "pedigree/kernel/process/Thread.h"
34 #endif
35 
36 class Event;
37 
39 
40 namespace RingBufferWait
41 {
42 enum WaitType
43 {
44  Reading,
45  Writing
46 };
47 }
48 
60 template <class T>
62 {
63  public:
64  RingBuffer(); // Not implemented, use RingBuffer(size_t)
65 
67  RingBuffer(size_t ringSize)
68  : m_RingSize(ringSize), m_WriteCondition(), m_ReadCondition(), m_Ring(),
69  m_Lock(false)
70  {
71  }
72 
75  {
76  }
77 
79  void write(const T &obj, Time::Timestamp &timeout)
80  {
81  m_Lock.acquire();
82  while (true)
83  {
84  // Wait for room in the buffer if we're full.
85  if (m_Ring.count() >= m_RingSize)
86  {
88  m_WriteCondition.wait(m_Lock, timeout);
89  if (result.hasError())
90  {
92  return;
93  }
94 
95  continue;
96  }
97 
98  m_Ring.pushBack(obj);
99  break;
100  }
101 
102  m_Lock.release();
103 
104  notifyMonitors();
105 
106  // Signal readers waiting for objects to read.
107  m_ReadCondition.signal();
108  }
109 
110  void write(const T &obj)
111  {
112  Time::Timestamp timeout = Time::Infinity;
113  write(obj, timeout);
114  }
115 
117  size_t write(const T *obj, size_t n, Time::Timestamp &timeout)
118  {
119  if (n > m_RingSize)
120  n = m_RingSize;
121 
122  size_t i;
123  for (i = 0; i < n && timeout > 0; ++i)
124  {
125  write(obj[i], timeout);
126  }
127 
128  return i; // return actual count written
129  }
130 
131  size_t write(const T *obj, size_t n)
132  {
133  Time::Timestamp timeout = Time::Infinity;
134  return write(obj, n, timeout);
135  }
136 
138  T read(Time::Timestamp &timeout)
139  {
140  T ret = T();
141 
142  Time::Timestamp origTimeout = timeout;
143 
144  m_Lock.acquire();
145  while (true)
146  {
147  // Wait for room in the buffer if we're full.
148  if (m_Ring.count() == 0)
149  {
151  m_ReadCondition.wait(m_Lock, timeout);
152  if (result.hasError())
153  {
155  return ret;
156  }
157 
158  continue;
159  }
160 
161  ret = m_Ring.popFront();
162  break;
163  }
164 
165  m_Lock.release();
166 
167  notifyMonitors();
168 
169  // Signal writers that may be waiting for buffer space.
170  m_WriteCondition.signal();
171 
172  return ret;
173  }
174 
175  T read()
176  {
177  Time::Timestamp timeout = 0;
178  return read(timeout);
179  }
180 
182  size_t read(T *out, size_t n, Time::Timestamp &timeout)
183  {
184  if (n > m_RingSize)
185  n = m_RingSize;
186 
187  size_t i;
188  for (i = 0; i < n && timeout > 0; ++i)
189  {
190  out[i] = read(timeout);
191  }
192 
193  return i;
194  }
195 
196  size_t read(T *out, size_t n)
197  {
198  Time::Timestamp timeout = Time::Infinity;
199  return read(out, n, timeout);
200  }
201 
203  bool dataReady()
204  {
205  LockGuard<Mutex> guard(m_Lock);
206  return m_Ring.count() > 0;
207  }
208 
210  bool canWrite()
211  {
212  LockGuard<Mutex> guard(m_Lock);
213  return m_Ring.count() < m_RingSize;
214  }
215 
217  bool waitFor(RingBufferWait::WaitType wait, Time::Timestamp &timeout)
218  {
219  m_Lock.acquire();
220  if (wait == RingBufferWait::Writing)
221  {
222  while (true)
223  {
224  if (m_Ring.count() < m_RingSize)
225  {
226  m_Lock.release();
227  return true;
228  }
229 
231  m_WriteCondition.wait(m_Lock, timeout);
232  if (result.hasError())
233  {
234  return false;
235  }
236  }
237  }
238  else
239  {
240  while (true)
241  {
242  if (m_Ring.count())
243  {
244  m_Lock.release();
245  return true;
246  }
247 
249  m_ReadCondition.wait(m_Lock, timeout);
250  if (result.hasError())
251  {
252  return false;
253  }
254  }
255  }
256 
257  m_Lock.release();
258  return false;
259  }
260 
261  bool waitFor(RingBufferWait::WaitType wait)
262  {
263  Time::Timestamp timeout = Time::Infinity;
264  return waitFor(wait, timeout);
265  }
266 
280  void monitor(Thread *pThread, Event *pEvent)
281  {
282  m_Lock.acquire();
283  m_MonitorTargets.pushBack(new MonitorTarget(pThread, pEvent));
284  m_Lock.release();
285  }
286 
288  void cullMonitorTargets(Thread *pThread)
289  {
290  m_Lock.acquire();
291  for (typename List<MonitorTarget *>::Iterator it =
292  m_MonitorTargets.begin();
293  it != m_MonitorTargets.end(); it++)
294  {
295  MonitorTarget *pMT = *it;
296 
297  if (pMT->pThread == pThread)
298  {
299  delete pMT;
300  m_MonitorTargets.erase(it);
301  it = m_MonitorTargets.begin();
302  if (it == m_MonitorTargets.end())
303  return;
304  }
305  }
306  m_Lock.release();
307  }
308 
309  private:
312  {
313 #ifdef THREADS
314  m_Lock.acquire();
315  for (typename List<MonitorTarget *>::Iterator it =
316  m_MonitorTargets.begin();
317  it != m_MonitorTargets.end(); it++)
318  {
319  MonitorTarget *pMT = *it;
320 
321  pMT->pThread->sendEvent(pMT->pEvent);
322  delete pMT;
323  }
324  m_MonitorTargets.clear();
325  m_Lock.release();
326 #endif
327  }
328 
329  size_t m_RingSize;
330 
331  ConditionVariable m_WriteCondition;
332  ConditionVariable m_ReadCondition;
333 
334  List<T> m_Ring;
335 
336  Mutex m_Lock;
337 
339  {
340  MonitorTarget(Thread *pT, Event *pE) : pThread(pT), pEvent(pE)
341  {
342  }
343 
344  Thread *pThread;
345  Event *pEvent;
346  };
347 
348  List<MonitorTarget *> m_MonitorTargets;
349 };
350 
351 extern template class RingBuffer<char>; // IWYU pragma: keep
352 extern template class RingBuffer<void *>; // IWYU pragma: keep
353 
354 #endif
T read(Time::Timestamp &timeout)
read - read a byte from the ring buffer.
Definition: RingBuffer.h:138
RingBuffer(size_t ringSize)
Constructor - pass in the desired size of the ring buffer.
Definition: RingBuffer.h:67
size_t write(const T *obj, size_t n, Time::Timestamp &timeout)
write - write the given number of objects to the ring buffer.
Definition: RingBuffer.h:117
bool canWrite()
canWrite - is it possible to write to the ring buffer without blocking?
Definition: RingBuffer.h:210
bool waitFor(RingBufferWait::WaitType wait, Time::Timestamp &timeout)
waitFor - block until the given condition is true (readable/writeable)
Definition: RingBuffer.h:217
Definition: Mutex.h:58
Definition: Result.h:36
size_t read(T *out, size_t n, Time::Timestamp &timeout)
read - read up to the given number of objects from the ring buffer
Definition: RingBuffer.h:182
void write(const T &obj, Time::Timestamp &timeout)
write - write a byte to the ring buffer.
Definition: RingBuffer.h:79
bool dataReady()
dataReady - is data ready for reading from the ring buffer?
Definition: RingBuffer.h:203
void monitor(Thread *pThread, Event *pEvent)
monitor - add a new Event to be fired when something happens
Definition: RingBuffer.h:280
::Iterator< T, node_t > Iterator
Definition: List.h:71
void cullMonitorTargets(Thread *pThread)
Cull all monitor targets pointing to pThread.
Definition: RingBuffer.h:288
Definition: Thread.h:54
Definition: Event.h:48
~RingBuffer()
Destructor - destroys the ring; ensure nothing is calling waitFor.
Definition: RingBuffer.h:74
Utility class to provide a ring buffer.
Definition: RingBuffer.h:61
void notifyMonitors()
Trigger event for threads waiting on us.
Definition: RingBuffer.h:311