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