129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen/* 229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * Copyright (C) 2015 The Android Open Source Project 329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * 429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * Licensed under the Apache License, Version 2.0 (the "License"); 529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * you may not use this file except in compliance with the License. 629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * You may obtain a copy of the License at 729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * 829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * http://www.apache.org/licenses/LICENSE-2.0 929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * 1029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * Unless required by applicable law or agreed to in writing, software 1129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * distributed under the License is distributed on an "AS IS" BASIS, 1229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * See the License for the specific language governing permissions and 1429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen * limitations under the License. 1529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen */ 1629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 1729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#undef NDEBUG 1829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#define _LARGEFILE64_SOURCE 1929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 2029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenextern "C" { 2129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen #include <fec.h> 2229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 2329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 2429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <assert.h> 2566dd09e8e2407082ce93bf0784de641298131912Elliott Hughes#include <android-base/file.h> 2629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <errno.h> 2729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <fcntl.h> 2829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <getopt.h> 2929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <openssl/sha.h> 3029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <pthread.h> 3129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <stdlib.h> 3229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <string.h> 3329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <sys/ioctl.h> 3429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <sys/mman.h> 3529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include <sparse/sparse.h> 3629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen#include "image.h" 3729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 380403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen#if defined(__linux__) 390403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen #include <linux/fs.h> 400403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen#elif defined(__APPLE__) 410403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen #include <sys/disk.h> 420403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen #define BLKGETSIZE64 DKIOCGETBLOCKCOUNT 430403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen #define O_LARGEFILE 0 440403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen#endif 450403024cd6763fff3a0118b15e68c0f7fe4766d5Sami Tolvanen 4629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenvoid image_init(image *ctx) 4729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 4829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen memset(ctx, 0, sizeof(*ctx)); 4929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 5029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 518bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanenvoid image_free(image *ctx) 5229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 5329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert(ctx->input == ctx->output); 5429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 5529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->input) { 5629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen delete[] ctx->input; 5729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 5829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 5929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->fec) { 6029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen delete[] ctx->fec; 6129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 6229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 6329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen image_init(ctx); 6429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 6529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 6629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic void calculate_rounds(uint64_t size, image *ctx) 6729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 6829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!size) { 6929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("empty file?\n"); 7029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } else if (size % FEC_BLOCKSIZE) { 7129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("file size %" PRIu64 " is not a multiple of %u bytes\n", 7229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen size, FEC_BLOCKSIZE); 7329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 7429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 7529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->inp_size = size; 7629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->blocks = fec_div_round_up(ctx->inp_size, FEC_BLOCKSIZE); 7729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rounds = fec_div_round_up(ctx->blocks, ctx->rs_n); 7829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 7929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 8029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic int process_chunk(void *priv, const void *data, int len) 8129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 8229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen image *ctx = (image *)priv; 8329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert(len % FEC_BLOCKSIZE == 0); 8429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 8529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (data) { 8629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen memcpy(&ctx->input[ctx->pos], data, len); 8729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 8829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 8929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->pos += len; 9029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return 0; 9129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 9229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 93f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanenstatic void file_image_load(const std::vector<int>& fds, image *ctx) 9429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 95f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen uint64_t size = 0; 96f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen std::vector<struct sparse_file *> files; 97f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen 98f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen for (auto fd : fds) { 99f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen uint64_t len = 0; 100f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen struct sparse_file *file; 10129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 102f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen if (ctx->sparse) { 103f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen file = sparse_file_import(fd, false, false); 104f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } else { 105f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen file = sparse_file_import_auto(fd, false, ctx->verbose); 106f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } 10729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 108f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen if (!file) { 109f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("failed to read file %s\n", ctx->fec_filename); 110f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } 11129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 112f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen len = sparse_file_len(file, false, false); 113f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen files.push_back(file); 11429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 115f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen size += len; 116f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } 117f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen 118f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen calculate_rounds(size, ctx); 11929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 12029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->verbose) { 12129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen INFO("allocating %" PRIu64 " bytes of memory\n", ctx->inp_size); 12229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 12329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 12429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->input = new uint8_t[ctx->inp_size]; 12529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 12629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!ctx->input) { 12729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to allocate memory\n"); 12829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 12929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 13029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen memset(ctx->input, 0, ctx->inp_size); 13129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->output = ctx->input; 132f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen ctx->pos = 0; 13329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 134f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen for (auto file : files) { 135f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen sparse_file_callback(file, false, false, process_chunk, ctx); 136f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen sparse_file_destroy(file); 137f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } 13829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 139f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen for (auto fd : fds) { 140f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen close(fd); 141f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } 14229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 14329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 1448bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanenbool image_load(const std::vector<std::string>& filenames, image *ctx) 14529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 14629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert(ctx->roots > 0 && ctx->roots < FEC_RSM); 14729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rs_n = FEC_RSM - ctx->roots; 14829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 14929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen int flags = O_RDONLY; 15029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 15129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->inplace) { 15229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen flags = O_RDWR; 15329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 15429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 155f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen std::vector<int> fds; 15629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 157a3b37f4d08e757ce90a7b02ca0e15951455c477cChih-Hung Hsieh for (const auto& fn : filenames) { 158f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), flags | O_LARGEFILE)); 159f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen 160f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen if (fd < 0) { 161f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("failed to open file '%s': %s\n", fn.c_str(), strerror(errno)); 162f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen } 163f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen 164f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen fds.push_back(fd); 16529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 16629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 1678bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen file_image_load(fds, ctx); 16829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 16929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return true; 17029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 17129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 172f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanenbool image_save(const std::string& filename, image *ctx) 17329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 17429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen /* TODO: support saving as a sparse file */ 175f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), 176f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen O_WRONLY | O_CREAT | O_TRUNC, 0666)); 17729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 17829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (fd < 0) { 179f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("failed to open file '%s: %s'\n", filename.c_str(), 180f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen strerror(errno)); 18129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 18229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 18329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!android::base::WriteFully(fd, ctx->output, ctx->inp_size)) { 18429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to write to output: %s\n", strerror(errno)); 18529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 18629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 187f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen close(fd); 18829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return true; 18929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 19029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 1918bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanenbool image_ecc_new(const std::string& filename, image *ctx) 19229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 1938bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen assert(ctx->rounds > 0); /* image_load should be called first */ 19429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 1958bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen ctx->fec_filename = filename.c_str(); 1968bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen ctx->fec_size = ctx->rounds * ctx->roots * FEC_BLOCKSIZE; 19729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 19829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->verbose) { 19929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen INFO("allocating %u bytes of memory\n", ctx->fec_size); 20029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 20129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 20229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->fec = new uint8_t[ctx->fec_size]; 20329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 20429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!ctx->fec) { 20529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to allocate %u bytes\n", ctx->fec_size); 20629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 20729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 20829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return true; 20929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 21029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 211f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanenbool image_ecc_load(const std::string& filename, image *ctx) 21229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 213f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY)); 21429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 21529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (fd < 0) { 216f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("failed to open file '%s': %s\n", filename.c_str(), 217f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen strerror(errno)); 21829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 21929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 22029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (lseek64(fd, -FEC_BLOCKSIZE, SEEK_END) < 0) { 221f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("failed to seek to header in '%s': %s\n", filename.c_str(), 22229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen strerror(errno)); 22329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 22429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 22529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert(sizeof(fec_header) <= FEC_BLOCKSIZE); 22629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 22729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen uint8_t header[FEC_BLOCKSIZE]; 22829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen fec_header *p = (fec_header *)header; 22929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 23029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!android::base::ReadFully(fd, header, sizeof(header))) { 23129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to read %zd bytes from '%s': %s\n", sizeof(header), 232f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen filename.c_str(), strerror(errno)); 23329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 23429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 23529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (p->magic != FEC_MAGIC) { 236f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("invalid magic in '%s': %08x\n", filename.c_str(), p->magic); 23729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 23829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 23929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (p->version != FEC_VERSION) { 240f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("unsupported version in '%s': %u\n", filename.c_str(), 241f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen p->version); 24229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 24329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 24429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (p->size != sizeof(fec_header)) { 245f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("unexpected header size in '%s': %u\n", filename.c_str(), 246f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen p->size); 24729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 24829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 24929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (p->roots == 0 || p->roots >= FEC_RSM) { 250f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("invalid roots in '%s': %u\n", filename.c_str(), p->roots); 25129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 25229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 25329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (p->fec_size % p->roots || p->fec_size % FEC_BLOCKSIZE) { 254f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("invalid length in '%s': %u\n", filename.c_str(), p->fec_size); 25529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 25629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 25729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->roots = (int)p->roots; 25829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rs_n = FEC_RSM - ctx->roots; 25929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 26029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen calculate_rounds(p->inp_size, ctx); 26129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 26229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!image_ecc_new(filename, ctx)) { 26329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to allocate ecc\n"); 26429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 26529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 26629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (p->fec_size != ctx->fec_size) { 267f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("inconsistent header in '%s'\n", filename.c_str()); 26829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 26929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 27029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (lseek64(fd, 0, SEEK_SET) < 0) { 271f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen FATAL("failed to rewind '%s': %s", filename.c_str(), strerror(errno)); 27229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 27329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 2748bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen if (!android::base::ReadFully(fd, ctx->fec, ctx->fec_size)) { 27529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to read %u bytes from '%s': %s\n", ctx->fec_size, 276f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen filename.c_str(), strerror(errno)); 27729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 27829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 279f35a15d11e79892c06ce303e0b983c132955d261Sami Tolvanen close(fd); 28029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 28129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen uint8_t hash[SHA256_DIGEST_LENGTH]; 28229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen SHA256(ctx->fec, ctx->fec_size, hash); 28329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 28429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (memcmp(hash, p->hash, SHA256_DIGEST_LENGTH) != 0) { 28529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("invalid ecc data\n"); 28629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 28729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 28829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return true; 28929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 29029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 29129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenbool image_ecc_save(image *ctx) 29229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 29385e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen assert(2 * sizeof(fec_header) <= FEC_BLOCKSIZE); 29429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 29585e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen uint8_t header[FEC_BLOCKSIZE] = {0}; 29629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 29785e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen fec_header *f = (fec_header *)header; 29829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 29929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen f->magic = FEC_MAGIC; 30029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen f->version = FEC_VERSION; 30129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen f->size = sizeof(fec_header); 30229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen f->roots = ctx->roots; 30329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen f->fec_size = ctx->fec_size; 30429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen f->inp_size = ctx->inp_size; 30529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 30629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen SHA256(ctx->fec, ctx->fec_size, f->hash); 30729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 30829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen /* store a copy of the fec_header at the end of the header block */ 30985e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen memcpy(&header[sizeof(header) - sizeof(fec_header)], header, 31085e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen sizeof(fec_header)); 31129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 3128bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen assert(ctx->fec_filename); 31329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 3148bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen int fd = TEMP_FAILURE_RETRY(open(ctx->fec_filename, 3158bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen O_WRONLY | O_CREAT | O_TRUNC, 0666)); 31629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 3178bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen if (fd < 0) { 3188bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen FATAL("failed to open file '%s': %s\n", ctx->fec_filename, 3198bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen strerror(errno)); 3208bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen } 32129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 32285e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen if (!android::base::WriteFully(fd, ctx->fec, ctx->fec_size)) { 3238bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen FATAL("failed to write to output: %s\n", strerror(errno)); 32429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 32529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 32685e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen if (ctx->padding > 0) { 32785e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen uint8_t padding[FEC_BLOCKSIZE] = {0}; 32885e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen 32985e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen for (uint32_t i = 0; i < ctx->padding; i += FEC_BLOCKSIZE) { 33085e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen if (!android::base::WriteFully(fd, padding, FEC_BLOCKSIZE)) { 33185e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen FATAL("failed to write padding: %s\n", strerror(errno)); 33285e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen } 33385e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen } 33485e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen } 33585e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen 33685e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen if (!android::base::WriteFully(fd, header, sizeof(header))) { 33785e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen FATAL("failed to write to header: %s\n", strerror(errno)); 33885e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen } 33985e592cb86c9cbca82852240f0148adbee1b74e8Sami Tolvanen 3408bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen close(fd); 3418bad827700bae35005872f3e6d674c5144fda8ffSami Tolvanen 34229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return true; 34329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 34429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 34529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenstatic void * process(void *cookie) 34629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 34729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen image_proc_ctx *ctx = (image_proc_ctx *)cookie; 34829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->func(ctx); 34929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return NULL; 35029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 35129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 35229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanenbool image_process(image_proc_func func, image *ctx) 35329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen{ 35429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen int threads = ctx->threads; 35529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 35629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (threads < IMAGE_MIN_THREADS) { 35729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen threads = sysconf(_SC_NPROCESSORS_ONLN); 35829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 35929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (threads < IMAGE_MIN_THREADS) { 36029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen threads = IMAGE_MIN_THREADS; 36129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 36229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 36329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 36429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert(ctx->rounds > 0); 36529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 36629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if ((uint64_t)threads > ctx->rounds) { 36729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen threads = (int)ctx->rounds; 36829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 36929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (threads > IMAGE_MAX_THREADS) { 37029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen threads = IMAGE_MAX_THREADS; 37129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 37229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 37329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->verbose) { 37429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen INFO("starting %d threads to compute RS(255, %d)\n", threads, 37529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rs_n); 37629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 37729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 37829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen pthread_t pthreads[threads]; 37929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen image_proc_ctx args[threads]; 38029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 38129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen uint64_t current = 0; 38229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen uint64_t end = ctx->rounds * ctx->rs_n * FEC_BLOCKSIZE; 38329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen uint64_t rs_blocks_per_thread = 38429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen fec_div_round_up(ctx->rounds * FEC_BLOCKSIZE, threads); 38529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 38629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->verbose) { 38729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen INFO("computing %" PRIu64 " codes per thread\n", rs_blocks_per_thread); 38829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 38929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 39029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen for (int i = 0; i < threads; ++i) { 39129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].func = func; 39229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].id = i; 39329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].ctx = ctx; 39429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].rv = 0; 39529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].fec_pos = current * ctx->roots; 39629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].start = current * ctx->rs_n; 39729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].end = (current + rs_blocks_per_thread) * ctx->rs_n; 39829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 39929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].rs = init_rs_char(FEC_PARAMS(ctx->roots)); 40029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 40129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (!args[i].rs) { 40229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to initialize encoder for thread %d\n", i); 40329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 40429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 40529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (args[i].end > end) { 40629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].end = end; 40729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } else if (i == threads && args[i].end + rs_blocks_per_thread * 40829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rs_n > end) { 40929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].end = end; 41029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 41129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 41229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (ctx->verbose) { 41329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen INFO("thread %d: [%" PRIu64 ", %" PRIu64 ")\n", 41429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen i, args[i].start, args[i].end); 41529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 41629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 41729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert(args[i].start < args[i].end); 41829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen assert((args[i].end - args[i].start) % ctx->rs_n == 0); 41929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 42029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (pthread_create(&pthreads[i], NULL, process, &args[i]) != 0) { 42129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to create thread %d\n", i); 42229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 42329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 42429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen current += rs_blocks_per_thread; 42529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 42629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 42729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rv = 0; 42829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 42929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen for (int i = 0; i < threads; ++i) { 43029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (pthread_join(pthreads[i], NULL) != 0) { 43129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen FATAL("failed to join thread %d: %s\n", i, strerror(errno)); 43229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 43329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 43429bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen ctx->rv += args[i].rv; 43529bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 43629bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen if (args[i].rs) { 43729bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen free_rs_char(args[i].rs); 43829bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen args[i].rs = NULL; 43929bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 44029bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen } 44129bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen 44229bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen return true; 44329bf737e56e10c2742f1e14fe9f07184d59bbcc0Sami Tolvanen} 444