From 7c5cd1e104f23ec7d9c23086993630f398e2d8e0 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 25 Jul 2019 14:03:55 +0200 Subject: Implement simple, fork() based parallel unpacking in rdsquashfs Signed-off-by: David Oberhollenzer --- unpack/fill_files.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 2 deletions(-) (limited to 'unpack/fill_files.c') diff --git a/unpack/fill_files.c b/unpack/fill_files.c index 6584699..865d050 100644 --- a/unpack/fill_files.c +++ b/unpack/fill_files.c @@ -33,7 +33,98 @@ static int fill_files(data_reader_t *data, file_info_t *list, int flags) return 0; } -int fill_unpacked_files(fstree_t *fs, data_reader_t *data, int flags) +static file_info_t *split_list(file_info_t *list, uint64_t threashold) { - return fill_files(data, fs->files, flags); + file_info_t *it, *new = NULL; + uint64_t size = 0; + + for (it = list; it != NULL; it = it->next) { + if (it->input_file == NULL) + continue; + + size += it->size - it->sparse; + + if (size >= threashold) { + new = it->next; + it->next = NULL; + break; + } + } + + return new; +} + +static uint64_t total_size(file_info_t *list) +{ + uint64_t size = 0; + file_info_t *it; + + for (it = list; it != NULL; it = it->next) { + if (it->input_file != NULL) + size += it->size - it->sparse; + } + + return size; +} + +int fill_unpacked_files(fstree_t *fs, data_reader_t *data, int flags, + unsigned int num_jobs) +{ + file_info_t *sublists[num_jobs], *it; + int exitstatus, status = 0; + uint64_t threshold; + unsigned int i; + pid_t pid; + + if (num_jobs <= 1) { + status = fill_files(data, fs->files, flags); + + for (it = fs->files; it != NULL; it = it->next) + free(it->input_file); + + return status; + } + + threshold = total_size(fs->files) / num_jobs; + + for (i = 0; i < num_jobs; ++i) { + sublists[i] = fs->files; + + fs->files = split_list(fs->files, threshold); + } + + for (i = 0; i < num_jobs; ++i) { + pid = fork(); + + if (pid == 0) { + if (fill_files(data, sublists[i], flags)) + exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); + } + + if (pid < 0) { + perror("fork"); + status = -1; + num_jobs = i; + break; + } + } + + for (i = 0; i < num_jobs; ++i) { + do { + pid = waitpid(-1, &exitstatus, 0); + if (errno == ECHILD) + goto out; + } while (pid < 0); + + if (!WIFEXITED(exitstatus) || + WEXITSTATUS(exitstatus) != EXIT_SUCCESS) { + status = -1; + } + + for (it = sublists[i]; it != NULL; it = it->next) + free(it->input_file); + } +out: + return status; } -- cgit v1.2.3