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
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
153 lzma_outq_is_empty(const lzma_outq *outq)
154 {
155 	return outq->bufs_used == 0;
156 }
157