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