Coverage Report

Created: 2025-08-26 06:02

/src/xz/src/liblzma/common/outqueue.h
Line
Count
Source
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      allocator       lzma_allocator for custom allocator functions
192
/// \param      out             Beginning of the output buffer
193
/// \param      out_pos         The next byte will be written to
194
///                             out[*out_pos].
195
/// \param      out_size        Size of the out buffer; the first byte into
196
///                             which no data is written to is out[out_size].
197
/// \param      unpadded_size   Unpadded Size from the Block encoder
198
/// \param      uncompressed_size Uncompressed Size from the Block encoder
199
///
200
/// \return     - LZMA: All OK. Either no data was available or the buffer
201
///               being read didn't become empty yet.
202
///             - LZMA_STREAM_END: The buffer being read was finished.
203
///               *unpadded_size and *uncompressed_size were set if they
204
///               were not NULL.
205
///
206
/// \note       This reads lzma_outbuf.finished and .pos variables and thus
207
///             calls to this function need to be protected with a mutex.
208
///
209
extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
210
    const lzma_allocator *restrict allocator,
211
    uint8_t *restrict out, size_t *restrict out_pos,
212
    size_t out_size, lzma_vli *restrict unpadded_size,
213
    lzma_vli *restrict uncompressed_size);
214
215
216
/// \brief      Enable partial output from a worker thread
217
///
218
/// If the buffer at the head of the output queue isn't finished,
219
/// this will call enable_partial_output on the worker associated with
220
/// that output buffer.
221
///
222
/// \note       This reads a lzma_outbuf.finished variable and thus
223
///             calls to this function need to be protected with a mutex.
224
///
225
extern void lzma_outq_enable_partial_output(lzma_outq *outq,
226
    void (*enable_partial_output)(void *worker));
227
228
229
/// \brief      Test if there is at least one buffer free
230
///
231
/// This must be used before getting a new buffer with lzma_outq_get_buf().
232
///
233
static inline bool
234
lzma_outq_has_buf(const lzma_outq *outq)
235
118k
{
236
118k
  return outq->bufs_in_use < outq->bufs_limit;
237
118k
}
stream_decoder_mt.c:lzma_outq_has_buf
Line
Count
Source
235
118k
{
236
118k
  return outq->bufs_in_use < outq->bufs_limit;
237
118k
}
Unexecuted instantiation: outqueue.c:lzma_outq_has_buf
238
239
240
/// \brief      Test if the queue is completely empty
241
static inline bool
242
lzma_outq_is_empty(const lzma_outq *outq)
243
575k
{
244
575k
  return outq->bufs_in_use == 0;
245
575k
}
stream_decoder_mt.c:lzma_outq_is_empty
Line
Count
Source
243
575k
{
244
575k
  return outq->bufs_in_use == 0;
245
575k
}
Unexecuted instantiation: outqueue.c:lzma_outq_is_empty
246
247
248
/// \brief      Get the amount of memory needed for a single lzma_outbuf
249
///
250
/// \note       Caller must check that the argument is significantly less
251
///             than SIZE_MAX to avoid an integer overflow!
252
static inline uint64_t
253
lzma_outq_outbuf_memusage(size_t buf_size)
254
403k
{
255
403k
  assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
256
403k
  return sizeof(lzma_outbuf) + buf_size;
257
403k
}
stream_decoder_mt.c:lzma_outq_outbuf_memusage
Line
Count
Source
254
117k
{
255
117k
  assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
256
117k
  return sizeof(lzma_outbuf) + buf_size;
257
117k
}
outqueue.c:lzma_outq_outbuf_memusage
Line
Count
Source
254
285k
{
255
285k
  assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
256
285k
  return sizeof(lzma_outbuf) + buf_size;
257
285k
}
258
259
#endif