libwebsockets
Lightweight C library for HTML5 websockets
LWS Ringbuffer APIs

Macros

#define lws_ring_consume_and_update_oldest_tail(___ring, ___type, ___ptail, ___count, ___list_head, ___mtail, ___mlist)
 
#define lws_ring_consume_single_tail(___ring, ___ptail, ___count)
 

Functions

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_destroy (struct lws_ring *ring)
 
LWS_VISIBLE LWS_EXTERN size_t lws_ring_get_count_free_elements (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_insert (struct lws_ring *ring, const void *src, size_t max_count)
 
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 const void * lws_ring_get_element (struct lws_ring *ring, uint32_t *tail)
 
LWS_VISIBLE LWS_EXTERN void lws_ring_update_oldest_tail (struct lws_ring *ring, uint32_t tail)
 
LWS_VISIBLE LWS_EXTERN uint32_t lws_ring_get_oldest_tail (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_bump_head (struct lws_ring *ring, size_t bytes)
 
LWS_VISIBLE LWS_EXTERN void lws_ring_dump (struct lws_ring *ring, uint32_t *tail)
 

Detailed Description

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

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

You can find out how many whole elements are free or waiting using

In addition there are special purpose optional byte-centric apis

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.

Macro Definition Documentation

◆ lws_ring_consume_and_update_oldest_tail

#define lws_ring_consume_and_update_oldest_tail (   ___ring,
  ___type,
  ___ptail,
  ___count,
  ___list_head,
  ___mtail,
  ___mlist 
)

#include <include/libwebsockets/lws-ring.h>

Value:
{ \
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) { \
___ring, &(*___ppss)->___mtail); \
if (___m >= ___n) { \
___n = ___m; \
___oldest = (*___ppss)->___mtail; \
} \
} lws_end_foreach_llp(___ppss, ___mlist); \
lws_ring_update_oldest_tail(___ring, ___oldest); \
} \
}

◆ lws_ring_consume_single_tail

#define lws_ring_consume_single_tail (   ___ring,
  ___ptail,
  ___count 
)

#include <include/libwebsockets/lws-ring.h>

Value:
{ \
lws_ring_consume(___ring, ___ptail, NULL, ___count); \
lws_ring_update_oldest_tail(___ring, *(___ptail)); \
}

Function Documentation

◆ lws_ring_bump_head()

LWS_VISIBLE LWS_EXTERN void lws_ring_bump_head ( struct lws_ring *  ring,
size_t  bytes 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_bump_head(): used to write directly into the ring

Parameters
ringthe struct lws_ring to operate on
bytesthe number of bytes you inserted at the current head

◆ lws_ring_consume()

LWS_VISIBLE LWS_EXTERN size_t lws_ring_consume ( struct lws_ring *  ring,
uint32_t *  tail,
void *  dest,
size_t  max_count 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_consume(): attempt to copy out and remove up to max_count elements to src

Parameters
ringthe struct lws_ring to report on
taila pointer to the tail struct to use, or NULL for single tail
destthe array of elements to be inserted. or NULL for no copy
max_countthe 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_ring_create()

LWS_VISIBLE LWS_EXTERN struct lws_ring* lws_ring_create ( size_t  element_len,
size_t  count,
void(*)(void *element)  destroy_element 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_create(): create a new ringbuffer

Parameters
element_lenthe size in bytes of one element in the ringbuffer
countthe number of elements the ringbuffer can contain
destroy_elementNULL, 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_ring_destroy()

LWS_VISIBLE LWS_EXTERN void lws_ring_destroy ( struct lws_ring *  ring)

#include <include/libwebsockets/lws-ring.h>

lws_ring_destroy(): destroy a previously created ringbuffer

Parameters
ringthe struct lws_ring to destroy

Destroys the ringbuffer allocation and the struct lws_ring itself.

◆ lws_ring_get_count_free_elements()

LWS_VISIBLE LWS_EXTERN size_t lws_ring_get_count_free_elements ( struct lws_ring *  ring)

#include <include/libwebsockets/lws-ring.h>

lws_ring_get_count_free_elements(): return how many elements can fit in the free space

Parameters
ringthe struct lws_ring to report on

Returns how much room is left in the ringbuffer for whole element insertion.

◆ lws_ring_get_count_waiting_elements()

LWS_VISIBLE LWS_EXTERN size_t lws_ring_get_count_waiting_elements ( struct lws_ring *  ring,
uint32_t *  tail 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_get_count_waiting_elements(): return how many elements can be consumed

Parameters
ringthe struct lws_ring to report on
taila 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_ring_get_element()

LWS_VISIBLE LWS_EXTERN const void* lws_ring_get_element ( struct lws_ring *  ring,
uint32_t *  tail 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_get_element(): get a pointer to the next waiting element for tail

Parameters
ringthe struct lws_ring to report on
taila 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_ring_get_oldest_tail()

LWS_VISIBLE LWS_EXTERN uint32_t lws_ring_get_oldest_tail ( struct lws_ring *  ring)

#include <include/libwebsockets/lws-ring.h>

lws_ring_get_oldest_tail(): get current oldest available data index

Parameters
ringthe 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_ring_insert()

LWS_VISIBLE LWS_EXTERN size_t lws_ring_insert ( struct lws_ring *  ring,
const void *  src,
size_t  max_count 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_insert(): attempt to insert up to max_count elements from src

Parameters
ringthe struct lws_ring to report on
srcthe array of elements to be inserted
max_countthe 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_ring_next_linear_insert_range()

LWS_VISIBLE LWS_EXTERN int lws_ring_next_linear_insert_range ( struct lws_ring *  ring,
void **  start,
size_t *  bytes 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_next_linear_insert_range(): used to write directly into the ring

Parameters
ringthe struct lws_ring to report on
startpointer to a void * set to the start of the next ringbuffer area
bytespointer 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_ring_update_oldest_tail()

LWS_VISIBLE LWS_EXTERN void lws_ring_update_oldest_tail ( struct lws_ring *  ring,
uint32_t  tail 
)

#include <include/libwebsockets/lws-ring.h>

lws_ring_update_oldest_tail(): free up elements older than tail for reuse

Parameters
ringthe struct lws_ring to report on
taila 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_ring_update_oldest_tail
LWS_VISIBLE LWS_EXTERN void lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
lws_ring_get_oldest_tail
LWS_VISIBLE LWS_EXTERN uint32_t lws_ring_get_oldest_tail(struct lws_ring *ring)
lws_ring_get_count_waiting_elements
LWS_VISIBLE LWS_EXTERN size_t lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)