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