Path: blob/master/Utilities/cmliblzma/liblzma/common/outqueue.h
3153 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file outqueue.h5/// \brief Output queue handling in multithreaded coding6//7// Author: Lasse Collin8//9///////////////////////////////////////////////////////////////////////////////1011#ifndef LZMA_OUTQUEUE_H12#define LZMA_OUTQUEUE_H1314#include "common.h"151617/// Output buffer for a single thread18typedef struct lzma_outbuf_s lzma_outbuf;19struct lzma_outbuf_s {20/// Pointer to the next buffer. This is used for the cached buffers.21/// The worker thread must not modify this.22lzma_outbuf *next;2324/// This initialized by lzma_outq_get_buf() and25/// is used by lzma_outq_enable_partial_output().26/// The worker thread must not modify this.27void *worker;2829/// Amount of memory allocated for buf[].30/// The worker thread must not modify this.31size_t allocated;3233/// Writing position in the worker thread or, in other words, the34/// amount of finished data written to buf[] which can be copied out35///36/// \note This is read by another thread and thus access37/// to this variable needs a mutex.38size_t pos;3940/// Decompression: Position in the input buffer in the worker thread41/// that matches the output "pos" above. This is used to detect if42/// more output might be possible from the worker thread: if it has43/// consumed all its input, then more output isn't possible.44///45/// \note This is read by another thread and thus access46/// to this variable needs a mutex.47size_t decoder_in_pos;4849/// True when no more data will be written into this buffer.50///51/// \note This is read by another thread and thus access52/// to this variable needs a mutex.53bool finished;5455/// Return value for lzma_outq_read() when the last byte from56/// a finished buffer has been read. Defaults to LZMA_STREAM_END.57/// This must *not* be LZMA_OK. The idea is to allow a decoder to58/// pass an error code to the main thread, setting the code here59/// together with finished = true.60lzma_ret finish_ret;6162/// Additional size information. lzma_outq_read() may read these63/// when "finished" is true.64lzma_vli unpadded_size;65lzma_vli uncompressed_size;6667/// Buffer of "allocated" bytes68uint8_t buf[];69};707172typedef struct {73/// Linked list of buffers in use. The next output byte will be74/// read from the head and buffers for the next thread will be75/// appended to the tail. tail->next is always NULL.76lzma_outbuf *head;77lzma_outbuf *tail;7879/// Number of bytes read from head->buf[] in lzma_outq_read()80size_t read_pos;8182/// Linked list of allocated buffers that aren't currently used.83/// This way buffers of similar size can be reused and don't84/// need to be reallocated every time. For simplicity, all85/// cached buffers in the list have the same allocated size.86lzma_outbuf *cache;8788/// Total amount of memory allocated for buffers89uint64_t mem_allocated;9091/// Amount of memory used by the buffers that are in use in92/// the head...tail linked list.93uint64_t mem_in_use;9495/// Number of buffers in use in the head...tail list. If and only if96/// this is zero, the pointers head and tail above are NULL.97uint32_t bufs_in_use;9899/// Number of buffers allocated (in use + cached)100uint32_t bufs_allocated;101102/// Maximum allowed number of allocated buffers103uint32_t bufs_limit;104} lzma_outq;105106107/**108* \brief Calculate the memory usage of an output queue109*110* \return Approximate memory usage in bytes or UINT64_MAX on error.111*/112extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);113114115/// \brief Initialize an output queue116///117/// \param outq Pointer to an output queue. Before calling118/// this function the first time, *outq should119/// have been zeroed with memzero() so that this120/// function knows that there are no previous121/// allocations to free.122/// \param allocator Pointer to allocator or NULL123/// \param threads Number of buffers that may be in use124/// concurrently. Note that more than this number125/// of buffers may actually get allocated to126/// improve performance when buffers finish127/// out of order. The actual maximum number of128/// allocated buffers is derived from the number129/// of threads.130///131/// \return - LZMA_OK132/// - LZMA_MEM_ERROR133///134extern lzma_ret lzma_outq_init(lzma_outq *outq,135const lzma_allocator *allocator, uint32_t threads);136137138/// \brief Free the memory associated with the output queue139extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);140141142/// \brief Free all cached buffers that consume memory but aren't in use143extern void lzma_outq_clear_cache(144lzma_outq *outq, const lzma_allocator *allocator);145146147/// \brief Like lzma_outq_clear_cache() but might keep one buffer148///149/// One buffer is not freed if its size is equal to keep_size.150/// This is useful if the caller knows that it will soon need a buffer of151/// keep_size bytes. This way it won't be freed and immediately reallocated.152extern void lzma_outq_clear_cache2(153lzma_outq *outq, const lzma_allocator *allocator,154size_t keep_size);155156157/// \brief Preallocate a new buffer into cache158///159/// Splitting the buffer allocation into a separate function makes it160/// possible to ensure that way lzma_outq_get_buf() cannot fail.161/// If the preallocated buffer isn't actually used (for example, some162/// other error occurs), the caller has to do nothing as the buffer will163/// be used later or cleared from the cache when not needed.164///165/// \return LZMA_OK on success, LZMA_MEM_ERROR if allocation fails166///167extern lzma_ret lzma_outq_prealloc_buf(168lzma_outq *outq, const lzma_allocator *allocator, size_t size);169170171/// \brief Get a new buffer172///173/// lzma_outq_prealloc_buf() must be used to ensure that there is a buffer174/// available before calling lzma_outq_get_buf().175///176extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq, void *worker);177178179/// \brief Test if there is data ready to be read180///181/// Call to this function must be protected with the same mutex that182/// is used to protect lzma_outbuf.finished.183///184extern bool lzma_outq_is_readable(const lzma_outq *outq);185186187/// \brief Read finished data188///189/// \param outq Pointer to an output queue190/// \param out Beginning of the output buffer191/// \param out_pos The next byte will be written to192/// out[*out_pos].193/// \param out_size Size of the out buffer; the first byte into194/// which no data is written to is out[out_size].195/// \param unpadded_size Unpadded Size from the Block encoder196/// \param uncompressed_size Uncompressed Size from the Block encoder197///198/// \return - LZMA: All OK. Either no data was available or the buffer199/// being read didn't become empty yet.200/// - LZMA_STREAM_END: The buffer being read was finished.201/// *unpadded_size and *uncompressed_size were set if they202/// were not NULL.203///204/// \note This reads lzma_outbuf.finished and .pos variables and thus205/// calls to this function need to be protected with a mutex.206///207extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,208const lzma_allocator *restrict allocator,209uint8_t *restrict out, size_t *restrict out_pos,210size_t out_size, lzma_vli *restrict unpadded_size,211lzma_vli *restrict uncompressed_size);212213214/// \brief Enable partial output from a worker thread215///216/// If the buffer at the head of the output queue isn't finished,217/// this will call enable_partial_output on the worker associated with218/// that output buffer.219///220/// \note This reads a lzma_outbuf.finished variable and thus221/// calls to this function need to be protected with a mutex.222///223extern void lzma_outq_enable_partial_output(lzma_outq *outq,224void (*enable_partial_output)(void *worker));225226227/// \brief Test if there is at least one buffer free228///229/// This must be used before getting a new buffer with lzma_outq_get_buf().230///231static inline bool232lzma_outq_has_buf(const lzma_outq *outq)233{234return outq->bufs_in_use < outq->bufs_limit;235}236237238/// \brief Test if the queue is completely empty239static inline bool240lzma_outq_is_empty(const lzma_outq *outq)241{242return outq->bufs_in_use == 0;243}244245246/// \brief Get the amount of memory needed for a single lzma_outbuf247///248/// \note Caller must check that the argument is significantly less249/// than SIZE_MAX to avoid an integer overflow!250static inline uint64_t251lzma_outq_outbuf_memusage(size_t buf_size)252{253assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));254return sizeof(lzma_outbuf) + buf_size;255}256257#endif258259260