#include #include #include #include #include #include #include #include #include #include #include #include #define eprintf(...) fprintf(stderr, __VA_ARGS__); typedef struct _Config { char ifile[PATH_MAX + 1]; char ofile[PATH_MAX + 1]; size_t size; uint64_t x0; uint64_t a; uint64_t c; uint64_t m; char *pad; } Config; typedef struct _Context { pthread_t id; pthread_barrier_t *barrier; size_t start; size_t end; size_t length; char *pad; char *input; char *output; } Context; void *lcg_gen(void *arg) { Config *cfg = (Config*) arg; uint64_t x = cfg->x0; uint64_t a = cfg->a; uint64_t c = cfg->c; uint64_t m = cfg->m; for (size_t i = 0; i < cfg->size; i++) { cfg->pad[i] = x; x = (x * a + c) % m; } return NULL; } void *worker(void *arg) { Context *ctx = (Context*) arg; printf("[worker %ld] start: %zu, end: %zu, len: %zu\n", ctx->id, ctx->start, ctx->end, ctx->length); for (size_t i = ctx->start; i < ctx->end; i++) { ctx->output[i] = ctx->input[i] ^ ctx->pad[i]; } pthread_barrier_wait(ctx->barrier); return NULL; } int main(int argc, char *argv[]) { Config cfg; char current_opt; extern char *optarg; extern int optind, optopt, opterr; while ((current_opt = (char) getopt(argc, argv, "hi:o:x:a:c:m:")) != -1) { switch (current_opt) { case 'x': cfg.x0 = atoi(optarg); break; case 'a': cfg.a = atoi(optarg); break; case 'c': cfg.c = atoi(optarg); break; case 'm': cfg.m = atoi(optarg); break; case 'i': strncpy(cfg.ifile, optarg, PATH_MAX); break; case 'o': strncpy(cfg.ofile, optarg, PATH_MAX); break; case 'h': printf("< help text here >\n"); return EXIT_SUCCESS; case ':': eprintf("Option %c requires an argument!\n", optopt); return EXIT_FAILURE; case '?': eprintf("Use \"%s -h\" to see help page\n", argv[0]); return EXIT_FAILURE; } } int ifd; int ofd; if ((ifd = open(cfg.ifile, O_RDONLY)) == -1) { perror("input file"); return EXIT_FAILURE; } if ((ofd = open(cfg.ofile, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE)) == -1) { perror("output file"); return EXIT_FAILURE; } struct stat istat; if (fstat(ifd, &istat) == -1) { perror("input file"); return EXIT_FAILURE; } cfg.size = (size_t) istat.st_size; char *input = mmap(NULL, cfg.size, PROT_READ, MAP_PRIVATE, ifd, 0); if (input == MAP_FAILED) { perror("input file"); return EXIT_FAILURE; } char *output = calloc(sizeof(char), cfg.size); close(ifd); if ((cfg.pad = calloc(sizeof(char), cfg.size)) == NULL) { perror("pad"); return EXIT_FAILURE; } pthread_t th_lcg_gen; if (pthread_create(&th_lcg_gen, NULL, lcg_gen, (void*) &cfg) != 0) { return EXIT_FAILURE; } pthread_join(th_lcg_gen, NULL); int workers_count = get_nprocs(); Context **workers = calloc(sizeof(Context*), workers_count); size_t blen = cfg.size / workers_count; // averrage len for one block printf("[main] workers count: %d\n", workers_count); pthread_barrier_t barrier; if (pthread_barrier_init(&barrier, NULL, workers_count + 1) != 0) { return EXIT_FAILURE; } printf("[main] file size: %zu\n", cfg.size); for (int i = 0; i < workers_count; i++) { workers[i] = calloc(sizeof(Context), 1); workers[i]->barrier = &barrier; workers[i]->pad = cfg.pad; workers[i]->input = input; workers[i]->output = output; workers[i]->start = i * blen; if (i == workers_count - 1) { workers[i]->end = cfg.size; // handle remainder after integer division } else { workers[i]->end = (i + 1) * blen; } workers[i]->length = workers[i]->end - workers[i]->start; pthread_create(&workers[i]->id, NULL, worker, (void*) workers[i]); } pthread_barrier_wait(&barrier); for (int i = 0; i < workers_count; i++) { pthread_join(workers[i]->id, NULL); } pthread_barrier_destroy(&barrier); munmap(input, cfg.size); for (int i = 0; i < workers_count; i++) { free(workers[i]); } free(workers); free(cfg.pad); write(ofd, output, cfg.size); close(ofd); free(output); return EXIT_SUCCESS; }