201 lines
5.3 KiB
C
201 lines
5.3 KiB
C
|
|
/*
|
||
|
|
* CS 361: Template project driver
|
||
|
|
*
|
||
|
|
* Name: Nicholas Tamassia
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <assert.h>
|
||
|
|
#include <getopt.h>
|
||
|
|
#include <inttypes.h>
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <stdbool.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#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;
|
||
|
|
}
|