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
13 #include "common.h"
14
15
16 /// Output buffer for a single thread
17 typedef struct {
18 /// Pointer to the output buffer of lzma_outq.buf_size_max bytes
19 uint8_t *buf;
20
21 /// Amount of data written to buf
22 size_t size;
23
24 /// Additional size information
25 lzma_vli unpadded_size;
26 lzma_vli uncompressed_size;
27
28 /// True when no more data will be written into this buffer.
29 ///
30 /// \note This is read by another thread and thus access
31 /// to this variable needs a mutex.
32 bool finished;
33
34 } lzma_outbuf;
35
36
37 typedef struct {
38 /// Array of buffers that are used cyclically.
39 lzma_outbuf *bufs;
40
41 /// Memory allocated for all the buffers
42 uint8_t *bufs_mem;
43
44 /// Amount of buffer space available in each buffer
45 size_t buf_size_max;
46
47 /// Number of buffers allocated
48 uint32_t bufs_allocated;
49
50 /// Position in the bufs array. The next buffer to be taken
51 /// into use is bufs[bufs_pos].
52 uint32_t bufs_pos;
53
54 /// Number of buffers in use
55 uint32_t bufs_used;
56
57 /// Position in the buffer in lzma_outq_read()
58 size_t read_pos;
59
60 } lzma_outq;
61
62
63 /**
64 * \brief Calculate the memory usage of an output queue
65 *
66 * \return Approximate memory usage in bytes or UINT64_MAX on error.
67 */
68 extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);
69
70
71 /// \brief Initialize an output queue
72 ///
73 /// \param outq Pointer to an output queue. Before calling
74 /// this function the first time, *outq should
75 /// have been zeroed with memzero() so that this
76 /// function knows that there are no previous
77 /// allocations to free.
78 /// \param allocator Pointer to allocator or NULL
79 /// \param buf_size_max Maximum amount of data that a single buffer
80 /// in the queue may need to store.
81 /// \param threads Number of buffers that may be in use
82 /// concurrently. Note that more than this number
83 /// of buffers will actually get allocated to
84 /// improve performance when buffers finish
85 /// out of order.
86 ///
87 /// \return - LZMA_OK
88 /// - LZMA_MEM_ERROR
89 ///
90 extern lzma_ret lzma_outq_init(
91 lzma_outq *outq, const lzma_allocator *allocator,
92 uint64_t buf_size_max, uint32_t threads);
93
94
95 /// \brief Free the memory associated with the output queue
96 extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);
97
98
99 /// \brief Get a new buffer
100 ///
101 /// lzma_outq_has_buf() must be used to check that there is a buffer
102 /// available before calling lzma_outq_get_buf().
103 ///
104 extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq);
105
106
107 /// \brief Test if there is data ready to be read
108 ///
109 /// Call to this function must be protected with the same mutex that
110 /// is used to protect lzma_outbuf.finished.
111 ///
112 extern bool lzma_outq_is_readable(const lzma_outq *outq);
113
114
115 /// \brief Read finished data
116 ///
117 /// \param outq Pointer to an output queue
118 /// \param out Beginning of the output buffer
119 /// \param out_pos The next byte will be written to
120 /// out[*out_pos].
121 /// \param out_size Size of the out buffer; the first byte into
122 /// which no data is written to is out[out_size].
123 /// \param unpadded_size Unpadded Size from the Block encoder
124 /// \param uncompressed_size Uncompressed Size from the Block encoder
125 ///
126 /// \return - LZMA: All OK. Either no data was available or the buffer
127 /// being read didn't become empty yet.
128 /// - LZMA_STREAM_END: The buffer being read was finished.
129 /// *unpadded_size and *uncompressed_size were set.
130 ///
131 /// \note This reads lzma_outbuf.finished variables and thus call
132 /// to this function needs to be protected with a mutex.
133 ///
134 extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
135 uint8_t *restrict out, size_t *restrict out_pos,
136 size_t out_size, lzma_vli *restrict unpadded_size,
137 lzma_vli *restrict uncompressed_size);
138
139
140 /// \brief Test if there is at least one buffer free
141 ///
142 /// This must be used before getting a new buffer with lzma_outq_get_buf().
143 ///
144 static inline bool
lzma_outq_has_buf(const lzma_outq * outq)145 lzma_outq_has_buf(const lzma_outq *outq)
146 {
147 return outq->bufs_used < outq->bufs_allocated;
148 }
149
150
151 /// \brief Test if the queue is completely empty
152 static inline bool
lzma_outq_is_empty(const lzma_outq * outq)153 lzma_outq_is_empty(const lzma_outq *outq)
154 {
155 return outq->bufs_used == 0;
156 }
157