csci3753

CSCI3753 Coursework
git clone https://git.pngu.org/csci3753
Log | Files | Refs | README

multi-lookup.c (5797B)


// Jack Sangdahl
// CSCI3753 SP24
// PA6 Threaded Resolver
#include "multi-lookup.h"
#include "array.h"
#include "util.h"
#include <sys/time.h>

int main(int argc, char **argv) {
  if (argc < 6) {
    fprintf(stderr,
            "usage: %s <# requester> <# resolver> <requester log> <resolver "
            "log> <data file(s)>\n",
            argv[0]);
    exit(EXIT_FAILURE);
  } else if (argc > MAX_INPUT_FILES + 6) {
    fprintf(stderr, "%s error: too many input files\n", argv[0]);
    return EXIT_FAILURE;
  }
  int req_thread_cnt = atoi(argv[1]);
  if (req_thread_cnt < 1) {
    fprintf(stderr, "%s error: minimum 1 requester thread\n", argv[0]);
    return EXIT_FAILURE;
  } else if (req_thread_cnt > MAX_REQUESTER_THREADS) {
    fprintf(stderr, "%s error: requester threads cannot exceed %d\n", argv[0],
            MAX_REQUESTER_THREADS);
    return EXIT_FAILURE;
  }
  int res_thread_cnt = atoi(argv[2]);
  if (res_thread_cnt < 1) {
    fprintf(stderr, "%s error: minimum 1 resolver thread\n", argv[0]);
    return EXIT_FAILURE;
  } else if (res_thread_cnt > MAX_RESOLVER_THREADS) {
    fprintf(stderr, "%s error: resolver threads cannot exceed %d\n", argv[0],
            MAX_RESOLVER_THREADS);
    return EXIT_FAILURE;
  }
  double start_time = get_time_sec();
  array stack;
  array_init(&stack);
  struct requester_data req_data;
  struct resolver_data res_data;
  req_data.stack = &stack;
  res_data.stack = &stack;
  req_data.req_log = argv[3];
  res_data.res_log = argv[4];
  pthread_mutex_init(&res_data.res_log_lock, NULL);
  pthread_mutex_init(&req_data.req_log_lock, NULL);
  pthread_mutex_init(&res_data.term_lock, NULL);
  req_data.res_thread_cnt = res_thread_cnt;
  res_data.res_thread_cnt = res_thread_cnt;
  int total_files = argc - 5;
  char **filenames = (char **)malloc(total_files * sizeof(char *));
  for (int i = 5; i < argc; i++) {
    filenames[i - 5] = (char *)malloc((strlen(argv[i]) + 1) * sizeof(char));
    strcpy(filenames[i - 5], argv[i]);
  }
  req_data.input_filenames = filenames;
  req_data.total_files = total_files;
  static int file_idx = 0;
  pthread_mutex_init(&req_data.file_idx_lock, NULL);
  req_data.file_idx = &file_idx;
  pthread_t *requester_threads =
      (pthread_t *)malloc(req_thread_cnt * sizeof(pthread_t));
  pthread_t *resolver_threads =
      (pthread_t *)malloc(res_thread_cnt * sizeof(pthread_t));
  for (int i = 0; i < req_thread_cnt; i++)
    pthread_create(&requester_threads[i], NULL, requester, (void *)&req_data);
  for (int i = 0; i < res_thread_cnt; i++)
    pthread_create(&resolver_threads[i], NULL, resolver, (void *)&res_data);
  for (int i = 0; i < req_thread_cnt; i++)
    pthread_join(requester_threads[i], NULL);
  for (int i = 0; i < res_thread_cnt; i++)
    pthread_join(resolver_threads[i], NULL);
  pthread_mutex_destroy(&req_data.file_idx_lock);
  pthread_mutex_destroy(&req_data.req_log_lock);
  pthread_mutex_destroy(&res_data.res_log_lock);
  pthread_mutex_destroy(&res_data.term_lock);
  for (int i = 5; i < argc; i++)
    free(filenames[i - 5]);
  free(filenames);
  array_free(&stack);
  free(requester_threads);
  free(resolver_threads);
  double end_time = get_time_sec();
  printf("%s: total time is %f seconds\n", argv[0],
         (double)(end_time - start_time));
  return 0;
}

void *requester(void *a) {
  struct requester_data *data = (struct requester_data *)a;
  double start_time = get_time_sec();
  int files_serviced = 0;
  char hostname[MAX_NAME_LENGTH];
  FILE *input_file = NULL, *log_file = NULL;
  while (1) {
    pthread_mutex_lock(&data->file_idx_lock);
    int curr_file = *(data->file_idx);
    if (curr_file >= data->total_files) {
      pthread_mutex_unlock(&data->file_idx_lock);
      break;
    }
    (*data->file_idx)++;
    pthread_mutex_unlock(&data->file_idx_lock);
    input_file = fopen(data->input_filenames[curr_file], "r");
    if (!input_file) {
      perror("failed to open data file");
      return NULL;
    }
  }
  while (fgets(hostname, sizeof(hostname), input_file)) {
    hostname[strcspn(hostname, "\n")] = '\0';
    array_put(data->stack, hostname);
    pthread_mutex_lock(&data->req_log_lock);
    log_file = fopen(data->req_log, "a");
    fprintf(log_file, "%s\n", hostname);
    fclose(log_file);
    pthread_mutex_unlock(&data->req_log_lock);
  }
  fclose(input_file);
  files_serviced++;
  for (int i = 0; i < data->res_thread_cnt; i++)
    array_put(data->stack, NULL);
  double end_time = get_time_sec();
  printf("thread %lx serviced %d files in %f seconds\n", (long)pthread_self(),
         files_serviced, (double)(end_time - start_time));
  return NULL;
}

void *resolver(void *a) {
  struct resolver_data *data = (struct resolver_data *)a;
  double start_time = get_time_sec();
  int hosts_resolved = 0;
  char *hostname, ip_addr[MAX_IP_LENGTH];
  FILE *log_file;
  while (1) {
    array_get(data->stack, &hostname);
    if (!hostname) {
      pthread_mutex_lock(&data->term_lock);
      data->res_thread_cnt--;
      if (!data->res_thread_cnt) {
        pthread_mutex_unlock(&data->term_lock);
        break;
      }
      pthread_mutex_unlock(&data->term_lock);
      continue;
    }
    if (dnslookup(hostname, ip_addr, sizeof(ip_addr)))
      strcpy(ip_addr, "NOT_RESOLVED");
    pthread_mutex_lock(&data->res_log_lock);
    log_file = fopen(data->res_log, "a");
    fprintf(log_file, "%s, %s\n", hostname, ip_addr);
    fclose(log_file);
    pthread_mutex_unlock(&data->res_log_lock);
    hosts_resolved++;
  }
  double end_time = get_time_sec();
  printf("thread %lx resolved %d hosts in %f seconds\n", (long)pthread_self(),
         hosts_resolved, (double)(end_time - start_time));
  return NULL;
}

double get_time_sec(void) {
  struct timeval time;
  gettimeofday(&time, NULL);
  return time.tv_sec + (time.tv_usec / 1000000.0);
}