| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| /// \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 | |
| typedef struct { | |
| /// Pointer to the output buffer of lzma_outq.buf_size_max bytes | |
| uint8_t *buf; | |
| /// Amount of data written to buf | |
| size_t size; | |
| /// Additional size information | |
| lzma_vli unpadded_size; | |
| lzma_vli uncompressed_size; | |
| /// 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; | |
| } lzma_outbuf; | |
| typedef struct { | |
| /// Array of buffers that are used cyclically. | |
| lzma_outbuf *bufs; | |
| /// Memory allocated for all the buffers | |
| uint8_t *bufs_mem; | |
| /// Amount of buffer space available in each buffer | |
| size_t buf_size_max; | |
| /// Number of buffers allocated | |
| uint32_t bufs_allocated; | |
| /// Position in the bufs array. The next buffer to be taken | |
| /// into use is bufs[bufs_pos]. | |
| uint32_t bufs_pos; | |
| /// Number of buffers in use | |
| uint32_t bufs_used; | |
| /// Position in the buffer in lzma_outq_read() | |
| size_t read_pos; | |
| } 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 buf_size_max Maximum amount of data that a single buffer | |
| /// in the queue may need to store. | |
| /// \param threads Number of buffers that may be in use | |
| /// concurrently. Note that more than this number | |
| /// of buffers will actually get allocated to | |
| /// improve performance when buffers finish | |
| /// out of order. | |
| /// | |
| /// \return - LZMA_OK | |
| /// - LZMA_MEM_ERROR | |
| /// | |
| extern lzma_ret lzma_outq_init(lzma_outq *outq, lzma_allocator *allocator, | |
| uint64_t buf_size_max, uint32_t threads); | |
| /// \brief Free the memory associated with the output queue | |
| extern void lzma_outq_end(lzma_outq *outq, lzma_allocator *allocator); | |
| /// \brief Get a new buffer | |
| /// | |
| /// lzma_outq_has_buf() must be used to check that there is a buffer | |
| /// available before calling lzma_outq_get_buf(). | |
| /// | |
| extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq); | |
| /// \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. | |
| /// *unpadded_size and *uncompressed_size were set. | |
| /// | |
| /// \note This reads lzma_outbuf.finished variables and thus call | |
| /// to this function needs to be protected with a mutex. | |
| /// | |
| extern lzma_ret lzma_outq_read(lzma_outq *restrict outq, | |
| uint8_t *restrict out, size_t *restrict out_pos, | |
| size_t out_size, lzma_vli *restrict unpadded_size, | |
| lzma_vli *restrict uncompressed_size); | |
| /// \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) | |
| { | |
| return outq->bufs_used < outq->bufs_allocated; | |
| } | |
| /// \brief Test if the queue is completely empty | |
| static inline bool | |
| lzma_outq_is_empty(const lzma_outq *outq) | |
| { | |
| return outq->bufs_used == 0; | |
| } |