| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include <libwebsockets.h>
- #include "private-lib-core.h"
- struct lws_ring *
- lws_ring_create(size_t element_len, size_t count,
- void (*destroy_element)(void *))
- {
- struct lws_ring *ring = lws_malloc(sizeof(*ring), "ring create");
- if (!ring)
- return NULL;
- ring->buflen = (uint32_t)(count * element_len);
- ring->element_len = (uint32_t)element_len;
- ring->head = 0;
- ring->oldest_tail = 0;
- ring->destroy_element = destroy_element;
- ring->buf = lws_malloc(ring->buflen, "ring buf");
- if (!ring->buf) {
- lws_free(ring);
- return NULL;
- }
- return ring;
- }
- void
- lws_ring_destroy(struct lws_ring *ring)
- {
- if (ring->destroy_element)
- while (ring->oldest_tail != ring->head) {
- ring->destroy_element((uint8_t *)ring->buf +
- ring->oldest_tail);
- ring->oldest_tail =
- (ring->oldest_tail + ring->element_len) %
- ring->buflen;
- }
- if (ring->buf)
- lws_free_set_NULL(ring->buf);
- lws_free(ring);
- }
- size_t
- lws_ring_get_count_free_elements(struct lws_ring *ring)
- {
- int f;
- /*
- * possible ringbuf patterns
- *
- * h == t
- * |--------t***h---|
- * |**h-----------t*|
- * |t**************h|
- * |*****ht*********|
- */
- if (ring->head == ring->oldest_tail)
- f = ring->buflen - ring->element_len;
- else
- if (ring->head < ring->oldest_tail)
- f = (ring->oldest_tail - ring->head) -
- ring->element_len;
- else
- f = (ring->buflen - ring->head) + ring->oldest_tail -
- ring->element_len;
- if (f < 2)
- return 0;
- return f / ring->element_len;
- }
- size_t
- lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)
- { int f;
- if (!tail)
- tail = &ring->oldest_tail;
- /*
- * possible ringbuf patterns
- *
- * h == t
- * |--------t***h---|
- * |**h-----------t*|
- * |t**************h|
- * |*****ht*********|
- */
- if (ring->head == *tail)
- f = 0;
- else
- if (ring->head > *tail)
- f = (ring->head - *tail);
- else
- f = (ring->buflen - *tail) + ring->head;
- return f / ring->element_len;
- }
- int
- lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
- size_t *bytes)
- {
- int n;
- /* n is how many bytes the whole fifo can take */
- n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len);
- if (!n)
- return 1;
- if (ring->head + n > ring->buflen) {
- *start = (void *)(((uint8_t *)ring->buf) + ring->head);
- *bytes = ring->buflen - ring->head;
- return 0;
- }
- *start = (void *)(((uint8_t *)ring->buf) + ring->head);
- *bytes = n;
- return 0;
- }
- void
- lws_ring_bump_head(struct lws_ring *ring, size_t bytes)
- {
- ring->head = (ring->head + (uint32_t)bytes) % ring->buflen;
- }
- size_t
- lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
- {
- const uint8_t *osrc = src;
- int m, n;
- /* n is how many bytes the whole fifo can take */
- n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len);
- /* restrict n to how much we want to insert */
- if ((uint32_t)n > max_count * ring->element_len)
- n = (int)(max_count * ring->element_len);
- /*
- * n is legal to insert, but as an optimization we can cut the
- * insert into one or two memcpys, depending on if it wraps
- */
- if (ring->head + n > ring->buflen) {
- /*
- * He does wrap. The first memcpy should take us up to
- * the end of the buffer
- */
- m = ring->buflen - ring->head;
- memcpy(((uint8_t *)ring->buf) + ring->head, src, m);
- /* we know it will wrap exactly back to zero */
- ring->head = 0;
- /* adapt the second memcpy for what we already did */
- src = ((uint8_t *)src) + m;
- n -= m;
- }
- memcpy(((uint8_t *)ring->buf) + ring->head, src, n);
- ring->head = (ring->head + n) % ring->buflen;
- return (((uint8_t *)src + n) - osrc) / ring->element_len;
- }
- size_t
- lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
- size_t max_count)
- {
- uint8_t *odest = dest;
- void *orig_tail = tail;
- uint32_t fake_tail;
- int m, n;
- if (!tail) {
- fake_tail = ring->oldest_tail;
- tail = &fake_tail;
- }
- /* n is how many bytes the whole fifo has for us */
- n = (int)(lws_ring_get_count_waiting_elements(ring, tail) *
- ring->element_len);
- /* restrict n to how much we want to insert */
- if ((size_t)n > max_count * ring->element_len)
- n = (int)(max_count * ring->element_len);
- if (!dest) {
- *tail = ((*tail) + n) % ring->buflen;
- if (!orig_tail) /* single tail */
- lws_ring_update_oldest_tail(ring, *tail);
- return n / ring->element_len;
- }
- if (*tail + n > ring->buflen) {
- /*
- * He does wrap. The first memcpy should take us up to
- * the end of the buffer
- */
- m = ring->buflen - *tail;
- memcpy(dest, ((uint8_t *)ring->buf) + *tail, m);
- /* we know it will wrap exactly back to zero */
- *tail = 0;
- /* adapt the second memcpy for what we already did */
- dest = ((uint8_t *)dest) + m;
- n -= m;
- }
- memcpy(dest, ((uint8_t *)ring->buf) + *tail, n);
- *tail = ((*tail) + n) % ring->buflen;
- if (!orig_tail) /* single tail */
- lws_ring_update_oldest_tail(ring, *tail);
- return (((uint8_t *)dest + n) - odest) / ring->element_len;
- }
- const void *
- lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)
- {
- if (!tail)
- tail = &ring->oldest_tail;
- if (*tail == ring->head)
- return NULL;
- return ((uint8_t *)ring->buf) + *tail;
- }
- void
- lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
- {
- if (!ring->destroy_element) {
- ring->oldest_tail = tail;
- return;
- }
- while (ring->oldest_tail != tail) {
- ring->destroy_element((uint8_t *)ring->buf + ring->oldest_tail);
- ring->oldest_tail = (ring->oldest_tail + ring->element_len) %
- ring->buflen;
- }
- }
- uint32_t
- lws_ring_get_oldest_tail(struct lws_ring *ring)
- {
- return ring->oldest_tail;
- }
- void
- lws_ring_dump(struct lws_ring *ring, uint32_t *tail)
- {
- if (tail == NULL)
- tail = &ring->oldest_tail;
- lwsl_notice("ring %p: buflen %u, elem_len %u, head %u, oldest_tail %u\n"
- " free_elems: %u; for tail %u, waiting elements: %u\n",
- ring, (int)ring->buflen, (int)ring->element_len,
- (int)ring->head, (int)ring->oldest_tail,
- (int)lws_ring_get_count_free_elements(ring), (int)*tail,
- (int)lws_ring_get_count_waiting_elements(ring, tail));
- }
|