2011-04-11 22:03:30 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
/// \file outqueue.h
|
|
|
|
/// \brief Output queue handling in multithreaded coding
|
|
|
|
//
|
|
|
|
// Author: Lasse Collin
|
|
|
|
//
|
|
|
|
// This file has been put into the public domain.
|
|
|
|
// You can do whatever you want with this file.
|
|
|
|
//
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
|
|
|
|
/// Output buffer for a single thread
|
2021-01-09 21:14:36 +02:00
|
|
|
typedef struct lzma_outbuf_s lzma_outbuf;
|
|
|
|
struct lzma_outbuf_s {
|
|
|
|
/// Pointer to the next buffer. This is used for the cached buffers.
|
|
|
|
/// The worker thread must not modify this.
|
|
|
|
lzma_outbuf *next;
|
|
|
|
|
|
|
|
/// This initialized by lzma_outq_get_buf() and
|
|
|
|
/// is used by lzma_outq_enable_partial_output().
|
|
|
|
/// The worker thread must not modify this.
|
|
|
|
void *worker;
|
|
|
|
|
|
|
|
/// Amount of memory allocated for buf[].
|
|
|
|
/// The worker thread must not modify this.
|
|
|
|
size_t allocated;
|
|
|
|
|
|
|
|
/// Writing position in the worker thread or, in other words, the
|
|
|
|
/// amount of finished data written to buf[] which can be copied out
|
|
|
|
///
|
|
|
|
/// \note This is read by another thread and thus access
|
|
|
|
/// to this variable needs a mutex.
|
|
|
|
size_t pos;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2022-03-06 16:41:19 +02:00
|
|
|
/// Decompression: Position in the input buffer in the worker thread
|
|
|
|
/// that matches the output "pos" above. This is used to detect if
|
|
|
|
/// more output might be possible from the worker thread: if it has
|
|
|
|
/// consumed all its input, then more output isn't possible.
|
|
|
|
///
|
|
|
|
/// \note This is read by another thread and thus access
|
|
|
|
/// to this variable needs a mutex.
|
|
|
|
size_t decoder_in_pos;
|
|
|
|
|
2011-04-11 22:03:30 +03:00
|
|
|
/// True when no more data will be written into this buffer.
|
|
|
|
///
|
|
|
|
/// \note This is read by another thread and thus access
|
|
|
|
/// to this variable needs a mutex.
|
|
|
|
bool finished;
|
|
|
|
|
2022-03-06 16:41:19 +02:00
|
|
|
/// Return value for lzma_outq_read() when the last byte from
|
|
|
|
/// a finished buffer has been read. Defaults to LZMA_STREAM_END.
|
|
|
|
/// This must *not* be LZMA_OK. The idea is to allow a decoder to
|
|
|
|
/// pass an error code to the main thread, setting the code here
|
|
|
|
/// together with finished = true.
|
|
|
|
lzma_ret finish_ret;
|
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Additional size information. lzma_outq_read() may read these
|
|
|
|
/// when "finished" is true.
|
|
|
|
lzma_vli unpadded_size;
|
|
|
|
lzma_vli uncompressed_size;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Buffer of "allocated" bytes
|
|
|
|
uint8_t buf[];
|
|
|
|
};
|
2011-04-11 22:03:30 +03:00
|
|
|
|
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
typedef struct {
|
|
|
|
/// Linked list of buffers in use. The next output byte will be
|
|
|
|
/// read from the head and buffers for the next thread will be
|
|
|
|
/// appended to the tail. tail->next is always NULL.
|
|
|
|
lzma_outbuf *head;
|
|
|
|
lzma_outbuf *tail;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Number of bytes read from head->buf[] in lzma_outq_read()
|
|
|
|
size_t read_pos;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Linked list of allocated buffers that aren't currently used.
|
|
|
|
/// This way buffers of similar size can be reused and don't
|
|
|
|
/// need to be reallocated every time. For simplicity, all
|
|
|
|
/// cached buffers in the list have the same allocated size.
|
|
|
|
lzma_outbuf *cache;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Total amount of memory allocated for buffers
|
2022-03-06 16:41:19 +02:00
|
|
|
uint64_t mem_allocated;
|
|
|
|
|
|
|
|
/// Amount of memory used by the buffers that are in use in
|
|
|
|
/// the head...tail linked list.
|
|
|
|
uint64_t mem_in_use;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Number of buffers in use in the head...tail list. If and only if
|
|
|
|
/// this is zero, the pointers head and tail above are NULL.
|
|
|
|
uint32_t bufs_in_use;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Number of buffers allocated (in use + cached)
|
|
|
|
uint32_t bufs_allocated;
|
2011-04-11 22:03:30 +03:00
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// Maximum allowed number of allocated buffers
|
|
|
|
uint32_t bufs_limit;
|
2011-04-11 22:03:30 +03:00
|
|
|
} lzma_outq;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Calculate the memory usage of an output queue
|
|
|
|
*
|
|
|
|
* \return Approximate memory usage in bytes or UINT64_MAX on error.
|
|
|
|
*/
|
|
|
|
extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief Initialize an output queue
|
|
|
|
///
|
|
|
|
/// \param outq Pointer to an output queue. Before calling
|
|
|
|
/// this function the first time, *outq should
|
|
|
|
/// have been zeroed with memzero() so that this
|
|
|
|
/// function knows that there are no previous
|
|
|
|
/// allocations to free.
|
|
|
|
/// \param allocator Pointer to allocator or NULL
|
|
|
|
/// \param threads Number of buffers that may be in use
|
|
|
|
/// concurrently. Note that more than this number
|
2021-01-09 21:14:36 +02:00
|
|
|
/// of buffers may actually get allocated to
|
2011-04-11 22:03:30 +03:00
|
|
|
/// improve performance when buffers finish
|
2021-01-09 21:14:36 +02:00
|
|
|
/// out of order. The actual maximum number of
|
|
|
|
/// allocated buffers is derived from the number
|
|
|
|
/// of threads.
|
2011-04-11 22:03:30 +03:00
|
|
|
///
|
|
|
|
/// \return - LZMA_OK
|
|
|
|
/// - LZMA_MEM_ERROR
|
|
|
|
///
|
2021-01-09 21:14:36 +02:00
|
|
|
extern lzma_ret lzma_outq_init(lzma_outq *outq,
|
|
|
|
const lzma_allocator *allocator, uint32_t threads);
|
2011-04-11 22:03:30 +03:00
|
|
|
|
|
|
|
|
|
|
|
/// \brief Free the memory associated with the output queue
|
2012-07-17 18:19:59 +03:00
|
|
|
extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);
|
2011-04-11 22:03:30 +03:00
|
|
|
|
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// \brief Free all cached buffers that consume memory but aren't in use
|
|
|
|
extern void lzma_outq_clear_cache(
|
|
|
|
lzma_outq *outq, const lzma_allocator *allocator);
|
|
|
|
|
|
|
|
|
2022-03-06 16:41:19 +02:00
|
|
|
/// \brief Like lzma_outq_clear_cache() but might keep one buffer
|
|
|
|
///
|
|
|
|
/// One buffer is not freed if its size is equal to keep_size.
|
|
|
|
/// This is useful if the caller knows that it will soon need a buffer of
|
|
|
|
/// keep_size bytes. This way it won't be freed and immediately reallocated.
|
|
|
|
extern void lzma_outq_clear_cache2(
|
|
|
|
lzma_outq *outq, const lzma_allocator *allocator,
|
|
|
|
size_t keep_size);
|
|
|
|
|
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// \brief Preallocate a new buffer into cache
|
|
|
|
///
|
|
|
|
/// Splitting the buffer allocation into a separate function makes it
|
|
|
|
/// possible to ensure that way lzma_outq_get_buf() cannot fail.
|
|
|
|
/// If the preallocated buffer isn't actually used (for example, some
|
|
|
|
/// other error occurs), the caller has to do nothing as the buffer will
|
|
|
|
/// be used later or cleared from the cache when not needed.
|
|
|
|
///
|
|
|
|
/// \return LZMA_OK on success, LZMA_MEM_ERROR if allocation fails
|
|
|
|
///
|
|
|
|
extern lzma_ret lzma_outq_prealloc_buf(
|
|
|
|
lzma_outq *outq, const lzma_allocator *allocator, size_t size);
|
|
|
|
|
|
|
|
|
2011-04-11 22:03:30 +03:00
|
|
|
/// \brief Get a new buffer
|
|
|
|
///
|
2021-01-09 21:14:36 +02:00
|
|
|
/// lzma_outq_prealloc_buf() must be used to ensure that there is a buffer
|
2011-04-11 22:03:30 +03:00
|
|
|
/// available before calling lzma_outq_get_buf().
|
|
|
|
///
|
2021-01-09 21:14:36 +02:00
|
|
|
extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq, void *worker);
|
2011-04-11 22:03:30 +03:00
|
|
|
|
|
|
|
|
|
|
|
/// \brief Test if there is data ready to be read
|
|
|
|
///
|
|
|
|
/// Call to this function must be protected with the same mutex that
|
|
|
|
/// is used to protect lzma_outbuf.finished.
|
|
|
|
///
|
|
|
|
extern bool lzma_outq_is_readable(const lzma_outq *outq);
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief Read finished data
|
|
|
|
///
|
|
|
|
/// \param outq Pointer to an output queue
|
|
|
|
/// \param out Beginning of the output buffer
|
|
|
|
/// \param out_pos The next byte will be written to
|
|
|
|
/// out[*out_pos].
|
|
|
|
/// \param out_size Size of the out buffer; the first byte into
|
|
|
|
/// which no data is written to is out[out_size].
|
|
|
|
/// \param unpadded_size Unpadded Size from the Block encoder
|
|
|
|
/// \param uncompressed_size Uncompressed Size from the Block encoder
|
|
|
|
///
|
|
|
|
/// \return - LZMA: All OK. Either no data was available or the buffer
|
|
|
|
/// being read didn't become empty yet.
|
|
|
|
/// - LZMA_STREAM_END: The buffer being read was finished.
|
2021-01-09 21:14:36 +02:00
|
|
|
/// *unpadded_size and *uncompressed_size were set if they
|
|
|
|
/// were not NULL.
|
2011-04-11 22:03:30 +03:00
|
|
|
///
|
2021-01-09 21:14:36 +02:00
|
|
|
/// \note This reads lzma_outbuf.finished and .pos variables and thus
|
|
|
|
/// calls to this function need to be protected with a mutex.
|
2011-04-11 22:03:30 +03:00
|
|
|
///
|
|
|
|
extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
|
2021-01-09 21:14:36 +02:00
|
|
|
const lzma_allocator *restrict allocator,
|
2011-04-11 22:03:30 +03:00
|
|
|
uint8_t *restrict out, size_t *restrict out_pos,
|
|
|
|
size_t out_size, lzma_vli *restrict unpadded_size,
|
|
|
|
lzma_vli *restrict uncompressed_size);
|
|
|
|
|
|
|
|
|
2021-01-09 21:14:36 +02:00
|
|
|
/// \brief Enable partial output from a worker thread
|
|
|
|
///
|
|
|
|
/// If the buffer at the head of the output queue isn't finished,
|
|
|
|
/// this will call enable_partial_output on the worker associated with
|
|
|
|
/// that output buffer.
|
|
|
|
///
|
|
|
|
/// \note This reads a lzma_outbuf.finished variable and thus
|
|
|
|
/// calls to this function need to be protected with a mutex.
|
|
|
|
///
|
|
|
|
extern void lzma_outq_enable_partial_output(lzma_outq *outq,
|
|
|
|
void (*enable_partial_output)(void *worker));
|
|
|
|
|
|
|
|
|
2011-04-11 22:03:30 +03:00
|
|
|
/// \brief Test if there is at least one buffer free
|
|
|
|
///
|
|
|
|
/// This must be used before getting a new buffer with lzma_outq_get_buf().
|
|
|
|
///
|
|
|
|
static inline bool
|
|
|
|
lzma_outq_has_buf(const lzma_outq *outq)
|
|
|
|
{
|
2021-01-09 21:14:36 +02:00
|
|
|
return outq->bufs_in_use < outq->bufs_limit;
|
2011-04-11 22:03:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// \brief Test if the queue is completely empty
|
|
|
|
static inline bool
|
|
|
|
lzma_outq_is_empty(const lzma_outq *outq)
|
|
|
|
{
|
2021-01-09 21:14:36 +02:00
|
|
|
return outq->bufs_in_use == 0;
|
2011-04-11 22:03:30 +03:00
|
|
|
}
|
2022-03-06 16:41:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
/// \brief Get the amount of memory needed for a single lzma_outbuf
|
|
|
|
///
|
|
|
|
/// \note Caller must check that the argument is significantly less
|
|
|
|
/// than SIZE_MAX to avoid an integer overflow!
|
|
|
|
static inline uint64_t
|
|
|
|
lzma_outq_outbuf_memusage(size_t buf_size)
|
|
|
|
{
|
|
|
|
assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
|
|
|
|
return sizeof(lzma_outbuf) + buf_size;
|
|
|
|
}
|