/* * CS 361: Template project driver * * Name: Nicholas Tamassia */ #include #include #include #include #include #include #include #include #include "discrete.h" #include "pthread.h" int cmdline (int, char **, size_t *, uint64_t **, uint64_t **, uint64_t **, size_t *); void usage (void) { printf ("Usage: threads [options] (g:p:g2n ... )\n"); printf (" Required arguments must be an array of g:p:g2n values\n"); printf (" Options are:\n"); printf (" -n N Create N concurrent threads\n"); printf (" g:p:g2n is a colon-delimited list of 3 uint64_t values\n"); printf (" g A group generator\n"); printf (" p A prime number\n"); printf (" g2n g^n mod p for some unknown n\n"); } int main (int argc, char **argv) { uint64_t *primes = NULL; uint64_t *gens = NULL; uint64_t *powers = NULL; size_t num_threads = 1; size_t num_args = 0; if (cmdline (argc, argv, &num_args, &primes, &gens, &powers, &num_threads) < 0) { usage (); return EXIT_FAILURE; } if (num_args < 1 || num_args > 20) { printf ("There must be between 1 and 20 arguments\n"); return EXIT_FAILURE; } // Unithreaded version to serve as a template if (num_threads == 1) { for (int i = 0; i < num_args; i++) { uint64_t result = discrete_log (powers[i], gens[i], primes[i]); printf ("Given g = %" PRId64 ", p = %" PRId64 ", g2n = %" PRId64 " => n = %" PRId64 "\n", gens[i], primes[i], powers[i], result); } } else { uint64_t *logs = calloc (num_args, sizeof (uint64_t)); if (logs == NULL) { fprintf (stderr, "Failed to allocate logs array\n"); return EXIT_FAILURE; } // Adjust number of threads if there are fewer arguments than threads if (num_threads > num_args) num_threads = num_args; size_t base = (num_args + num_threads - 1) / num_threads; // Ceiling division size_t rem = num_args % num_threads; pthread_t *threads = calloc (num_threads, sizeof (pthread_t)); struct time_args *targs = calloc (num_threads, sizeof (struct time_args)); if (threads == NULL || targs == NULL) { free (logs); free (threads); free (targs); fprintf (stderr, "Failed to allocate thread structures\n"); return EXIT_FAILURE; } size_t created = 0; for (size_t t = 0; t < num_threads; t++) { size_t start = t * base; size_t count = (t + 1 == num_threads && rem > 0) ? rem : base; targs[created].start_index = start; targs[created].number = count; targs[created].generators = gens; targs[created].primes = primes; targs[created].mod_powers = powers; targs[created].results = logs; if (pthread_create (&threads[created], NULL, time_log_thread, (void *)&targs[created]) != 0) { for (size_t j = 0; j < created; j++) pthread_join (threads[j], NULL); free (logs); free (threads); free (targs); fprintf (stderr, "Failed to create worker thread\n"); return EXIT_FAILURE; } created++; } for (size_t j = 0; j < created; j++) pthread_join (threads[j], NULL); for (size_t i = 0; i < num_args; i++) { printf ("Given g = %lu, p = %lu, g2n = %lu => n = %lu\n", gens[i], primes[i], powers[i], logs[i]); } free (logs); free (threads); free (targs); } if (primes != NULL) free (primes); if (gens != NULL) free (gens); if (powers != NULL) free (powers); return EXIT_SUCCESS; } /***************************************************************************** ****************** DO NOT MODIFY FUNCTIONS IN THIS SECTION ****************** *****************************************************************************/ int cmdline (int argc, char **argv, size_t *length, uint64_t **primes, uint64_t **gens, uint64_t **powers, size_t *num_threads) { int option; while ((option = getopt (argc, argv, "n:h")) != -1) { switch (option) { case 'n': *num_threads = (size_t)strtol (optarg, NULL, 10); break; case 'h': return -1; break; default: return -1; } } if (optind == argc) return -1; *length = (size_t)(argc - optind); *primes = calloc (*length, sizeof (uint64_t)); size_t index; // These must both have g:p:g2n values *gens = calloc (*length, sizeof (uint64_t)); *powers = calloc (*length, sizeof (uint64_t)); for (index = optind; index < argc; index++) { char *token = strtok (argv[index], ":"); uint64_t value = strtol (token, NULL, 10); (*gens)[index - optind] = value; token = strtok (NULL, ":"); assert (token != NULL); value = strtol (token, NULL, 10); (*primes)[index - optind] = value; token = strtok (NULL, ":"); assert (token != NULL); value = strtol (token, NULL, 10); (*powers)[index - optind] = value; } return 0; }