// Jack Sangdahl // CSCI3753 SP24 // PA6 Threaded Resolver #include "multi-lookup.h" #include "array.h" #include "util.h" #include int main(int argc, char **argv) { if (argc < 6) { fprintf(stderr, "usage: %s <# requester> <# resolver> \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); }