1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Output queue handling in multithreaded coding
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
16 /// This is to ease integer overflow checking: We may allocate up to
17 /// 2 * LZMA_THREADS_MAX buffers and we need some extra memory for other
18 /// data structures (that's the second /2).
19 #define BUF_SIZE_MAX (UINT64_MAX / LZMA_THREADS_MAX / 2 / 2)
23 get_options(uint64_t *bufs_alloc_size, uint32_t *bufs_count,
24 uint64_t buf_size_max, uint32_t threads)
26 if (threads > LZMA_THREADS_MAX || buf_size_max > BUF_SIZE_MAX)
27 return LZMA_OPTIONS_ERROR;
29 // The number of buffers is twice the number of threads.
30 // This wastes RAM but keeps the threads busy when buffers
31 // finish out of order.
33 // NOTE: If this is changed, update BUF_SIZE_MAX too.
34 *bufs_count = threads * 2;
35 *bufs_alloc_size = *bufs_count * buf_size_max;
42 lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads)
44 uint64_t bufs_alloc_size;
47 if (get_options(&bufs_alloc_size, &bufs_count, buf_size_max, threads)
51 return sizeof(lzma_outq) + bufs_count * sizeof(lzma_outbuf)
57 lzma_outq_init(lzma_outq *outq, const lzma_allocator *allocator,
58 uint64_t buf_size_max, uint32_t threads)
60 uint64_t bufs_alloc_size;
63 // Set bufs_count and bufs_alloc_size.
64 return_if_error(get_options(&bufs_alloc_size, &bufs_count,
65 buf_size_max, threads));
67 // Allocate memory if needed.
68 if (outq->buf_size_max != buf_size_max
69 || outq->bufs_allocated != bufs_count) {
70 lzma_outq_end(outq, allocator);
72 #if SIZE_MAX < UINT64_MAX
73 if (bufs_alloc_size > SIZE_MAX)
74 return LZMA_MEM_ERROR;
77 outq->bufs = lzma_alloc(bufs_count * sizeof(lzma_outbuf),
79 outq->bufs_mem = lzma_alloc((size_t)(bufs_alloc_size),
82 if (outq->bufs == NULL || outq->bufs_mem == NULL) {
83 lzma_outq_end(outq, allocator);
84 return LZMA_MEM_ERROR;
88 // Initialize the rest of the main structure. Initialization of
89 // outq->bufs[] is done when they are actually needed.
90 outq->buf_size_max = (size_t)(buf_size_max);
91 outq->bufs_allocated = bufs_count;
101 lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator)
103 lzma_free(outq->bufs, allocator);
106 lzma_free(outq->bufs_mem, allocator);
107 outq->bufs_mem = NULL;
114 lzma_outq_get_buf(lzma_outq *outq)
116 // Caller must have checked it with lzma_outq_has_buf().
117 assert(outq->bufs_used < outq->bufs_allocated);
119 // Initialize the new buffer.
120 lzma_outbuf *buf = &outq->bufs[outq->bufs_pos];
121 buf->buf = outq->bufs_mem + outq->bufs_pos * outq->buf_size_max;
123 buf->finished = false;
125 // Update the queue state.
126 if (++outq->bufs_pos == outq->bufs_allocated)
136 lzma_outq_is_readable(const lzma_outq *outq)
138 uint32_t i = outq->bufs_pos - outq->bufs_used;
139 if (outq->bufs_pos < outq->bufs_used)
140 i += outq->bufs_allocated;
142 return outq->bufs[i].finished;
147 lzma_outq_read(lzma_outq *restrict outq, uint8_t *restrict out,
148 size_t *restrict out_pos, size_t out_size,
149 lzma_vli *restrict unpadded_size,
150 lzma_vli *restrict uncompressed_size)
152 // There must be at least one buffer from which to read.
153 if (outq->bufs_used == 0)
157 uint32_t i = outq->bufs_pos - outq->bufs_used;
158 if (outq->bufs_pos < outq->bufs_used)
159 i += outq->bufs_allocated;
161 lzma_outbuf *buf = &outq->bufs[i];
163 // If it isn't finished yet, we cannot read from it.
167 // Copy from the buffer to output.
168 lzma_bufcpy(buf->buf, &outq->read_pos, buf->size,
169 out, out_pos, out_size);
171 // Return if we didn't get all the data from the buffer.
172 if (outq->read_pos < buf->size)
175 // The buffer was finished. Tell the caller its size information.
176 *unpadded_size = buf->unpadded_size;
177 *uncompressed_size = buf->uncompressed_size;
179 // Free this buffer for further use.
183 return LZMA_STREAM_END;