jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
6.6KB

  1. /*
  2. Copyright (C) 2000 Paul Davis
  3. Copyright (C) 2003 Rohan Drape
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code.
  16. This is safe for the case of one read thread and one write thread.
  17. */
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <sys/mman.h>
  21. #include "ringbuffer.h"
  22. /* Create a new ringbuffer to hold at least `sz' bytes of data. The
  23. actual buffer size is rounded up to the next power of two. */
  24. ringbuffer_t *
  25. ringbuffer_create (int sz)
  26. {
  27. int power_of_two;
  28. ringbuffer_t *rb;
  29. rb = malloc (sizeof (ringbuffer_t));
  30. for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++);
  31. rb->size = 1 << power_of_two;
  32. rb->size_mask = rb->size;
  33. rb->size_mask -= 1;
  34. rb->write_ptr = 0;
  35. rb->read_ptr = 0;
  36. rb->buf = malloc (rb->size);
  37. rb->mlocked = 0;
  38. return rb;
  39. }
  40. /* Free all data associated with the ringbuffer `rb'. */
  41. void
  42. ringbuffer_free (ringbuffer_t * rb)
  43. {
  44. if (rb->mlocked) {
  45. munlock (rb->buf, rb->size);
  46. }
  47. free (rb->buf);
  48. }
  49. /* Lock the data block of `rb' using the system call 'mlock'. */
  50. int
  51. ringbuffer_mlock (ringbuffer_t * rb)
  52. {
  53. if (mlock (rb->buf, rb->size)) {
  54. return -1;
  55. }
  56. rb->mlocked = 1;
  57. return 0;
  58. }
  59. /* Reset the read and write pointers to zero. This is not thread
  60. safe. */
  61. void
  62. ringbuffer_reset (ringbuffer_t * rb)
  63. {
  64. rb->read_ptr = 0;
  65. rb->write_ptr = 0;
  66. }
  67. /* Return the number of bytes available for reading. This is the
  68. number of bytes in front of the read pointer and behind the write
  69. pointer. */
  70. size_t
  71. ringbuffer_read_space (ringbuffer_t * rb)
  72. {
  73. size_t w, r;
  74. w = rb->write_ptr;
  75. r = rb->read_ptr;
  76. if (w > r) {
  77. return w - r;
  78. } else {
  79. return (w - r + rb->size) & rb->size_mask;
  80. }
  81. }
  82. /* Return the number of bytes available for writing. This is the
  83. number of bytes in front of the write pointer and behind the read
  84. pointer. */
  85. size_t
  86. ringbuffer_write_space (ringbuffer_t * rb)
  87. {
  88. size_t w, r;
  89. w = rb->write_ptr;
  90. r = rb->read_ptr;
  91. if (w > r) {
  92. return ((r - w + rb->size) & rb->size_mask) - 1;
  93. } else if (w < r) {
  94. return (r - w) - 1;
  95. } else {
  96. return rb->size - 1;
  97. }
  98. }
  99. /* The copying data reader. Copy at most `cnt' bytes from `rb' to
  100. `dest'. Returns the actual number of bytes copied. */
  101. size_t
  102. ringbuffer_read (ringbuffer_t * rb, char *dest, size_t cnt)
  103. {
  104. size_t free_cnt;
  105. size_t cnt2;
  106. size_t to_read;
  107. size_t n1, n2;
  108. if ((free_cnt = ringbuffer_read_space (rb)) == 0) {
  109. return 0;
  110. }
  111. to_read = cnt > free_cnt ? free_cnt : cnt;
  112. cnt2 = rb->read_ptr + to_read;
  113. if (cnt2 > rb->size) {
  114. n1 = rb->size - rb->read_ptr;
  115. n2 = cnt2 & rb->size_mask;
  116. } else {
  117. n1 = to_read;
  118. n2 = 0;
  119. }
  120. memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
  121. rb->read_ptr += n1;
  122. rb->read_ptr &= rb->size_mask;
  123. if (n2) {
  124. memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
  125. rb->read_ptr += n2;
  126. rb->read_ptr &= rb->size_mask;
  127. }
  128. return to_read;
  129. }
  130. /* The copying data writer. Copy at most `cnt' bytes to `rb' from
  131. `src'. Returns the actual number of bytes copied. */
  132. size_t
  133. ringbuffer_write (ringbuffer_t * rb, char *src, size_t cnt)
  134. {
  135. size_t free_cnt;
  136. size_t cnt2;
  137. size_t to_write;
  138. size_t n1, n2;
  139. if ((free_cnt = ringbuffer_write_space (rb)) == 0) {
  140. return 0;
  141. }
  142. to_write = cnt > free_cnt ? free_cnt : cnt;
  143. cnt2 = rb->write_ptr + to_write;
  144. if (cnt2 > rb->size) {
  145. n1 = rb->size - rb->write_ptr;
  146. n2 = cnt2 & rb->size_mask;
  147. } else {
  148. n1 = to_write;
  149. n2 = 0;
  150. }
  151. memcpy (&(rb->buf[rb->write_ptr]), src, n1);
  152. rb->write_ptr += n1;
  153. rb->write_ptr &= rb->size_mask;
  154. if (n2) {
  155. memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
  156. rb->write_ptr += n2;
  157. rb->write_ptr &= rb->size_mask;
  158. }
  159. return to_write;
  160. }
  161. /* Advance the read pointer `cnt' places. */
  162. void
  163. ringbuffer_read_advance (ringbuffer_t * rb, size_t cnt)
  164. {
  165. rb->read_ptr += cnt;
  166. rb->read_ptr &= rb->size_mask;
  167. }
  168. /* Advance the write pointer `cnt' places. */
  169. void
  170. ringbuffer_write_advance (ringbuffer_t * rb, size_t cnt)
  171. {
  172. rb->write_ptr += cnt;
  173. rb->write_ptr &= rb->size_mask;
  174. }
  175. /* The non-copying data reader. `vec' is an array of two places. Set
  176. the values at `vec' to hold the current readable data at `rb'. If
  177. the readable data is in one segment the second segment has zero
  178. length. */
  179. void
  180. ringbuffer_get_read_vector (ringbuffer_t * rb,
  181. 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. /* The non-copying data writer. `vec' is an array of two places. Set
  209. the values at `vec' to hold the current writeable data at `rb'. If
  210. the writeable data is in one segment the second segment has zero
  211. length. */
  212. void
  213. ringbuffer_get_write_vector (ringbuffer_t * rb,
  214. ringbuffer_data_t * vec)
  215. {
  216. size_t free_cnt;
  217. size_t cnt2;
  218. size_t w, r;
  219. w = rb->write_ptr;
  220. r = rb->read_ptr;
  221. if (w > r) {
  222. free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
  223. } else if (w < r) {
  224. free_cnt = (r - w) - 1;
  225. } else {
  226. free_cnt = rb->size - 1;
  227. }
  228. cnt2 = w + free_cnt;
  229. if (cnt2 > rb->size) {
  230. /* Two part vector: the rest of the buffer after the current write
  231. ptr, plus some from the start of the buffer. */
  232. vec[0].buf = &(rb->buf[w]);
  233. vec[0].len = rb->size - w;
  234. vec[1].buf = rb->buf;
  235. vec[1].len = cnt2 & rb->size_mask;
  236. } else {
  237. vec[0].buf = &(rb->buf[w]);
  238. vec[0].len = free_cnt;
  239. vec[1].len = 0;
  240. }
  241. }