outqueue.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. /// \file outqueue.h
  4. /// \brief Output queue handling in multithreaded coding
  5. //
  6. // Author: Lasse Collin
  7. //
  8. // This file has been put into the public domain.
  9. // You can do whatever you want with this file.
  10. //
  11. ///////////////////////////////////////////////////////////////////////////////
  12. #include "common.h"
  13. /// Output buffer for a single thread
  14. typedef struct lzma_outbuf_s lzma_outbuf;
  15. struct lzma_outbuf_s {
  16. /// Pointer to the next buffer. This is used for the cached buffers.
  17. /// The worker thread must not modify this.
  18. lzma_outbuf *next;
  19. /// This initialized by lzma_outq_get_buf() and
  20. /// is used by lzma_outq_enable_partial_output().
  21. /// The worker thread must not modify this.
  22. void *worker;
  23. /// Amount of memory allocated for buf[].
  24. /// The worker thread must not modify this.
  25. size_t allocated;
  26. /// Writing position in the worker thread or, in other words, the
  27. /// amount of finished data written to buf[] which can be copied out
  28. ///
  29. /// \note This is read by another thread and thus access
  30. /// to this variable needs a mutex.
  31. size_t pos;
  32. /// Decompression: Position in the input buffer in the worker thread
  33. /// that matches the output "pos" above. This is used to detect if
  34. /// more output might be possible from the worker thread: if it has
  35. /// consumed all its input, then more output isn't possible.
  36. ///
  37. /// \note This is read by another thread and thus access
  38. /// to this variable needs a mutex.
  39. size_t decoder_in_pos;
  40. /// True when no more data will be written into this buffer.
  41. ///
  42. /// \note This is read by another thread and thus access
  43. /// to this variable needs a mutex.
  44. bool finished;
  45. /// Return value for lzma_outq_read() when the last byte from
  46. /// a finished buffer has been read. Defaults to LZMA_STREAM_END.
  47. /// This must *not* be LZMA_OK. The idea is to allow a decoder to
  48. /// pass an error code to the main thread, setting the code here
  49. /// together with finished = true.
  50. lzma_ret finish_ret;
  51. /// Additional size information. lzma_outq_read() may read these
  52. /// when "finished" is true.
  53. lzma_vli unpadded_size;
  54. lzma_vli uncompressed_size;
  55. /// Buffer of "allocated" bytes
  56. uint8_t buf[];
  57. };
  58. typedef struct {
  59. /// Linked list of buffers in use. The next output byte will be
  60. /// read from the head and buffers for the next thread will be
  61. /// appended to the tail. tail->next is always NULL.
  62. lzma_outbuf *head;
  63. lzma_outbuf *tail;
  64. /// Number of bytes read from head->buf[] in lzma_outq_read()
  65. size_t read_pos;
  66. /// Linked list of allocated buffers that aren't currently used.
  67. /// This way buffers of similar size can be reused and don't
  68. /// need to be reallocated every time. For simplicity, all
  69. /// cached buffers in the list have the same allocated size.
  70. lzma_outbuf *cache;
  71. /// Total amount of memory allocated for buffers
  72. uint64_t mem_allocated;
  73. /// Amount of memory used by the buffers that are in use in
  74. /// the head...tail linked list.
  75. uint64_t mem_in_use;
  76. /// Number of buffers in use in the head...tail list. If and only if
  77. /// this is zero, the pointers head and tail above are NULL.
  78. uint32_t bufs_in_use;
  79. /// Number of buffers allocated (in use + cached)
  80. uint32_t bufs_allocated;
  81. /// Maximum allowed number of allocated buffers
  82. uint32_t bufs_limit;
  83. } lzma_outq;
  84. /**
  85. * \brief Calculate the memory usage of an output queue
  86. *
  87. * \return Approximate memory usage in bytes or UINT64_MAX on error.
  88. */
  89. extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);
  90. /// \brief Initialize an output queue
  91. ///
  92. /// \param outq Pointer to an output queue. Before calling
  93. /// this function the first time, *outq should
  94. /// have been zeroed with memzero() so that this
  95. /// function knows that there are no previous
  96. /// allocations to free.
  97. /// \param allocator Pointer to allocator or NULL
  98. /// \param threads Number of buffers that may be in use
  99. /// concurrently. Note that more than this number
  100. /// of buffers may actually get allocated to
  101. /// improve performance when buffers finish
  102. /// out of order. The actual maximum number of
  103. /// allocated buffers is derived from the number
  104. /// of threads.
  105. ///
  106. /// \return - LZMA_OK
  107. /// - LZMA_MEM_ERROR
  108. ///
  109. extern lzma_ret lzma_outq_init(lzma_outq *outq,
  110. const lzma_allocator *allocator, uint32_t threads);
  111. /// \brief Free the memory associated with the output queue
  112. extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);
  113. /// \brief Free all cached buffers that consume memory but aren't in use
  114. extern void lzma_outq_clear_cache(
  115. lzma_outq *outq, const lzma_allocator *allocator);
  116. /// \brief Like lzma_outq_clear_cache() but might keep one buffer
  117. ///
  118. /// One buffer is not freed if its size is equal to keep_size.
  119. /// This is useful if the caller knows that it will soon need a buffer of
  120. /// keep_size bytes. This way it won't be freed and immediately reallocated.
  121. extern void lzma_outq_clear_cache2(
  122. lzma_outq *outq, const lzma_allocator *allocator,
  123. size_t keep_size);
  124. /// \brief Preallocate a new buffer into cache
  125. ///
  126. /// Splitting the buffer allocation into a separate function makes it
  127. /// possible to ensure that way lzma_outq_get_buf() cannot fail.
  128. /// If the preallocated buffer isn't actually used (for example, some
  129. /// other error occurs), the caller has to do nothing as the buffer will
  130. /// be used later or cleared from the cache when not needed.
  131. ///
  132. /// \return LZMA_OK on success, LZMA_MEM_ERROR if allocation fails
  133. ///
  134. extern lzma_ret lzma_outq_prealloc_buf(
  135. lzma_outq *outq, const lzma_allocator *allocator, size_t size);
  136. /// \brief Get a new buffer
  137. ///
  138. /// lzma_outq_prealloc_buf() must be used to ensure that there is a buffer
  139. /// available before calling lzma_outq_get_buf().
  140. ///
  141. extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq, void *worker);
  142. /// \brief Test if there is data ready to be read
  143. ///
  144. /// Call to this function must be protected with the same mutex that
  145. /// is used to protect lzma_outbuf.finished.
  146. ///
  147. extern bool lzma_outq_is_readable(const lzma_outq *outq);
  148. /// \brief Read finished data
  149. ///
  150. /// \param outq Pointer to an output queue
  151. /// \param out Beginning of the output buffer
  152. /// \param out_pos The next byte will be written to
  153. /// out[*out_pos].
  154. /// \param out_size Size of the out buffer; the first byte into
  155. /// which no data is written to is out[out_size].
  156. /// \param unpadded_size Unpadded Size from the Block encoder
  157. /// \param uncompressed_size Uncompressed Size from the Block encoder
  158. ///
  159. /// \return - LZMA: All OK. Either no data was available or the buffer
  160. /// being read didn't become empty yet.
  161. /// - LZMA_STREAM_END: The buffer being read was finished.
  162. /// *unpadded_size and *uncompressed_size were set if they
  163. /// were not NULL.
  164. ///
  165. /// \note This reads lzma_outbuf.finished and .pos variables and thus
  166. /// calls to this function need to be protected with a mutex.
  167. ///
  168. extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
  169. const lzma_allocator *restrict allocator,
  170. uint8_t *restrict out, size_t *restrict out_pos,
  171. size_t out_size, lzma_vli *restrict unpadded_size,
  172. lzma_vli *restrict uncompressed_size);
  173. /// \brief Enable partial output from a worker thread
  174. ///
  175. /// If the buffer at the head of the output queue isn't finished,
  176. /// this will call enable_partial_output on the worker associated with
  177. /// that output buffer.
  178. ///
  179. /// \note This reads a lzma_outbuf.finished variable and thus
  180. /// calls to this function need to be protected with a mutex.
  181. ///
  182. extern void lzma_outq_enable_partial_output(lzma_outq *outq,
  183. void (*enable_partial_output)(void *worker));
  184. /// \brief Test if there is at least one buffer free
  185. ///
  186. /// This must be used before getting a new buffer with lzma_outq_get_buf().
  187. ///
  188. static inline bool
  189. lzma_outq_has_buf(const lzma_outq *outq)
  190. {
  191. return outq->bufs_in_use < outq->bufs_limit;
  192. }
  193. /// \brief Test if the queue is completely empty
  194. static inline bool
  195. lzma_outq_is_empty(const lzma_outq *outq)
  196. {
  197. return outq->bufs_in_use == 0;
  198. }
  199. /// \brief Get the amount of memory needed for a single lzma_outbuf
  200. ///
  201. /// \note Caller must check that the argument is significantly less
  202. /// than SIZE_MAX to avoid an integer overflow!
  203. static inline uint64_t
  204. lzma_outq_outbuf_memusage(size_t buf_size)
  205. {
  206. assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
  207. return sizeof(lzma_outbuf) + buf_size;
  208. }