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