Ardour  9.0-pre0-582-g084a23a80d
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 #pragma once
22 
23 //#include <sys/mman.h>
24 
25 #include <atomic>
26 #include <cstring>
27 #include <glib.h>
28 
29 #include "pbd/libpbd_visibility.h"
30 
31 namespace PBD {
32 
33 /* ringbuffer class where the element size is not required to be a power of two */
34 
35 template<class T>
36 class /*LIBPBD_API*/ RingBufferNPT
37 {
38  public:
39  RingBufferNPT (size_t sz) {
40  size = sz;
41  buf = new T[size];
42  reset ();
43  }
44 
45  virtual ~RingBufferNPT () {
46  delete [] buf;
47  }
48 
49  void reset () {
50  /* !!! NOT THREAD SAFE !!! */
51  write_ptr.store (0);
52  read_ptr.store (0);
53  }
54 
55  void set (size_t r, size_t w) {
56  /* !!! NOT THREAD SAFE !!! */
57  write_ptr.store (w);
58  read_ptr.store (r);
59  }
60 
61  size_t read (T *dest, size_t cnt);
62  size_t write (const T *src, size_t cnt);
63  size_t write_one (const T src);
64 
65  struct rw_vector {
66  T *buf[2];
67  size_t len[2];
68  };
69 
70  void get_read_vector (rw_vector *);
71  void get_write_vector (rw_vector *);
72 
73  void decrement_read_ptr (size_t cnt) {
74  read_ptr.store ((read_ptr.load () - cnt) % size);
75  }
76 
77  void increment_read_ptr (size_t cnt) {
78  read_ptr.store ((read_ptr.load () + cnt) % size);
79  }
80 
81  void increment_write_ptr (size_t cnt) {
82  write_ptr.store ((write_ptr.load () + cnt) % size);
83  }
84 
85  size_t write_space () {
86  size_t w, r;
87 
88  w = write_ptr.load ();
89  r = read_ptr.load ();
90 
91  if (w > r) {
92  return ((r - w + size) % size) - 1;
93  } else if (w < r) {
94  return (r - w) - 1;
95  } else {
96  return size - 1;
97  }
98  }
99 
100  size_t read_space () {
101  size_t w, r;
102 
103  w = write_ptr.load ();
104  r = read_ptr.load ();
105 
106  if (w > r) {
107  return w - r;
108  } else {
109  return (w - r + size) % size;
110  }
111  }
112 
113  T *buffer () { return buf; }
114  size_t get_write_ptr () const { return write_ptr.load (); }
115  size_t get_read_ptr () const { return read_ptr.load (); }
116  size_t bufsize () const { return size; }
117 
118  protected:
119  T *buf;
120  size_t size;
121  mutable std::atomic<int> write_ptr;
122  mutable std::atomic<int> read_ptr;
123 
124 private:
126 };
127 
128 template<class T> /*LIBPBD_API*/ size_t
129 RingBufferNPT<T>::read (T *dest, size_t cnt)
130 {
131  size_t free_cnt;
132  size_t cnt2;
133  size_t to_read;
134  size_t n1, n2;
135  size_t priv_read_ptr;
136 
137  priv_read_ptr = read_ptr.load ();
138 
139  if ((free_cnt = read_space ()) == 0) {
140  return 0;
141  }
142 
143  to_read = cnt > free_cnt ? free_cnt : cnt;
144 
145  cnt2 = priv_read_ptr + to_read;
146 
147  if (cnt2 > size) {
148  n1 = size - priv_read_ptr;
149  n2 = cnt2 % size;
150  } else {
151  n1 = to_read;
152  n2 = 0;
153  }
154 
155  memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));
156  priv_read_ptr = (priv_read_ptr + n1) % size;
157 
158  if (n2) {
159  memcpy (dest+n1, buf, n2 * sizeof (T));
160  priv_read_ptr = n2;
161  }
162 
163  read_ptr.store (priv_read_ptr);
164  return to_read;
165 }
166 
167 template<class T> /*LIBPBD_API*/ size_t
168 RingBufferNPT<T>::write (const T *src, size_t cnt)
169 {
170  size_t free_cnt;
171  size_t cnt2;
172  size_t to_write;
173  size_t n1, n2;
174  size_t priv_write_ptr;
175 
176  priv_write_ptr = write_ptr.load ();
177 
178  if ((free_cnt = write_space ()) == 0) {
179  return 0;
180  }
181 
182  to_write = cnt > free_cnt ? free_cnt : cnt;
183 
184  cnt2 = priv_write_ptr + to_write;
185 
186  if (cnt2 > size) {
187  n1 = size - priv_write_ptr;
188  n2 = cnt2 % size;
189  } else {
190  n1 = to_write;
191  n2 = 0;
192  }
193 
194  memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));
195  priv_write_ptr = (priv_write_ptr + n1) % size;
196 
197  if (n2) {
198  memcpy (buf, src+n1, n2 * sizeof (T));
199  priv_write_ptr = n2;
200  }
201 
202  write_ptr.store (priv_write_ptr);
203  return to_write;
204 }
205 
206 template<class T> /*LIBPBD_API*/ size_t
208 {
209  return write (&src, 1);
210 }
211 
212 template<class T> /*LIBPBD_API*/ void
214 {
215  size_t free_cnt;
216  size_t cnt2;
217  size_t w, r;
218 
219  w = write_ptr.load ();
220  r = read_ptr.load ();
221 
222  if (w > r) {
223  free_cnt = w - r;
224  } else {
225  free_cnt = (w - r + size) % size;
226  }
227 
228  cnt2 = r + free_cnt;
229 
230  if (cnt2 > size) {
231  /* Two part vector: the rest of the buffer after the
232  current write ptr, plus some from the start of
233  the buffer.
234  */
235 
236  vec->buf[0] = &buf[r];
237  vec->len[0] = size - r;
238  vec->buf[1] = buf;
239  vec->len[1] = cnt2 % size;
240 
241  } else {
242 
243  /* Single part vector: just the rest of the buffer */
244 
245  vec->buf[0] = &buf[r];
246  vec->len[0] = free_cnt;
247  vec->buf[1] = 0;
248  vec->len[1] = 0;
249  }
250 }
251 
252 template<class T> /*LIBPBD_API*/ void
254 {
255  size_t free_cnt;
256  size_t cnt2;
257  size_t w, r;
258 
259  w = write_ptr.load ();
260  r = read_ptr.load ();
261 
262  if (w > r) {
263  free_cnt = ((r - w + size) % size) - 1;
264  } else if (w < r) {
265  free_cnt = (r - w) - 1;
266  } else {
267  free_cnt = size - 1;
268  }
269 
270  cnt2 = w + free_cnt;
271 
272  if (cnt2 > size) {
273 
274  /* Two part vector: the rest of the buffer after the
275  current write ptr, plus some from the start of
276  the buffer.
277  */
278 
279  vec->buf[0] = &buf[w];
280  vec->len[0] = size - w;
281  vec->buf[1] = buf;
282  vec->len[1] = cnt2 % size;
283  } else {
284  vec->buf[0] = &buf[w];
285  vec->len[0] = free_cnt;
286  vec->len[1] = 0;
287  }
288 }
289 
290 } /* namespace */
291 
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:77
void get_write_vector(rw_vector *)
RingBufferNPT(size_t sz)
Definition: ringbufferNPT.h:39
size_t bufsize() const
size_t get_read_ptr() const
void increment_write_ptr(size_t cnt)
Definition: ringbufferNPT.h:81
virtual ~RingBufferNPT()
Definition: ringbufferNPT.h:45
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:73
RingBufferNPT(RingBufferNPT const &)
void get_read_vector(rw_vector *)
void set(size_t r, size_t w)
Definition: ringbufferNPT.h:55
size_t get_write_ptr() const
Definition: axis_view.h:42