libwebsockets
Lightweight C library for HTML5 websockets
lws-ring.h
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
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 
80 struct lws_ring;
81 
99 LWS_VISIBLE LWS_EXTERN struct lws_ring *
100 lws_ring_create(size_t element_len, size_t count,
101  void (*destroy_element)(void *element));
102 
110 LWS_VISIBLE LWS_EXTERN void
111 lws_ring_destroy(struct lws_ring *ring);
112 
121 LWS_VISIBLE LWS_EXTERN size_t
122 lws_ring_get_count_free_elements(struct lws_ring *ring);
123 
133 LWS_VISIBLE LWS_EXTERN size_t
134 lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail);
135 
146 LWS_VISIBLE LWS_EXTERN size_t
147 lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count);
148 
170 LWS_VISIBLE LWS_EXTERN size_t
171 lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
172  size_t max_count);
173 
190 LWS_VISIBLE LWS_EXTERN const void *
191 lws_ring_get_element(struct lws_ring *ring, uint32_t *tail);
192 
203 LWS_VISIBLE LWS_EXTERN void
204 lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail);
205 
214 LWS_VISIBLE LWS_EXTERN uint32_t
215 lws_ring_get_oldest_tail(struct lws_ring *ring);
216 
235 LWS_VISIBLE LWS_EXTERN int
236 lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
237  size_t *bytes);
238 
245 LWS_VISIBLE LWS_EXTERN void
246 lws_ring_bump_head(struct lws_ring *ring, size_t bytes);
247 
248 LWS_VISIBLE LWS_EXTERN void
249 lws_ring_dump(struct lws_ring *ring, uint32_t *tail);
250 
251 /*
252  * This is a helper that combines the common pattern of needing to consume
253  * some ringbuffer elements, move the consumer tail on, and check if that
254  * has moved any ringbuffer elements out of scope, because it was the last
255  * consumer that had not already consumed them.
256  *
257  * Elements that go out of scope because the oldest tail is now after them
258  * get garbage-collected by calling the destroy_element callback on them
259  * defined when the ringbuffer was created.
260  */
261 
262 #define lws_ring_consume_and_update_oldest_tail(\
263  ___ring, /* the lws_ring object */ \
264  ___type, /* type of objects with tails */ \
265  ___ptail, /* ptr to tail of obj with tail doing consuming */ \
266  ___count, /* count of payload objects being consumed */ \
267  ___list_head, /* head of list of objects with tails */ \
268  ___mtail, /* member name of tail in ___type */ \
269  ___mlist /* member name of next list member ptr in ___type */ \
270  ) { \
271  int ___n, ___m; \
272  \
273  ___n = lws_ring_get_oldest_tail(___ring) == *(___ptail); \
274  lws_ring_consume(___ring, ___ptail, NULL, ___count); \
275  if (___n) { \
276  uint32_t ___oldest; \
277  ___n = 0; \
278  ___oldest = *(___ptail); \
279  lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
280  ___m = (int)lws_ring_get_count_waiting_elements( \
281  ___ring, &(*___ppss)->___mtail); \
282  if (___m >= ___n) { \
283  ___n = ___m; \
284  ___oldest = (*___ppss)->___mtail; \
285  } \
286  } lws_end_foreach_llp(___ppss, ___mlist); \
287  \
288  lws_ring_update_oldest_tail(___ring, ___oldest); \
289  } \
290 }
291 
292 /*
293  * This does the same as the lws_ring_consume_and_update_oldest_tail()
294  * helper, but for the simpler case there is only one consumer, so one
295  * tail, and that tail is always the oldest tail.
296  */
297 
298 #define lws_ring_consume_single_tail(\
299  ___ring, /* the lws_ring object */ \
300  ___ptail, /* ptr to tail of obj with tail doing consuming */ \
301  ___count /* count of payload objects being consumed */ \
302  ) { \
303  lws_ring_consume(___ring, ___ptail, NULL, ___count); \
304  lws_ring_update_oldest_tail(___ring, *(___ptail)); \
305 }
LWS_VISIBLE LWS_EXTERN size_t lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
LWS_VISIBLE LWS_EXTERN void lws_ring_destroy(struct lws_ring *ring)
LWS_VISIBLE LWS_EXTERN size_t lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest, size_t max_count)
LWS_VISIBLE LWS_EXTERN uint32_t lws_ring_get_oldest_tail(struct lws_ring *ring)
LWS_VISIBLE LWS_EXTERN size_t lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)
LWS_VISIBLE LWS_EXTERN size_t lws_ring_get_count_free_elements(struct lws_ring *ring)
LWS_VISIBLE LWS_EXTERN int lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start, size_t *bytes)
LWS_VISIBLE LWS_EXTERN void lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
LWS_VISIBLE LWS_EXTERN struct lws_ring * lws_ring_create(size_t element_len, size_t count, void(*destroy_element)(void *element))
LWS_VISIBLE LWS_EXTERN void lws_ring_bump_head(struct lws_ring *ring, size_t bytes)
LWS_VISIBLE LWS_EXTERN const void * lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)