summaryrefslogtreecommitdiff
path: root/include/sqfs/block_processor.h
blob: ca560f7cb54857cf78f5c7e45f95c7c5c21140f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
 * block_processor.h - This file is part of libsquashfs
 *
 * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#ifndef SFQS_BLOCK_PROCESSOR_H
#define SFQS_BLOCK_PROCESSOR_H

#include "sqfs/predef.h"

/**
 * @file block_processor.h
 *
 * @brief Contains declarations for the data block processor.
 */

/**
 * @struct sqfs_block_processor_t
 *
 * @brief Encapsulates a thread pool based block processor.
 *
 * The actual implementation may even be non-threaded, depending on the
 * operating system and compile configuration.
 *
 * Either way, the instantiated object processes data blocks that can be
 * enqueued through @ref sqfs_block_processor_enqueue. The completed blocks
 * (compressed and checksumed) are dequeued in the same order and a callback
 * is called for each one.
 */

/**
 * @enum E_SQFS_BLK_FLAGS
 *
 * @brief Generic flags that tell the processor what to do with a block and
 *        flags that the processor sets when it is done with a block.
 */
typedef enum {
	/**
	 * @brief Only calculate checksum, do NOT compress the data.
	 */
	SQFS_BLK_DONT_COMPRESS = 0x0001,

	/**
	 * @brief Set by compressor worker if the block was actually compressed.
	 */
	SQFS_BLK_IS_COMPRESSED = 0x0002,

	/**
	 * @brief Do not calculate block checksum.
	 */
	SQFS_BLK_DONT_CHECKSUM = 0x0004,

	/**
	 * @brief Set by compressor worker if compression failed.
	 */
	SQFS_BLK_COMPRESS_ERROR = 0x0008,

	/**
	 * @brief Indicates that an equeued block is the first block of a file.
	 */
	SQFS_BLK_FIRST_BLOCK = 0x0010,

	/**
	 * @brief Indicates that an equeued block is the last block of a file.
	 */
	SQFS_BLK_LAST_BLOCK = 0x0020,

	/**
	 * @brief Allign the block on disk to device block size.
	 *
	 * If set in combination with @ref SQFS_BLK_FIRST_BLOCK, the output
	 * file is padded to a multiple of the device block size before writing
	 * the block.
	 *
	 * If used with @ref SQFS_BLK_LAST_BLOCK, the output file is padded
	 * after writing the block.
	 */
	SQFS_BLK_ALLIGN = 0x0040,

	/**
	 * @brief Indicates that a block is not part of a file but contains
	 *        file tail ends and an entry in the fragment table has to be
	 *        added.
	 */
	SQFS_BLK_FRAGMENT_BLOCK = 0x0080,
} E_SQFS_BLK_FLAGS;

/**
 * @struct sqfs_block_t
 *
 * @brief Encapsulates a chunk of data to be processed by the block processor.
 */
struct sqfs_block_t {
	/**
	 * @brief Used internally, existing value is ignored and overwritten
	 *        when enqueueing a block.
	 */
	sqfs_block_t *next;

	/**
	 * @brief Used internally, existing value is ignored and overwritten
	 *        when enqueueing a block.
	 */
	uint32_t sequence_number;

	/**
	 * @brief Size of the data area.
	 */
	uint32_t size;

	/**
	 * @brief Checksum of the input data.
	 */
	uint32_t checksum;

	/**
	 * @brief User settable file block index.
	 *
	 * Can be used for purposes like indexing the block size table.
	 */
	uint32_t index;

	/**
	 * @brief Arbitary user pointer associated with the block.
	 */
	void *user;

	/**
	 * @brief User settable flag field.
	 *
	 * A combination of @ref E_SQFS_BLK_FLAGS and custom, user
	 * settable flags.
	 */
	uint32_t flags;

	/**
	 * @brief Raw data to be processed.
	 */
	uint8_t data[];
};

/**
 * @brief Signature of a callback function that can is called for each block.
 *
 * Gets called for each processed block. May be called from a different thread
 * than the one that calls enqueue or from the same thread, but only from one
 * thread at a time.
 *
 * Guaranteed to be called on blocks in the order that they are submitted
 * to enqueue.
 *
 * @param user The user pointer passed to @ref sqfs_block_processor_create.
 * @param blk The finished block.
 *
 * @return A non-zero return value is interpreted as fatal error.
 */
typedef int (*sqfs_block_cb)(void *user, sqfs_block_t *blk);

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Create a block processor.
 *
 * @memberof sqfs_block_processor_t
 *
 * @param max_block_size The maximum size of a data block. Required for the
 *                       internal scratch buffer used for compressing data.
 * @param cmp A pointer to a compressor. If multiple worker threads are used,
 *            the deep copy function of the compressor is used to create
 *            several instances that don't interfere with each other.
 * @param num_workers The number of worker threads to create.
 * @param max_backlog The maximum number of blocks currently in flight. When
 *                    trying to add more, enqueueing blocks until the in-flight
 *                    block count drops below the threshold.
 * @param user An arbitrary user pointer to pass to the block callback.
 * @param callback A function to call for each finished data block.
 *
 * @return A pointer to a block processor object on success, NULL on allocation
 *         failure or on failure to create the worker threads and
 *         synchronisation primitives.
 */
SQFS_API
sqfs_block_processor_t *sqfs_block_processor_create(size_t max_block_size,
						    sqfs_compressor_t *cmp,
						    unsigned int num_workers,
						    size_t max_backlog,
						    void *user,
						    sqfs_block_cb callback);

/**
 * @brief Destroy a block processor and free all memory used by it.
 *
 * @memberof sqfs_block_processor_t
 *
 * @param proc A pointer to a block processor object.
 */
SQFS_API void sqfs_block_processor_destroy(sqfs_block_processor_t *proc);

/**
 * @brief Add a block to be processed.
 *
 * @memberof sqfs_block_processor_t
 *
 * The function takes over ownership of the submitted block. It is freed after
 * processing and calling the block callback.
 *
 * @note Even on failure, the workers may still be running and you should still
 *       call @ref sqfs_block_processor_finish before cleaning up.
 *
 * @param proc A pointer to a block processor object.
 * @param block A poitner to a block to enqueue.
 *
 * @return Zero on success, an @ref E_SQFS_ERROR value on failure. Depending on
 *         the implementation used, the failure return value can actually come
 *         directly from the block callback.
 */
SQFS_API int sqfs_block_processor_enqueue(sqfs_block_processor_t *proc,
					  sqfs_block_t *block);

/**
 * @brief Wait for the workers to finish all in-flight data blocks.
 *
 * @memberof sqfs_block_processor_t
 *
 * @param proc A pointer to a block processor object.
 *
 * @return Zero on success, an @ref E_SQFS_ERROR value on failure. The failure
 *         return value can either be an error encountered during enqueueing,
 *         processing or a failure return status from the block callback.
 */
SQFS_API int sqfs_block_processor_finish(sqfs_block_processor_t *proc);

#ifdef __cplusplus
}
#endif

#endif /* SFQS_BLOCK_PROCESSOR_H */