| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 | 
							- /*
 
-  * libwebsockets - small server side websockets and web server implementation
 
-  *
 
-  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
 
-  *
 
-  * 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.
 
-  */
 
- /** \defgroup lws_ring LWS Ringbuffer APIs
 
-  * ##lws_ring: generic ringbuffer struct
 
-  *
 
-  * Provides an abstract ringbuffer api supporting one head and one or an
 
-  * unlimited number of tails.
 
-  *
 
-  * All of the members are opaque and manipulated by lws_ring_...() apis.
 
-  *
 
-  * The lws_ring and its buffer is allocated at runtime on the heap, using
 
-  *
 
-  *  - lws_ring_create()
 
-  *  - lws_ring_destroy()
 
-  *
 
-  * It may contain any type, the size of the "element" stored in the ring
 
-  * buffer and the number of elements is given at creation time.
 
-  *
 
-  * When you create the ringbuffer, you can optionally provide an element
 
-  * destroy callback that frees any allocations inside the element.  This is then
 
-  * automatically called for elements with no tail behind them, ie, elements
 
-  * which don't have any pending consumer are auto-freed.
 
-  *
 
-  * Whole elements may be inserted into the ringbuffer and removed from it, using
 
-  *
 
-  *  - lws_ring_insert()
 
-  *  - lws_ring_consume()
 
-  *
 
-  * You can find out how many whole elements are free or waiting using
 
-  *
 
-  *  - lws_ring_get_count_free_elements()
 
-  *  - lws_ring_get_count_waiting_elements()
 
-  *
 
-  * In addition there are special purpose optional byte-centric apis
 
-  *
 
-  *  - lws_ring_next_linear_insert_range()
 
-  *  - lws_ring_bump_head()
 
-  *
 
-  *  which let you, eg, read() directly into the ringbuffer without needing
 
-  *  an intermediate bounce buffer.
 
-  *
 
-  *  The accessors understand that the ring wraps, and optimizes insertion and
 
-  *  consumption into one or two memcpy()s depending on if the head or tail
 
-  *  wraps.
 
-  *
 
-  *  lws_ring only supports a single head, but optionally multiple tails with
 
-  *  an API to inform it when the "oldest" tail has moved on.  You can give
 
-  *  NULL where-ever an api asks for a tail pointer, and it will use an internal
 
-  *  single tail pointer for convenience.
 
-  *
 
-  *  The "oldest tail", which is the only tail if you give it NULL instead of
 
-  *  some other tail, is used to track which elements in the ringbuffer are
 
-  *  still unread by anyone.
 
-  *
 
-  *   - lws_ring_update_oldest_tail()
 
-  */
 
- ///@{
 
- struct lws_ring;
 
- /**
 
-  * lws_ring_create(): create a new ringbuffer
 
-  *
 
-  * \param element_len: the size in bytes of one element in the ringbuffer
 
-  * \param count: the number of elements the ringbuffer can contain
 
-  * \param destroy_element: NULL, or callback to be called for each element
 
-  *			   that is removed from the ringbuffer due to the
 
-  *			   oldest tail moving beyond it
 
-  *
 
-  * Creates the ringbuffer and allocates the storage.  Returns the new
 
-  * lws_ring *, or NULL if the allocation failed.
 
-  *
 
-  * If non-NULL, destroy_element will get called back for every element that is
 
-  * retired from the ringbuffer after the oldest tail has gone past it, and for
 
-  * any element still left in the ringbuffer when it is destroyed.  It replaces
 
-  * all other element destruction code in your user code.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN struct lws_ring *
 
- lws_ring_create(size_t element_len, size_t count,
 
- 		void (*destroy_element)(void *element));
 
- /**
 
-  * lws_ring_destroy():  destroy a previously created ringbuffer
 
-  *
 
-  * \param ring: the struct lws_ring to destroy
 
-  *
 
-  * Destroys the ringbuffer allocation and the struct lws_ring itself.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN void
 
- lws_ring_destroy(struct lws_ring *ring);
 
- /**
 
-  * lws_ring_get_count_free_elements():  return how many elements can fit
 
-  *				      in the free space
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  *
 
-  * Returns how much room is left in the ringbuffer for whole element insertion.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN size_t
 
- lws_ring_get_count_free_elements(struct lws_ring *ring);
 
- /**
 
-  * lws_ring_get_count_waiting_elements():  return how many elements can be consumed
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  * \param tail: a pointer to the tail struct to use, or NULL for single tail
 
-  *
 
-  * Returns how many elements are waiting to be consumed from the perspective
 
-  * of the tail pointer given.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN size_t
 
- lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail);
 
- /**
 
-  * lws_ring_insert():  attempt to insert up to max_count elements from src
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  * \param src: the array of elements to be inserted
 
-  * \param max_count: the number of available elements at src
 
-  *
 
-  * Attempts to insert as many of the elements at src as possible, up to the
 
-  * maximum max_count.  Returns the number of elements actually inserted.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN size_t
 
- lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count);
 
- /**
 
-  * lws_ring_consume():  attempt to copy out and remove up to max_count elements
 
-  *		        to src
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  * \param tail: a pointer to the tail struct to use, or NULL for single tail
 
-  * \param dest: the array of elements to be inserted. or NULL for no copy
 
-  * \param max_count: the number of available elements at src
 
-  *
 
-  * Attempts to copy out as many waiting elements as possible into dest, from
 
-  * the perspective of the given tail, up to max_count.  If dest is NULL, the
 
-  * copying out is not done but the elements are logically consumed as usual.
 
-  * NULL dest is useful in combination with lws_ring_get_element(), where you
 
-  * can use the element direct from the ringbuffer and then call this with NULL
 
-  * dest to logically consume it.
 
-  *
 
-  * Increments the tail position according to how many elements could be
 
-  * consumed.
 
-  *
 
-  * Returns the number of elements consumed.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN size_t
 
- lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
 
- 		 size_t max_count);
 
- /**
 
-  * lws_ring_get_element():  get a pointer to the next waiting element for tail
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  * \param tail: a pointer to the tail struct to use, or NULL for single tail
 
-  *
 
-  * Points to the next element that tail would consume, directly in the
 
-  * ringbuffer.  This lets you write() or otherwise use the element without
 
-  * having to copy it out somewhere first.
 
-  *
 
-  * After calling this, you must call lws_ring_consume(ring, &tail, NULL, 1)
 
-  * which will logically consume the element you used up and increment your
 
-  * tail (tail may also be NULL there if you use a single tail).
 
-  *
 
-  * Returns NULL if no waiting element, or a const void * pointing to it.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN const void *
 
- lws_ring_get_element(struct lws_ring *ring, uint32_t *tail);
 
- /**
 
-  * lws_ring_update_oldest_tail():  free up elements older than tail for reuse
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  * \param tail: a pointer to the tail struct to use, or NULL for single tail
 
-  *
 
-  * If you are using multiple tails, you must use this API to inform the
 
-  * lws_ring when none of the tails still need elements in the fifo any more,
 
-  * by updating it when the "oldest" tail has moved on.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN void
 
- lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail);
 
- /**
 
-  * lws_ring_get_oldest_tail():  get current oldest available data index
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  *
 
-  * If you are initializing a new ringbuffer consumer, you can set its tail to
 
-  * this to start it from the oldest ringbuffer entry still available.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN uint32_t
 
- lws_ring_get_oldest_tail(struct lws_ring *ring);
 
- /**
 
-  * lws_ring_next_linear_insert_range():  used to write directly into the ring
 
-  *
 
-  * \param ring: the struct lws_ring to report on
 
-  * \param start: pointer to a void * set to the start of the next ringbuffer area
 
-  * \param bytes: pointer to a size_t set to the max length you may use from *start
 
-  *
 
-  * This provides a low-level, bytewise access directly into the ringbuffer
 
-  * allowing direct insertion of data without having to use a bounce buffer.
 
-  *
 
-  * The api reports the position and length of the next linear range that can
 
-  * be written in the ringbuffer, ie, up to the point it would wrap, and sets
 
-  * *start and *bytes accordingly.  You can then, eg, directly read() into
 
-  * *start for up to *bytes, and use lws_ring_bump_head() to update the lws_ring
 
-  * with what you have done.
 
-  *
 
-  * Returns nonzero if no insertion is currently possible.
 
-  */
 
- LWS_VISIBLE LWS_EXTERN int
 
- lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
 
- 				  size_t *bytes);
 
- /**
 
-  * lws_ring_bump_head():  used to write directly into the ring
 
-  *
 
-  * \param ring: the struct lws_ring to operate on
 
-  * \param bytes: the number of bytes you inserted at the current head
 
-  */
 
- LWS_VISIBLE LWS_EXTERN void
 
- lws_ring_bump_head(struct lws_ring *ring, size_t bytes);
 
- LWS_VISIBLE LWS_EXTERN void
 
- lws_ring_dump(struct lws_ring *ring, uint32_t *tail);
 
- /*
 
-  * This is a helper that combines the common pattern of needing to consume
 
-  * some ringbuffer elements, move the consumer tail on, and check if that
 
-  * has moved any ringbuffer elements out of scope, because it was the last
 
-  * consumer that had not already consumed them.
 
-  *
 
-  * Elements that go out of scope because the oldest tail is now after them
 
-  * get garbage-collected by calling the destroy_element callback on them
 
-  * defined when the ringbuffer was created.
 
-  */
 
- #define lws_ring_consume_and_update_oldest_tail(\
 
- 		___ring,    /* the lws_ring object */ \
 
- 		___type,    /* type of objects with tails */ \
 
- 		___ptail,   /* ptr to tail of obj with tail doing consuming */ \
 
- 		___count,   /* count of payload objects being consumed */ \
 
- 		___list_head,	/* head of list of objects with tails */ \
 
- 		___mtail,   /* member name of tail in ___type */ \
 
- 		___mlist  /* member name of next list member ptr in ___type */ \
 
- 	) { \
 
- 		int ___n, ___m; \
 
- 	\
 
- 	___n = lws_ring_get_oldest_tail(___ring) == *(___ptail); \
 
- 	lws_ring_consume(___ring, ___ptail, NULL, ___count); \
 
- 	if (___n) { \
 
- 		uint32_t ___oldest; \
 
- 		___n = 0; \
 
- 		___oldest = *(___ptail); \
 
- 		lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
 
- 			___m = (int)lws_ring_get_count_waiting_elements( \
 
- 					___ring, &(*___ppss)->___mtail); \
 
- 			if (___m >= ___n) { \
 
- 				___n = ___m; \
 
- 				___oldest = (*___ppss)->___mtail; \
 
- 			} \
 
- 		} lws_end_foreach_llp(___ppss, ___mlist); \
 
- 	\
 
- 		lws_ring_update_oldest_tail(___ring, ___oldest); \
 
- 	} \
 
- }
 
- /*
 
-  * This does the same as the lws_ring_consume_and_update_oldest_tail()
 
-  * helper, but for the simpler case there is only one consumer, so one
 
-  * tail, and that tail is always the oldest tail.
 
-  */
 
- #define lws_ring_consume_single_tail(\
 
- 		___ring,  /* the lws_ring object */ \
 
- 		___ptail, /* ptr to tail of obj with tail doing consuming */ \
 
- 		___count  /* count of payload objects being consumed */ \
 
- 	) { \
 
- 	lws_ring_consume(___ring, ___ptail, NULL, ___count); \
 
- 	lws_ring_update_oldest_tail(___ring, *(___ptail)); \
 
- }
 
- ///@}
 
 
  |