/[svn]/linuxsampler/trunk/src/common/RingBuffer.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/common/RingBuffer.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 361 by schoenebeck, Wed Feb 9 01:22:18 2005 UTC revision 1790 by persson, Sun Nov 2 12:05:00 2008 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2008 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 23  Line 24 
24  #ifndef RINGBUFFER_H  #ifndef RINGBUFFER_H
25  #define RINGBUFFER_H  #define RINGBUFFER_H
26    
27  #define DEFAULT_WRAP_ELEMENTS 1024  #define DEFAULT_WRAP_ELEMENTS 0
28    
29  #include <string.h>  #include <string.h>
30    
31  #include "atomic.h"  #include "lsatomic.h"
32    
33  template<class T>  using LinuxSampler::atomic;
34    using LinuxSampler::memory_order_relaxed;
35    using LinuxSampler::memory_order_acquire;
36    using LinuxSampler::memory_order_release;
37    
38    
39    /** @brief Real-time safe and type safe RingBuffer implementation.
40     *
41     * This constant size buffer can be used to send data from exactly one
42     * sender / writing thread to exactly one receiver / reading thread. It is
43     * real-time safe due to the fact that data is only allocated when this
44     * RingBuffer is created and no system level mechanisms are used for
45     * ensuring thread safety of this class.
46     *
47     * <b>Important:</b> There are two distinct behaviors of this RingBuffer
48     * which has to be given as template argument @c T_DEEP_COPY, which is a
49     * boolean flag:
50     *
51     * - @c true: The RingBuffer will copy elements of type @c T by using type
52     *   @c T's assignment operator. This behavior is mandatory for all data
53     *   structures (classes) which additionally allocate memory on the heap.
54     *   Type @c T's needs to have an assignment operator implementation though,
55     *   otherwise this will cause a compilation error. This behavior is more
56     *   safe, but usually slower (except for very small buffer sizes, where it
57     *   might be even faster).
58     * - @c false: The RingBuffer will copy elements of type @c T by flatly
59     *   copying their structural data ( i.e. with @c memcpy() ) in one piece.
60     *   This will only work if class @c T (and all of its subelements) does not
61     *   allocate any additional data on the heap by itself. So use this option
62     *   with great care, because otherwise it will result in very ugly behavior
63     *   and crashes! For larger buffer sizes, this behavior will most probably
64     *   be faster.
65     */
66    template<class T, bool T_DEEP_COPY>
67  class RingBuffer  class RingBuffer
68  {  {
69  public:  public:
70      RingBuffer (int sz, int wrap_elements = DEFAULT_WRAP_ELEMENTS) {      RingBuffer (int sz, int wrap_elements = DEFAULT_WRAP_ELEMENTS) :
71            write_ptr(0), read_ptr(0) {
72              int power_of_two;              int power_of_two;
73    
74              this->wrap_elements = wrap_elements;              this->wrap_elements = wrap_elements;
# Line 45  public: Line 80  public:
80              size = 1<<power_of_two;              size = 1<<power_of_two;
81              size_mask = size;              size_mask = size;
82              size_mask -= 1;              size_mask -= 1;
             atomic_set(&write_ptr, 0);  
             atomic_set(&read_ptr, 0);  
83              buf = new T[size + wrap_elements];              buf = new T[size + wrap_elements];
84      };      };
85    
# Line 58  public: Line 91  public:
91       * Sets all remaining write space elements to zero. The write pointer       * Sets all remaining write space elements to zero. The write pointer
92       * will currently not be incremented after, but that might change in       * will currently not be incremented after, but that might change in
93       * future.       * future.
94         *
95         * @e Caution: for @c T_DEEP_COPY=true you might probably @e NOT want
96         * to call this method at all, at least not in case type @c T allocates
97         * any additional data on the heap by itself.
98       */       */
99      inline void fill_write_space_with_null() {      inline void fill_write_space_with_null() {
100               int w = atomic_read(&write_ptr),               int w = write_ptr.load(memory_order_relaxed),
101                   r = atomic_read(&read_ptr);                   r = read_ptr.load(memory_order_acquire);
102               memset(get_write_ptr(), 0, write_space_to_end());               memset(get_write_ptr(), 0, sizeof(T)*write_space_to_end());
103               if (r && w >= r) {               if (r && w >= r) {
104                 memset(get_buffer_begin(), 0, r - 1);                 memset(get_buffer_begin(), 0, sizeof(T)*(r - 1));
105               }               }
106    
107               // set the wrap space elements to null               // set the wrap space elements to null
108               if (wrap_elements) memset(&buf[size], 0, wrap_elements);               if (wrap_elements) memset(&buf[size], 0, sizeof(T)*wrap_elements);
109             }             }
110    
111      __inline int  read (T *dest, int cnt);      __inline int  read (T *dest, int cnt);
# Line 80  public: Line 117  public:
117      __inline T *get_buffer_begin();      __inline T *get_buffer_begin();
118    
119      __inline T *get_read_ptr(void) {      __inline T *get_read_ptr(void) {
120        return(&buf[atomic_read(&read_ptr)]);        return(&buf[read_ptr.load(memory_order_relaxed)]);
121      }      }
122    
123      /**      /**
# Line 88  public: Line 125  public:
125       * advanced by \a offset elements.       * advanced by \a offset elements.
126       */       */
127      /*inline T* get_read_ptr(int offset) {      /*inline T* get_read_ptr(int offset) {
128          int r = atomic_read(&read_ptr);          int r = read_ptr.load(memory_order_relaxed);
129          r += offset;          r += offset;
130          r &= size_mask;          r &= size_mask;
131          return &buf[r];          return &buf[r];
# Line 96  public: Line 133  public:
133    
134      __inline T *get_write_ptr();      __inline T *get_write_ptr();
135      __inline void increment_read_ptr(int cnt) {      __inline void increment_read_ptr(int cnt) {
136                 atomic_set(&read_ptr , (atomic_read(&read_ptr) + cnt) & size_mask);                 read_ptr.store((read_ptr.load(memory_order_relaxed) + cnt) & size_mask, memory_order_release);
137               }               }
138      __inline void set_read_ptr(int val) {      __inline void set_read_ptr(int val) {
139                 atomic_set(&read_ptr , val);                 read_ptr.store(val, memory_order_release);
140               }               }
141    
142      __inline void increment_write_ptr(int cnt) {      __inline void increment_write_ptr(int cnt) {
143                 atomic_set(&write_ptr,  (atomic_read(&write_ptr) + cnt) & size_mask);                 write_ptr.store((write_ptr.load(memory_order_relaxed) + cnt) & size_mask, memory_order_release);
144               }               }
145    
146      /* this function increments the write_ptr by cnt, if the buffer wraps then      /* this function increments the write_ptr by cnt, if the buffer wraps then
# Line 118  public: Line 155  public:
155         and the write ptr incremented accordingly.         and the write ptr incremented accordingly.
156      */      */
157      __inline void increment_write_ptr_with_wrap(int cnt) {      __inline void increment_write_ptr_with_wrap(int cnt) {
158                 int w=atomic_read(&write_ptr);                 int w = write_ptr.load(memory_order_relaxed);
159                 w += cnt;                 w += cnt;
160                 if(w >= size) {                 if(w >= size) {
161                   w -= size;                   w -= size;
162                   memcpy(&buf[0], &buf[size], w*sizeof(T));                   copy(&buf[0], &buf[size], w);
163  //printf("DEBUG !!!! increment_write_ptr_with_wrap: buffer wrapped, elements wrapped = %d (wrap_elements %d)\n",w,wrap_elements);  //printf("DEBUG !!!! increment_write_ptr_with_wrap: buffer wrapped, elements wrapped = %d (wrap_elements %d)\n",w,wrap_elements);
164                 }                 }
165                 atomic_set(&write_ptr, w);                 write_ptr.store(w, memory_order_release);
166               }               }
167    
168      /* this function returns the available write space in the buffer      /* this function returns the available write space in the buffer
# Line 145  public: Line 182  public:
182      __inline int write_space_to_end_with_wrap() {      __inline int write_space_to_end_with_wrap() {
183                int w, r;                int w, r;
184    
185                w = atomic_read(&write_ptr);                w = write_ptr.load(memory_order_relaxed);
186                r = atomic_read(&read_ptr);                r = read_ptr.load(memory_order_acquire);
187  //printf("write_space_to_end: w=%d r=%d\n",w,r);  //printf("write_space_to_end: w=%d r=%d\n",w,r);
188                if(r > w) {                if(r > w) {
189                  //printf("DEBUG: write_space_to_end_with_wrap: r>w r=%d w=%d val=%d\n",r,w,r - w - 1);                  //printf("DEBUG: write_space_to_end_with_wrap: r>w r=%d w=%d val=%d\n",r,w,r - w - 1);
# Line 184  public: Line 221  public:
221             */             */
222      __inline int adjust_write_space_to_avoid_boundary(int cnt, int capped_cnt) {      __inline int adjust_write_space_to_avoid_boundary(int cnt, int capped_cnt) {
223                 int w;                 int w;
224                 w = atomic_read(&write_ptr);                 w = write_ptr.load(memory_order_relaxed);
225                 if((w+capped_cnt) >= size && (w+capped_cnt) < (size+wrap_elements)) {                 if((w+capped_cnt) >= size && (w+capped_cnt) < (size+wrap_elements)) {
226  //printf("adjust_write_space_to_avoid_boundary returning cnt = %d\n",cnt);  //printf("adjust_write_space_to_avoid_boundary returning cnt = %d\n",cnt);
227                   return(cnt);                   return(cnt);
# Line 196  public: Line 233  public:
233      __inline int write_space_to_end() {      __inline int write_space_to_end() {
234                int w, r;                int w, r;
235    
236                w = atomic_read(&write_ptr);                w = write_ptr.load(memory_order_relaxed);
237                r = atomic_read(&read_ptr);                r = read_ptr.load(memory_order_acquire);
238  //printf("write_space_to_end: w=%d r=%d\n",w,r);  //printf("write_space_to_end: w=%d r=%d\n",w,r);
239                if(r > w) return(r - w - 1);                if(r > w) return(r - w - 1);
240                if(r) return(size - w);                if(r) return(size - w);
# Line 207  public: Line 244  public:
244      __inline int read_space_to_end() {      __inline int read_space_to_end() {
245                int w, r;                int w, r;
246    
247                w = atomic_read(&write_ptr);                w = write_ptr.load(memory_order_acquire);
248                r = atomic_read(&read_ptr);                r = read_ptr.load(memory_order_relaxed);
249                if(w >= r) return(w - r);                if(w >= r) return(w - r);
250                return(size - r);                return(size - r);
251              }              }
252      __inline void init() {      __inline void init() {
253                     atomic_set(&write_ptr, 0);                     write_ptr.store(0, memory_order_relaxed);
254                     atomic_set(&read_ptr, 0);                     read_ptr.store(0, memory_order_relaxed);
255                   //  wrap=0;                   //  wrap=0;
256              }              }
257    
258      int write_space () {      int write_space () {
259              int w, r;              int w, r;
260    
261              w = atomic_read(&write_ptr);              w = write_ptr.load(memory_order_relaxed);
262              r = atomic_read(&read_ptr);              r = read_ptr.load(memory_order_acquire);
263    
264              if (w > r) {              if (w > r) {
265                      return ((r - w + size) & size_mask) - 1;                      return ((r - w + size) & size_mask) - 1;
# Line 236  public: Line 273  public:
273      int read_space () {      int read_space () {
274              int w, r;              int w, r;
275    
276              w = atomic_read(&write_ptr);              w = write_ptr.load(memory_order_acquire);
277              r = atomic_read(&read_ptr);              r = read_ptr.load(memory_order_relaxed);
278    
279              if (w >= r) {              if (w >= r) {
280                      return w - r;                      return w - r;
# Line 254  public: Line 291  public:
291       * allows to read from a RingBuffer without being forced to free read       * allows to read from a RingBuffer without being forced to free read
292       * data while reading / positioning.       * data while reading / positioning.
293       */       */
294      template<class T1>      template<class T1, bool T1_DEEP_COPY>
295      class _NonVolatileReader {      class _NonVolatileReader {
296          public:          public:
297              int read_space() {              int read_space() {
298                  int r = read_ptr;                  int r = read_ptr;
299                  int w = atomic_read(&pBuf->write_ptr);                  int w = pBuf->write_ptr.load(memory_order_acquire);
300                  return (w >= r) ? w - r : (w - r + pBuf->size) & pBuf->size_mask;                  return (w >= r) ? w - r : (w - r + pBuf->size) & pBuf->size_mask;
301              }              }
302    
# Line 268  public: Line 305  public:
305               * read position by one.               * read position by one.
306               */               */
307              inline void operator--() {              inline void operator--() {
308                  if (read_ptr == atomic_read(&pBuf->read_ptr)) return; //TODO: or should we react oh this case (e.g. force segfault), as this is a very odd case?                  if (read_ptr == pBuf->read_ptr.load(memory_order_relaxed)) return; //TODO: or should we react oh this case (e.g. force segfault), as this is a very odd case?
309                  --read_ptr & pBuf->size_mask;                  read_ptr = (read_ptr-1) & pBuf->size_mask;
310              }              }
311    
312              /**              /**
# Line 339  public: Line 376  public:
376                      n2 = 0;                      n2 = 0;
377                  }                  }
378    
379                  memcpy(dest, &pBuf->buf[priv_read_ptr], n1 * sizeof(T));                  copy(dest, &pBuf->buf[priv_read_ptr], n1);
380                  priv_read_ptr = (priv_read_ptr + n1) & pBuf->size_mask;                  priv_read_ptr = (priv_read_ptr + n1) & pBuf->size_mask;
381    
382                  if (n2) {                  if (n2) {
383                      memcpy(dest+n1, pBuf->buf, n2 * sizeof(T));                      copy(dest+n1, pBuf->buf, n2);
384                      priv_read_ptr = n2;                      priv_read_ptr = n2;
385                  }                  }
386    
# Line 359  public: Line 396  public:
396               * @see RingBuffer::increment_read_ptr()               * @see RingBuffer::increment_read_ptr()
397               */               */
398              void free() {              void free() {
399                  atomic_set(&pBuf->read_ptr, read_ptr);                  pBuf->read_ptr.store(read_ptr, memory_order_release);
400              }              }
401    
402          protected:          protected:
403              _NonVolatileReader(RingBuffer<T1>* pBuf) {              _NonVolatileReader(RingBuffer<T1,T1_DEEP_COPY>* pBuf) {
404                  this->pBuf     = pBuf;                  this->pBuf     = pBuf;
405                  this->read_ptr = atomic_read(&pBuf->read_ptr);                  this->read_ptr = pBuf->read_ptr.load(memory_order_relaxed);
406              }              }
407    
408              RingBuffer<T1>* pBuf;              RingBuffer<T1,T1_DEEP_COPY>* pBuf;
409              int read_ptr;              int read_ptr;
410    
411              friend class RingBuffer<T1>;              friend class RingBuffer<T1,T1_DEEP_COPY>;
412      };      };
413    
414      typedef _NonVolatileReader<T> NonVolatileReader;      typedef _NonVolatileReader<T,T_DEEP_COPY> NonVolatileReader;
415    
416      NonVolatileReader get_non_volatile_reader() { return NonVolatileReader(this); }      NonVolatileReader get_non_volatile_reader() { return NonVolatileReader(this); }
417    
418    protected:    protected:
419      T *buf;      T *buf;
420      atomic_t write_ptr;      atomic<int> write_ptr;
421      atomic_t read_ptr;      atomic<int> read_ptr;
422      int size_mask;      int size_mask;
423    
424      friend class _NonVolatileReader<T>;      /**
425         * Copies \a n amount of elements from the buffer given by
426         * \a pSrc to the buffer given by \a pDst.
427         */
428        inline static void copy(T* pDst, T* pSrc, int n);
429    
430        friend class _NonVolatileReader<T,T_DEEP_COPY>;
431  };  };
432    
433  template<class T> T *  template<class T, bool T_DEEP_COPY>
434  RingBuffer<T>::get_write_ptr (void) {  T* RingBuffer<T,T_DEEP_COPY>::get_write_ptr (void) {
435    return(&buf[atomic_read(&write_ptr)]);    return(&buf[write_ptr.load(memory_order_relaxed)]);
436  }  }
437    
438  template<class T> T *  template<class T, bool T_DEEP_COPY>
439  RingBuffer<T>::get_buffer_begin (void) {  T* RingBuffer<T,T_DEEP_COPY>::get_buffer_begin (void) {
440    return(buf);    return(buf);
441  }  }
442    
443    
444    
445  template<class T> int  template<class T, bool T_DEEP_COPY>
446  RingBuffer<T>::read (T *dest, int cnt)  int RingBuffer<T,T_DEEP_COPY>::read(T* dest, int cnt)
   
447  {  {
448          int free_cnt;          int free_cnt;
449          int cnt2;          int cnt2;
# Line 409  RingBuffer<T>::read (T *dest, int cnt) Line 451  RingBuffer<T>::read (T *dest, int cnt)
451          int n1, n2;          int n1, n2;
452          int priv_read_ptr;          int priv_read_ptr;
453    
454          priv_read_ptr=atomic_read(&read_ptr);          priv_read_ptr = read_ptr.load(memory_order_relaxed);
455    
456          if ((free_cnt = read_space ()) == 0) {          if ((free_cnt = read_space ()) == 0) {
457                  return 0;                  return 0;
# Line 427  RingBuffer<T>::read (T *dest, int cnt) Line 469  RingBuffer<T>::read (T *dest, int cnt)
469                  n2 = 0;                  n2 = 0;
470          }          }
471    
472          memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));          copy(dest, &buf[priv_read_ptr], n1);
473          priv_read_ptr = (priv_read_ptr + n1) & size_mask;          priv_read_ptr = (priv_read_ptr + n1) & size_mask;
474    
475          if (n2) {          if (n2) {
476                  memcpy (dest+n1, buf, n2 * sizeof (T));                  copy(dest+n1, buf, n2);
477                  priv_read_ptr = n2;                  priv_read_ptr = n2;
478          }          }
479    
480          atomic_set(&read_ptr, priv_read_ptr);          read_ptr.store(priv_read_ptr, memory_order_release);
481          return to_read;          return to_read;
482  }  }
483    
484  template<class T> int  template<class T, bool T_DEEP_COPY>
485  RingBuffer<T>::write (T *src, int cnt)  int RingBuffer<T,T_DEEP_COPY>::write(T* src, int cnt)
   
486  {  {
487          int free_cnt;          int free_cnt;
488          int cnt2;          int cnt2;
# Line 449  RingBuffer<T>::write (T *src, int cnt) Line 490  RingBuffer<T>::write (T *src, int cnt)
490          int n1, n2;          int n1, n2;
491          int priv_write_ptr;          int priv_write_ptr;
492    
493          priv_write_ptr=atomic_read(&write_ptr);          priv_write_ptr = write_ptr.load(memory_order_relaxed);
494    
495          if ((free_cnt = write_space ()) == 0) {          if ((free_cnt = write_space ()) == 0) {
496                  return 0;                  return 0;
# Line 467  RingBuffer<T>::write (T *src, int cnt) Line 508  RingBuffer<T>::write (T *src, int cnt)
508                  n2 = 0;                  n2 = 0;
509          }          }
510    
511          memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));          copy(&buf[priv_write_ptr], src, n1);
512          priv_write_ptr = (priv_write_ptr + n1) & size_mask;          priv_write_ptr = (priv_write_ptr + n1) & size_mask;
513    
514          if (n2) {          if (n2) {
515                  memcpy (buf, src+n1, n2 * sizeof (T));                  copy(buf, src+n1, n2);
516                  priv_write_ptr = n2;                  priv_write_ptr = n2;
517          }          }
518          atomic_set(&write_ptr, priv_write_ptr);          write_ptr.store(priv_write_ptr, memory_order_release);
519          return to_write;          return to_write;
520  }  }
521    
522    template<class T, bool T_DEEP_COPY>
523    void RingBuffer<T,T_DEEP_COPY>::copy(T* pDst, T* pSrc, int n) {
524        if (T_DEEP_COPY) { // deep copy - won't work for data structures without assignment operator implementation
525            for (int i = 0; i < n; i++) pDst[i] = pSrc[i];
526        } else { // flat copy - won't work for complex data structures !
527            memcpy(pDst, pSrc, n * sizeof(T));
528        }
529    }
530    
531  #endif /* RINGBUFFER_H */  #endif /* RINGBUFFER_H */

Legend:
Removed from v.361  
changed lines
  Added in v.1790

  ViewVC Help
Powered by ViewVC