lws-ring.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to
  8. * deal in the Software without restriction, including without limitation the
  9. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. * sell copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. * IN THE SOFTWARE.
  23. */
  24. #include <libwebsockets.h>
  25. #include "private-lib-core.h"
  26. struct lws_ring *
  27. lws_ring_create(size_t element_len, size_t count,
  28. void (*destroy_element)(void *))
  29. {
  30. struct lws_ring *ring = lws_malloc(sizeof(*ring), "ring create");
  31. if (!ring)
  32. return NULL;
  33. ring->buflen = (uint32_t)(count * element_len);
  34. ring->element_len = (uint32_t)element_len;
  35. ring->head = 0;
  36. ring->oldest_tail = 0;
  37. ring->destroy_element = destroy_element;
  38. ring->buf = lws_malloc(ring->buflen, "ring buf");
  39. if (!ring->buf) {
  40. lws_free(ring);
  41. return NULL;
  42. }
  43. return ring;
  44. }
  45. void
  46. lws_ring_destroy(struct lws_ring *ring)
  47. {
  48. if (ring->destroy_element)
  49. while (ring->oldest_tail != ring->head) {
  50. ring->destroy_element((uint8_t *)ring->buf +
  51. ring->oldest_tail);
  52. ring->oldest_tail =
  53. (ring->oldest_tail + ring->element_len) %
  54. ring->buflen;
  55. }
  56. if (ring->buf)
  57. lws_free_set_NULL(ring->buf);
  58. lws_free(ring);
  59. }
  60. size_t
  61. lws_ring_get_count_free_elements(struct lws_ring *ring)
  62. {
  63. int f;
  64. /*
  65. * possible ringbuf patterns
  66. *
  67. * h == t
  68. * |--------t***h---|
  69. * |**h-----------t*|
  70. * |t**************h|
  71. * |*****ht*********|
  72. */
  73. if (ring->head == ring->oldest_tail)
  74. f = ring->buflen - ring->element_len;
  75. else
  76. if (ring->head < ring->oldest_tail)
  77. f = (ring->oldest_tail - ring->head) -
  78. ring->element_len;
  79. else
  80. f = (ring->buflen - ring->head) + ring->oldest_tail -
  81. ring->element_len;
  82. if (f < 2)
  83. return 0;
  84. return f / ring->element_len;
  85. }
  86. size_t
  87. lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)
  88. { int f;
  89. if (!tail)
  90. tail = &ring->oldest_tail;
  91. /*
  92. * possible ringbuf patterns
  93. *
  94. * h == t
  95. * |--------t***h---|
  96. * |**h-----------t*|
  97. * |t**************h|
  98. * |*****ht*********|
  99. */
  100. if (ring->head == *tail)
  101. f = 0;
  102. else
  103. if (ring->head > *tail)
  104. f = (ring->head - *tail);
  105. else
  106. f = (ring->buflen - *tail) + ring->head;
  107. return f / ring->element_len;
  108. }
  109. int
  110. lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
  111. size_t *bytes)
  112. {
  113. int n;
  114. /* n is how many bytes the whole fifo can take */
  115. n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len);
  116. if (!n)
  117. return 1;
  118. if (ring->head + n > ring->buflen) {
  119. *start = (void *)(((uint8_t *)ring->buf) + ring->head);
  120. *bytes = ring->buflen - ring->head;
  121. return 0;
  122. }
  123. *start = (void *)(((uint8_t *)ring->buf) + ring->head);
  124. *bytes = n;
  125. return 0;
  126. }
  127. void
  128. lws_ring_bump_head(struct lws_ring *ring, size_t bytes)
  129. {
  130. ring->head = (ring->head + (uint32_t)bytes) % ring->buflen;
  131. }
  132. size_t
  133. lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
  134. {
  135. const uint8_t *osrc = src;
  136. int m, n;
  137. /* n is how many bytes the whole fifo can take */
  138. n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len);
  139. /* restrict n to how much we want to insert */
  140. if ((uint32_t)n > max_count * ring->element_len)
  141. n = (int)(max_count * ring->element_len);
  142. /*
  143. * n is legal to insert, but as an optimization we can cut the
  144. * insert into one or two memcpys, depending on if it wraps
  145. */
  146. if (ring->head + n > ring->buflen) {
  147. /*
  148. * He does wrap. The first memcpy should take us up to
  149. * the end of the buffer
  150. */
  151. m = ring->buflen - ring->head;
  152. memcpy(((uint8_t *)ring->buf) + ring->head, src, m);
  153. /* we know it will wrap exactly back to zero */
  154. ring->head = 0;
  155. /* adapt the second memcpy for what we already did */
  156. src = ((uint8_t *)src) + m;
  157. n -= m;
  158. }
  159. memcpy(((uint8_t *)ring->buf) + ring->head, src, n);
  160. ring->head = (ring->head + n) % ring->buflen;
  161. return (((uint8_t *)src + n) - osrc) / ring->element_len;
  162. }
  163. size_t
  164. lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
  165. size_t max_count)
  166. {
  167. uint8_t *odest = dest;
  168. void *orig_tail = tail;
  169. uint32_t fake_tail;
  170. int m, n;
  171. if (!tail) {
  172. fake_tail = ring->oldest_tail;
  173. tail = &fake_tail;
  174. }
  175. /* n is how many bytes the whole fifo has for us */
  176. n = (int)(lws_ring_get_count_waiting_elements(ring, tail) *
  177. ring->element_len);
  178. /* restrict n to how much we want to insert */
  179. if ((size_t)n > max_count * ring->element_len)
  180. n = (int)(max_count * ring->element_len);
  181. if (!dest) {
  182. *tail = ((*tail) + n) % ring->buflen;
  183. if (!orig_tail) /* single tail */
  184. lws_ring_update_oldest_tail(ring, *tail);
  185. return n / ring->element_len;
  186. }
  187. if (*tail + n > ring->buflen) {
  188. /*
  189. * He does wrap. The first memcpy should take us up to
  190. * the end of the buffer
  191. */
  192. m = ring->buflen - *tail;
  193. memcpy(dest, ((uint8_t *)ring->buf) + *tail, m);
  194. /* we know it will wrap exactly back to zero */
  195. *tail = 0;
  196. /* adapt the second memcpy for what we already did */
  197. dest = ((uint8_t *)dest) + m;
  198. n -= m;
  199. }
  200. memcpy(dest, ((uint8_t *)ring->buf) + *tail, n);
  201. *tail = ((*tail) + n) % ring->buflen;
  202. if (!orig_tail) /* single tail */
  203. lws_ring_update_oldest_tail(ring, *tail);
  204. return (((uint8_t *)dest + n) - odest) / ring->element_len;
  205. }
  206. const void *
  207. lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)
  208. {
  209. if (!tail)
  210. tail = &ring->oldest_tail;
  211. if (*tail == ring->head)
  212. return NULL;
  213. return ((uint8_t *)ring->buf) + *tail;
  214. }
  215. void
  216. lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
  217. {
  218. if (!ring->destroy_element) {
  219. ring->oldest_tail = tail;
  220. return;
  221. }
  222. while (ring->oldest_tail != tail) {
  223. ring->destroy_element((uint8_t *)ring->buf + ring->oldest_tail);
  224. ring->oldest_tail = (ring->oldest_tail + ring->element_len) %
  225. ring->buflen;
  226. }
  227. }
  228. uint32_t
  229. lws_ring_get_oldest_tail(struct lws_ring *ring)
  230. {
  231. return ring->oldest_tail;
  232. }
  233. void
  234. lws_ring_dump(struct lws_ring *ring, uint32_t *tail)
  235. {
  236. if (tail == NULL)
  237. tail = &ring->oldest_tail;
  238. lwsl_notice("ring %p: buflen %u, elem_len %u, head %u, oldest_tail %u\n"
  239. " free_elems: %u; for tail %u, waiting elements: %u\n",
  240. ring, (int)ring->buflen, (int)ring->element_len,
  241. (int)ring->head, (int)ring->oldest_tail,
  242. (int)lws_ring_get_count_free_elements(ring), (int)*tail,
  243. (int)lws_ring_get_count_waiting_elements(ring, tail));
  244. }