Ardour  8.12
ringbufferNPT.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2000 Paul Davis & Benno Senoner
3  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
4  * Copyright (C) 2015-2016 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #ifndef ringbuffer_npt_h
22 #define ringbuffer_npt_h
23 
24 //#include <sys/mman.h>
25 
26 #include <atomic>
27 #include <cstring>
28 #include <glib.h>
29 
30 #include "pbd/libpbd_visibility.h"
31 
32 namespace PBD {
33 
34 /* ringbuffer class where the element size is not required to be a power of two */
35 
36 template<class T>
37 class /*LIBPBD_API*/ RingBufferNPT
38 {
39  public:
40  RingBufferNPT (size_t sz) {
41  size = sz;
42  buf = new T[size];
43  reset ();
44  }
45 
46  virtual ~RingBufferNPT () {
47  delete [] buf;
48  }
49 
50  void reset () {
51  /* !!! NOT THREAD SAFE !!! */
52  write_ptr.store (0);
53  read_ptr.store (0);
54  }
55 
56  void set (size_t r, size_t w) {
57  /* !!! NOT THREAD SAFE !!! */
58  write_ptr.store (w);
59  read_ptr.store (r);
60  }
61 
62  size_t read (T *dest, size_t cnt);
63  size_t write (const T *src, size_t cnt);
64  size_t write_one (const T src);
65 
66  struct rw_vector {
67  T *buf[2];
68  size_t len[2];
69  };
70 
71  void get_read_vector (rw_vector *);
72  void get_write_vector (rw_vector *);
73 
74  void decrement_read_ptr (size_t cnt) {
75  read_ptr.store ((read_ptr.load () - cnt) % size);
76  }
77 
78  void increment_read_ptr (size_t cnt) {
79  read_ptr.store ((read_ptr.load () + cnt) % size);
80  }
81 
82  void increment_write_ptr (size_t cnt) {
83  write_ptr.store ((write_ptr.load () + cnt) % size);
84  }
85 
86  size_t write_space () {
87  size_t w, r;
88 
89  w = write_ptr.load ();
90  r = read_ptr.load ();
91 
92  if (w > r) {
93  return ((r - w + size) % size) - 1;
94  } else if (w < r) {
95  return (r - w) - 1;
96  } else {
97  return size - 1;
98  }
99  }
100 
101  size_t read_space () {
102  size_t w, r;
103 
104  w = write_ptr.load ();
105  r = read_ptr.load ();
106 
107  if (w > r) {
108  return w - r;
109  } else {
110  return (w - r + size) % size;
111  }
112  }
113 
114  T *buffer () { return buf; }
115  size_t get_write_ptr () const { return write_ptr.load (); }
116  size_t get_read_ptr () const { return read_ptr.load (); }
117  size_t bufsize () const { return size; }
118 
119  protected:
120  T *buf;
121  size_t size;
122  mutable std::atomic<int> write_ptr;
123  mutable std::atomic<int> read_ptr;
124 
125 private:
127 };
128 
129 template<class T> /*LIBPBD_API*/ size_t
130 RingBufferNPT<T>::read (T *dest, size_t cnt)
131 {
132  size_t free_cnt;
133  size_t cnt2;
134  size_t to_read;
135  size_t n1, n2;
136  size_t priv_read_ptr;
137 
138  priv_read_ptr = read_ptr.load ();
139 
140  if ((free_cnt = read_space ()) == 0) {
141  return 0;
142  }
143 
144  to_read = cnt > free_cnt ? free_cnt : cnt;
145 
146  cnt2 = priv_read_ptr + to_read;
147 
148  if (cnt2 > size) {
149  n1 = size - priv_read_ptr;
150  n2 = cnt2 % size;
151  } else {
152  n1 = to_read;
153  n2 = 0;
154  }
155 
156  memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));
157  priv_read_ptr = (priv_read_ptr + n1) % size;
158 
159  if (n2) {
160  memcpy (dest+n1, buf, n2 * sizeof (T));
161  priv_read_ptr = n2;
162  }
163 
164  read_ptr.store (priv_read_ptr);
165  return to_read;
166 }
167 
168 template<class T> /*LIBPBD_API*/ size_t
169 RingBufferNPT<T>::write (const T *src, size_t cnt)
170 {
171  size_t free_cnt;
172  size_t cnt2;
173  size_t to_write;
174  size_t n1, n2;
175  size_t priv_write_ptr;
176 
177  priv_write_ptr = write_ptr.load ();
178 
179  if ((free_cnt = write_space ()) == 0) {
180  return 0;
181  }
182 
183  to_write = cnt > free_cnt ? free_cnt : cnt;
184 
185  cnt2 = priv_write_ptr + to_write;
186 
187  if (cnt2 > size) {
188  n1 = size - priv_write_ptr;
189  n2 = cnt2 % size;
190  } else {
191  n1 = to_write;
192  n2 = 0;
193  }
194 
195  memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));
196  priv_write_ptr = (priv_write_ptr + n1) % size;
197 
198  if (n2) {
199  memcpy (buf, src+n1, n2 * sizeof (T));
200  priv_write_ptr = n2;
201  }
202 
203  write_ptr.store (priv_write_ptr);
204  return to_write;
205 }
206 
207 template<class T> /*LIBPBD_API*/ size_t
209 {
210  return write (&src, 1);
211 }
212 
213 template<class T> /*LIBPBD_API*/ void
215 {
216  size_t free_cnt;
217  size_t cnt2;
218  size_t w, r;
219 
220  w = write_ptr.load ();
221  r = read_ptr.load ();
222 
223  if (w > r) {
224  free_cnt = w - r;
225  } else {
226  free_cnt = (w - r + size) % size;
227  }
228 
229  cnt2 = r + free_cnt;
230 
231  if (cnt2 > size) {
232  /* Two part vector: the rest of the buffer after the
233  current write ptr, plus some from the start of
234  the buffer.
235  */
236 
237  vec->buf[0] = &buf[r];
238  vec->len[0] = size - r;
239  vec->buf[1] = buf;
240  vec->len[1] = cnt2 % size;
241 
242  } else {
243 
244  /* Single part vector: just the rest of the buffer */
245 
246  vec->buf[0] = &buf[r];
247  vec->len[0] = free_cnt;
248  vec->buf[1] = 0;
249  vec->len[1] = 0;
250  }
251 }
252 
253 template<class T> /*LIBPBD_API*/ void
255 {
256  size_t free_cnt;
257  size_t cnt2;
258  size_t w, r;
259 
260  w = write_ptr.load ();
261  r = read_ptr.load ();
262 
263  if (w > r) {
264  free_cnt = ((r - w + size) % size) - 1;
265  } else if (w < r) {
266  free_cnt = (r - w) - 1;
267  } else {
268  free_cnt = size - 1;
269  }
270 
271  cnt2 = w + free_cnt;
272 
273  if (cnt2 > size) {
274 
275  /* Two part vector: the rest of the buffer after the
276  current write ptr, plus some from the start of
277  the buffer.
278  */
279 
280  vec->buf[0] = &buf[w];
281  vec->len[0] = size - w;
282  vec->buf[1] = buf;
283  vec->len[1] = cnt2 % size;
284  } else {
285  vec->buf[0] = &buf[w];
286  vec->len[0] = free_cnt;
287  vec->len[1] = 0;
288  }
289 }
290 
291 } /* namespace */
292 
293 #endif /* __ringbuffer_npt_h__ */
std::atomic< int > write_ptr
std::atomic< int > read_ptr
size_t write(const T *src, size_t cnt)
void increment_read_ptr(size_t cnt)
Definition: ringbufferNPT.h:78
void get_write_vector(rw_vector *)
RingBufferNPT(size_t sz)
Definition: ringbufferNPT.h:40
size_t bufsize() const
size_t get_read_ptr() const
void increment_write_ptr(size_t cnt)
Definition: ringbufferNPT.h:82
virtual ~RingBufferNPT()
Definition: ringbufferNPT.h:46
size_t write_one(const T src)
size_t read(T *dest, size_t cnt)
void decrement_read_ptr(size_t cnt)
Definition: ringbufferNPT.h:74
RingBufferNPT(RingBufferNPT const &)
void get_read_vector(rw_vector *)
void set(size_t r, size_t w)
Definition: ringbufferNPT.h:56
size_t get_write_ptr() const
Definition: axis_view.h:42