Project homepage Mailing List  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1638755740, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"", "f":3, "items": [ {"schema":"libjg2-1", "cid":"5a37b1a4088fca33731adecfd91f0c38", "oid":{ "oid": "e1a73c42096a9f94617a25440501d7adc4abbd9f", "alias": [ "refs/heads/main"]},"blobname": "include/libwebsockets/lws-ring.h", "blob": "/*\n * libwebsockets - small server side websockets and web server implementation\n *\n * Copyright (C) 2010 - 2019 Andy Green \\u003e\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \u0022Software\u0022), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/** \u005cdefgroup lws_ring LWS Ringbuffer APIs\n * ##lws_ring: generic ringbuffer struct\n *\n * Provides an abstract ringbuffer api supporting one head and one or an\n * unlimited number of tails.\n *\n * All of the members are opaque and manipulated by lws_ring_...() apis.\n *\n * The lws_ring and its buffer is allocated at runtime on the heap, using\n *\n * - lws_ring_create()\n * - lws_ring_destroy()\n *\n * It may contain any type, the size of the \u0022element\u0022 stored in the ring\n * buffer and the number of elements is given at creation time.\n *\n * When you create the ringbuffer, you can optionally provide an element\n * destroy callback that frees any allocations inside the element. This is then\n * automatically called for elements with no tail behind them, ie, elements\n * which don't have any pending consumer are auto-freed.\n *\n * Whole elements may be inserted into the ringbuffer and removed from it, using\n *\n * - lws_ring_insert()\n * - lws_ring_consume()\n *\n * You can find out how many whole elements are free or waiting using\n *\n * - lws_ring_get_count_free_elements()\n * - lws_ring_get_count_waiting_elements()\n *\n * In addition there are special purpose optional byte-centric apis\n *\n * - lws_ring_next_linear_insert_range()\n * - lws_ring_bump_head()\n *\n * which let you, eg, read() directly into the ringbuffer without needing\n * an intermediate bounce buffer.\n *\n * The accessors understand that the ring wraps, and optimizes insertion and\n * consumption into one or two memcpy()s depending on if the head or tail\n * wraps.\n *\n * lws_ring only supports a single head, but optionally multiple tails with\n * an API to inform it when the \u0022oldest\u0022 tail has moved on. You can give\n * NULL where-ever an api asks for a tail pointer, and it will use an internal\n * single tail pointer for convenience.\n *\n * The \u0022oldest tail\u0022, which is the only tail if you give it NULL instead of\n * some other tail, is used to track which elements in the ringbuffer are\n * still unread by anyone.\n *\n * - lws_ring_update_oldest_tail()\n */\n///@{\nstruct lws_ring;\n\n/**\n * lws_ring_create(): create a new ringbuffer\n *\n * \u005cparam element_len: the size in bytes of one element in the ringbuffer\n * \u005cparam count: the number of elements the ringbuffer can contain\n * \u005cparam destroy_element: NULL, or callback to be called for each element\n *\t\t\t that is removed from the ringbuffer due to the\n *\t\t\t oldest tail moving beyond it\n *\n * Creates the ringbuffer and allocates the storage. Returns the new\n * lws_ring *, or NULL if the allocation failed.\n *\n * If non-NULL, destroy_element will get called back for every element that is\n * retired from the ringbuffer after the oldest tail has gone past it, and for\n * any element still left in the ringbuffer when it is destroyed. It replaces\n * all other element destruction code in your user code.\n */\nLWS_VISIBLE LWS_EXTERN struct lws_ring *\nlws_ring_create(size_t element_len, size_t count,\n\t\tvoid (*destroy_element)(void *element));\n\n/**\n * lws_ring_destroy(): destroy a previously created ringbuffer\n *\n * \u005cparam ring: the struct lws_ring to destroy\n *\n * Destroys the ringbuffer allocation and the struct lws_ring itself.\n */\nLWS_VISIBLE LWS_EXTERN void\nlws_ring_destroy(struct lws_ring *ring);\n\n/**\n * lws_ring_get_count_free_elements(): return how many elements can fit\n *\t\t\t\t in the free space\n *\n * \u005cparam ring: the struct lws_ring to report on\n *\n * Returns how much room is left in the ringbuffer for whole element insertion.\n */\nLWS_VISIBLE LWS_EXTERN size_t\nlws_ring_get_count_free_elements(struct lws_ring *ring);\n\n/**\n * lws_ring_get_count_waiting_elements(): return how many elements can be consumed\n *\n * \u005cparam ring: the struct lws_ring to report on\n * \u005cparam tail: a pointer to the tail struct to use, or NULL for single tail\n *\n * Returns how many elements are waiting to be consumed from the perspective\n * of the tail pointer given.\n */\nLWS_VISIBLE LWS_EXTERN size_t\nlws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail);\n\n/**\n * lws_ring_insert(): attempt to insert up to max_count elements from src\n *\n * \u005cparam ring: the struct lws_ring to report on\n * \u005cparam src: the array of elements to be inserted\n * \u005cparam max_count: the number of available elements at src\n *\n * Attempts to insert as many of the elements at src as possible, up to the\n * maximum max_count. Returns the number of elements actually inserted.\n */\nLWS_VISIBLE LWS_EXTERN size_t\nlws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count);\n\n/**\n * lws_ring_consume(): attempt to copy out and remove up to max_count elements\n *\t\t to src\n *\n * \u005cparam ring: the struct lws_ring to report on\n * \u005cparam tail: a pointer to the tail struct to use, or NULL for single tail\n * \u005cparam dest: the array of elements to be inserted. or NULL for no copy\n * \u005cparam max_count: the number of available elements at src\n *\n * Attempts to copy out as many waiting elements as possible into dest, from\n * the perspective of the given tail, up to max_count. If dest is NULL, the\n * copying out is not done but the elements are logically consumed as usual.\n * NULL dest is useful in combination with lws_ring_get_element(), where you\n * can use the element direct from the ringbuffer and then call this with NULL\n * dest to logically consume it.\n *\n * Increments the tail position according to how many elements could be\n * consumed.\n *\n * Returns the number of elements consumed.\n */\nLWS_VISIBLE LWS_EXTERN size_t\nlws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,\n\t\t size_t max_count);\n\n/**\n * lws_ring_get_element(): get a pointer to the next waiting element for tail\n *\n * \u005cparam ring: the struct lws_ring to report on\n * \u005cparam tail: a pointer to the tail struct to use, or NULL for single tail\n *\n * Points to the next element that tail would consume, directly in the\n * ringbuffer. This lets you write() or otherwise use the element without\n * having to copy it out somewhere first.\n *\n * After calling this, you must call lws_ring_consume(ring, \u0026tail, NULL, 1)\n * which will logically consume the element you used up and increment your\n * tail (tail may also be NULL there if you use a single tail).\n *\n * Returns NULL if no waiting element, or a const void * pointing to it.\n */\nLWS_VISIBLE LWS_EXTERN const void *\nlws_ring_get_element(struct lws_ring *ring, uint32_t *tail);\n\n/**\n * lws_ring_update_oldest_tail(): free up elements older than tail for reuse\n *\n * \u005cparam ring: the struct lws_ring to report on\n * \u005cparam tail: a pointer to the tail struct to use, or NULL for single tail\n *\n * If you are using multiple tails, you must use this API to inform the\n * lws_ring when none of the tails still need elements in the fifo any more,\n * by updating it when the \u0022oldest\u0022 tail has moved on.\n */\nLWS_VISIBLE LWS_EXTERN void\nlws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail);\n\n/**\n * lws_ring_get_oldest_tail(): get current oldest available data index\n *\n * \u005cparam ring: the struct lws_ring to report on\n *\n * If you are initializing a new ringbuffer consumer, you can set its tail to\n * this to start it from the oldest ringbuffer entry still available.\n */\nLWS_VISIBLE LWS_EXTERN uint32_t\nlws_ring_get_oldest_tail(struct lws_ring *ring);\n\n/**\n * lws_ring_next_linear_insert_range(): used to write directly into the ring\n *\n * \u005cparam ring: the struct lws_ring to report on\n * \u005cparam start: pointer to a void * set to the start of the next ringbuffer area\n * \u005cparam bytes: pointer to a size_t set to the max length you may use from *start\n *\n * This provides a low-level, bytewise access directly into the ringbuffer\n * allowing direct insertion of data without having to use a bounce buffer.\n *\n * The api reports the position and length of the next linear range that can\n * be written in the ringbuffer, ie, up to the point it would wrap, and sets\n * *start and *bytes accordingly. You can then, eg, directly read() into\n * *start for up to *bytes, and use lws_ring_bump_head() to update the lws_ring\n * with what you have done.\n *\n * Returns nonzero if no insertion is currently possible.\n */\nLWS_VISIBLE LWS_EXTERN int\nlws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,\n\t\t\t\t size_t *bytes);\n\n/**\n * lws_ring_bump_head(): used to write directly into the ring\n *\n * \u005cparam ring: the struct lws_ring to operate on\n * \u005cparam bytes: the number of bytes you inserted at the current head\n */\nLWS_VISIBLE LWS_EXTERN void\nlws_ring_bump_head(struct lws_ring *ring, size_t bytes);\n\nLWS_VISIBLE LWS_EXTERN void\nlws_ring_dump(struct lws_ring *ring, uint32_t *tail);\n\n/*\n * This is a helper that combines the common pattern of needing to consume\n * some ringbuffer elements, move the consumer tail on, and check if that\n * has moved any ringbuffer elements out of scope, because it was the last\n * consumer that had not already consumed them.\n *\n * Elements that go out of scope because the oldest tail is now after them\n * get garbage-collected by calling the destroy_element callback on them\n * defined when the ringbuffer was created.\n */\n\n#define lws_ring_consume_and_update_oldest_tail(\u005c\n\t\t___ring, /* the lws_ring object */ \u005c\n\t\t___type, /* type of objects with tails */ \u005c\n\t\t___ptail, /* ptr to tail of obj with tail doing consuming */ \u005c\n\t\t___count, /* count of payload objects being consumed */ \u005c\n\t\t___list_head,\t/* head of list of objects with tails */ \u005c\n\t\t___mtail, /* member name of tail in ___type */ \u005c\n\t\t___mlist /* member name of next list member ptr in ___type */ \u005c\n\t) { \u005c\n\t\tint ___n, ___m; \u005c\n\t\u005c\n\t___n \u003d lws_ring_get_oldest_tail(___ring) \u003d\u003d *(___ptail); \u005c\n\tlws_ring_consume(___ring, ___ptail, NULL, ___count); \u005c\n\tif (___n) { \u005c\n\t\tuint32_t ___oldest; \u005c\n\t\t___n \u003d 0; \u005c\n\t\t___oldest \u003d *(___ptail); \u005c\n\t\tlws_start_foreach_llp(___type **, ___ppss, ___list_head) { \u005c\n\t\t\t___m \u003d (int)lws_ring_get_count_waiting_elements( \u005c\n\t\t\t\t\t___ring, \u0026(*___ppss)-\u003e___mtail); \u005c\n\t\t\tif (___m \u003e\u003d ___n) { \u005c\n\t\t\t\t___n \u003d ___m; \u005c\n\t\t\t\t___oldest \u003d (*___ppss)-\u003e___mtail; \u005c\n\t\t\t} \u005c\n\t\t} lws_end_foreach_llp(___ppss, ___mlist); \u005c\n\t\u005c\n\t\tlws_ring_update_oldest_tail(___ring, ___oldest); \u005c\n\t} \u005c\n}\n\n/*\n * This does the same as the lws_ring_consume_and_update_oldest_tail()\n * helper, but for the simpler case there is only one consumer, so one\n * tail, and that tail is always the oldest tail.\n */\n\n#define lws_ring_consume_single_tail(\u005c\n\t\t___ring, /* the lws_ring object */ \u005c\n\t\t___ptail, /* ptr to tail of obj with tail doing consuming */ \u005c\n\t\t___count /* count of payload objects being consumed */ \u005c\n\t) { \u005c\n\tlws_ring_consume(___ring, ___ptail, NULL, ___count); \u005c\n\tlws_ring_update_oldest_tail(___ring, *(___ptail)); \u005c\n}\n///@}\n","s":{"c":1638723141,"u": 560}} ],"g": 1248,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}