1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file 04_compress_easy_mt.c
6 /// \brief Compress in multi-call mode using LZMA2 in multi-threaded mode
8 /// Usage: ./04_compress_easy_mt < INFILE > OUTFILE
10 /// Example: ./04_compress_easy_mt < foo > foo.xz
12 // Author: Lasse Collin
14 ///////////////////////////////////////////////////////////////////////////////
25 init_encoder(lzma_stream
*strm
)
27 // The threaded encoder takes the options as pointer to
28 // a lzma_mt structure.
30 // No flags are needed.
33 // Let liblzma determine a sane block size.
36 // Use no timeout for lzma_code() calls by setting timeout
37 // to zero. That is, sometimes lzma_code() might block for
38 // a long time (from several seconds to even minutes).
39 // If this is not OK, for example due to progress indicator
40 // needing updates, specify a timeout in milliseconds here.
41 // See the documentation of lzma_mt in lzma/container.h for
42 // information how to choose a reasonable timeout.
45 // Use the default preset (6) for LZMA2.
46 // To use a preset, filters must be set to NULL.
47 .preset
= LZMA_PRESET_DEFAULT
,
50 // Use CRC64 for integrity checking. See also
51 // 01_compress_easy.c about choosing the integrity check.
52 .check
= LZMA_CHECK_CRC64
,
55 // Detect how many threads the CPU supports.
56 mt
.threads
= lzma_cputhreads();
58 // If the number of CPU cores/threads cannot be detected,
59 // use one thread. Note that this isn't the same as the normal
60 // single-threaded mode as this will still split the data into
61 // blocks and use more RAM than the normal single-threaded mode.
62 // You may want to consider using lzma_easy_encoder() or
63 // lzma_stream_encoder() instead of lzma_stream_encoder_mt() if
64 // lzma_cputhreads() returns 0 or 1.
68 // If the number of CPU cores/threads exceeds threads_max,
69 // limit the number of threads to keep memory usage lower.
70 // The number 8 is arbitrarily chosen and may be too low or
71 // high depending on the compression preset and the computer
74 // FIXME: A better way could be to check the amount of RAM
75 // (or available RAM) and use lzma_stream_encoder_mt_memusage()
76 // to determine if the number of threads should be reduced.
77 const uint32_t threads_max
= 8;
78 if (mt
.threads
> threads_max
)
79 mt
.threads
= threads_max
;
81 // Initialize the threaded encoder.
82 lzma_ret ret
= lzma_stream_encoder_mt(strm
, &mt
);
90 msg
= "Memory allocation failed";
93 case LZMA_OPTIONS_ERROR
:
94 // We are no longer using a plain preset so this error
95 // message has been edited accordingly compared to
96 // 01_compress_easy.c.
97 msg
= "Specified filter chain is not supported";
100 case LZMA_UNSUPPORTED_CHECK
:
101 msg
= "Specified integrity check is not supported";
105 msg
= "Unknown error, possibly a bug";
109 fprintf(stderr
, "Error initializing the encoder: %s (error code %u)\n",
115 // This function is identical to the one in 01_compress_easy.c.
117 compress(lzma_stream
*strm
, FILE *infile
, FILE *outfile
)
119 lzma_action action
= LZMA_RUN
;
121 uint8_t inbuf
[BUFSIZ
];
122 uint8_t outbuf
[BUFSIZ
];
124 strm
->next_in
= NULL
;
126 strm
->next_out
= outbuf
;
127 strm
->avail_out
= sizeof(outbuf
);
130 if (strm
->avail_in
== 0 && !feof(infile
)) {
131 strm
->next_in
= inbuf
;
132 strm
->avail_in
= fread(inbuf
, 1, sizeof(inbuf
),
135 if (ferror(infile
)) {
136 fprintf(stderr
, "Read error: %s\n",
142 action
= LZMA_FINISH
;
145 lzma_ret ret
= lzma_code(strm
, action
);
147 if (strm
->avail_out
== 0 || ret
== LZMA_STREAM_END
) {
148 size_t write_size
= sizeof(outbuf
) - strm
->avail_out
;
150 if (fwrite(outbuf
, 1, write_size
, outfile
)
152 fprintf(stderr
, "Write error: %s\n",
157 strm
->next_out
= outbuf
;
158 strm
->avail_out
= sizeof(outbuf
);
161 if (ret
!= LZMA_OK
) {
162 if (ret
== LZMA_STREAM_END
)
168 msg
= "Memory allocation failed";
171 case LZMA_DATA_ERROR
:
172 msg
= "File size limits exceeded";
176 msg
= "Unknown error, possibly a bug";
180 fprintf(stderr
, "Encoder error: %s (error code %u)\n",
191 lzma_stream strm
= LZMA_STREAM_INIT
;
193 bool success
= init_encoder(&strm
);
195 success
= compress(&strm
, stdin
, stdout
);
199 if (fclose(stdout
)) {
200 fprintf(stderr
, "Write error: %s\n", strerror(errno
));
204 return success
? EXIT_SUCCESS
: EXIT_FAILURE
;