ringbuffer.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // ringbuffer.cpp
  2. //
  3. // A lock-free ring buffer.
  4. //
  5. // (C) Copyright 2000 Paul Davis
  6. // (C) Copyright 2003 Rohan Drape
  7. // (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com>
  8. //
  9. // $Id: ringbuffer.cpp,v 1.1 2007/12/19 20:22:23 fredg Exp $
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU Library General Public License
  13. // version 2 as published by the Free Software Foundation.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public
  21. // License along with this program; if not, write to the Free Software
  22. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. //
  24. // Adapted from code by Paul Davis and Rohan Drape in
  25. // 'example-clients/ringbuffer.ch' in the Jack Audio Connection Kit.
  26. //
  27. #include <sys/types.h>
  28. #include <sys/mman.h>
  29. #include <err.h>
  30. #include <fcntl.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <unistd.h>
  35. #include "ringbuffer.h"
  36. RingBuffer::RingBuffer(char* shmfile,int pages)
  37. {
  38. int tmp=0;
  39. char* data=nullptr;
  40. if(pages)
  41. {
  42. int power_of_two;
  43. for (power_of_two = 1; 1 << power_of_two < pages; power_of_two++);
  44. pages = 1 << power_of_two;
  45. unlink(shmfile);
  46. fd = open(shmfile, O_RDWR|O_CREAT, 0666);
  47. void* zeropage = calloc (4096,1);
  48. for(int i=0;i<pages+1;i++) ::write(fd, zeropage, 4096);
  49. free(zeropage);
  50. data_size = 4096*(pages+1);
  51. }
  52. else
  53. {
  54. fd = open(shmfile, O_RDWR, 0);
  55. ringbuffer_t hdr;
  56. ::read(fd,&hdr,sizeof(hdr));
  57. if(memcmp(&hdr,"RING",4)!=0)
  58. {
  59. fprintf(stderr,"Ringbuffer: invalid typesig\n");
  60. abort();
  61. }
  62. tmp = hdr.size/4096;
  63. data_size = 4096*(tmp+1);
  64. }
  65. lseek(fd,0,SEEK_SET);
  66. data = (char*)mmap(NULL, data_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  67. if(!data) {
  68. fprintf(stderr,"Ringbuffer: mmap failed\n");
  69. abort();
  70. }
  71. rb = (ringbuffer_t*)data;
  72. rb_buf = data+4096;
  73. if(pages)
  74. {
  75. memcpy(rb->typesig,"RING",4);
  76. rb->size = pages*4096;
  77. rb->size_mask = rb->size;
  78. rb->size_mask -= 1;
  79. rb->write_ptr = 0;
  80. rb->read_ptr = 0;
  81. }
  82. }
  83. RingBuffer::~RingBuffer()
  84. {
  85. close(fd);
  86. munmap((void*)rb,data_size);
  87. }
  88. void RingBuffer::reset()
  89. {
  90. rb->read_ptr = 0;
  91. rb->write_ptr = 0;
  92. }
  93. void RingBuffer::writeAdvance(size_t cnt)
  94. {
  95. rb->write_ptr += cnt;
  96. rb->write_ptr &= rb->size_mask;
  97. }
  98. void RingBuffer::readAdvance(size_t cnt)
  99. {
  100. rb->read_ptr += cnt;
  101. rb->read_ptr &= rb->size_mask;
  102. }
  103. size_t RingBuffer::writeSpace() const
  104. {
  105. size_t w, r;
  106. w = rb->write_ptr;
  107. r = rb->read_ptr;
  108. if (w > r) {
  109. return ((r - w + rb->size) & rb->size_mask) - 1;
  110. } else if (w < r) {
  111. return (r - w) - 1;
  112. }
  113. return rb->size - 1;
  114. }
  115. size_t RingBuffer::readSpace() const
  116. {
  117. size_t w, r;
  118. w = rb->write_ptr;
  119. r = rb->read_ptr;
  120. if (w > r) {
  121. return w - r;
  122. }
  123. return (w - r + rb->size) & rb->size_mask;
  124. }
  125. size_t RingBuffer::read(char *dest,size_t cnt)
  126. {
  127. size_t free_cnt;
  128. size_t cnt2;
  129. size_t to_read;
  130. size_t n1, n2;
  131. if ((free_cnt = readSpace()) == 0) {
  132. return 0;
  133. }
  134. to_read = cnt > free_cnt ? free_cnt : cnt;
  135. cnt2 = rb->read_ptr + to_read;
  136. if (cnt2 > rb->size) {
  137. n1 = rb->size - rb->read_ptr;
  138. n2 = cnt2 & rb->size_mask;
  139. } else {
  140. n1 = to_read;
  141. n2 = 0;
  142. }
  143. memcpy (dest, &(rb_buf[rb->read_ptr]), n1);
  144. rb->read_ptr += n1;
  145. rb->read_ptr &= rb->size_mask;
  146. if (n2) {
  147. memcpy (dest + n1, &(rb_buf[rb->read_ptr]), n2);
  148. rb->read_ptr += n2;
  149. rb->read_ptr &= rb->size_mask;
  150. }
  151. return to_read;
  152. }
  153. size_t RingBuffer::write(char *src,size_t cnt)
  154. {
  155. size_t free_cnt;
  156. size_t cnt2;
  157. size_t to_write;
  158. size_t n1, n2;
  159. if ((free_cnt = writeSpace()) == 0) {
  160. return 0;
  161. }
  162. to_write = cnt > free_cnt ? free_cnt : cnt;
  163. cnt2 = rb->write_ptr + to_write;
  164. if (cnt2 > rb->size) {
  165. n1 = rb->size - rb->write_ptr;
  166. n2 = cnt2 & rb->size_mask;
  167. } else {
  168. n1 = to_write;
  169. n2 = 0;
  170. }
  171. memcpy (&(rb_buf[rb->write_ptr]), src, n1);
  172. rb->write_ptr += n1;
  173. rb->write_ptr &= rb->size_mask;
  174. if (n2) {
  175. memcpy (&(rb_buf[rb->write_ptr]), src + n1, n2);
  176. rb->write_ptr += n2;
  177. rb->write_ptr &= rb->size_mask;
  178. }
  179. return to_write;
  180. }
  181. void RingBuffer::getReadVector(ringbuffer_data_t *vec)
  182. {
  183. size_t free_cnt;
  184. size_t cnt2;
  185. size_t w, r;
  186. w = rb->write_ptr;
  187. r = rb->read_ptr;
  188. if (w > r) {
  189. free_cnt = w - r;
  190. } else {
  191. free_cnt = (w - r + rb->size) & rb->size_mask;
  192. }
  193. cnt2 = r + free_cnt;
  194. if (cnt2 > rb->size) {
  195. /* Two part vector: the rest of the buffer after the current write
  196. ptr, plus some from the start of the buffer. */
  197. vec[0].buf = &(rb_buf[r]);
  198. vec[0].len = rb->size - r;
  199. vec[1].buf = rb_buf;
  200. vec[1].len = cnt2 & rb->size_mask;
  201. } else {
  202. /* Single part vector: just the rest of the buffer */
  203. vec[0].buf = &(rb_buf[r]);
  204. vec[0].len = free_cnt;
  205. vec[1].len = 0;
  206. }
  207. }
  208. void RingBuffer::getWriteVector(ringbuffer_data_t *vec)
  209. {
  210. size_t free_cnt;
  211. size_t cnt2;
  212. size_t w, r;
  213. w = rb->write_ptr;
  214. r = rb->read_ptr;
  215. if (w > r) {
  216. free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
  217. } else if (w < r) {
  218. free_cnt = (r - w) - 1;
  219. } else {
  220. free_cnt = rb->size - 1;
  221. }
  222. cnt2 = w + free_cnt;
  223. if (cnt2 > rb->size) {
  224. /* Two part vector: the rest of the buffer after the current write
  225. ptr, plus some from the start of the buffer. */
  226. vec[0].buf = &(rb_buf[w]);
  227. vec[0].len = rb->size - w;
  228. vec[1].buf = rb_buf;
  229. vec[1].len = cnt2 & rb->size_mask;
  230. } else {
  231. vec[0].buf = &(rb_buf[w]);
  232. vec[0].len = free_cnt;
  233. vec[1].len = 0;
  234. }
  235. }
  236. void* RingBuffer::getUserdata()
  237. {
  238. return (char*)rb+sizeof(rb);
  239. }