// Copyright 2021 Jeisson Hidalgo-Cespedes CC-BY-4 #include #include #include #include #include #include #include "common.h" #include "consumer.h" #include "producer.h" #include "simulation.h" int analyze_arguments(simulation_t* simulation, int argc, char* argv[]); int create_consumers_producers(simulation_t* simulation); int join_threads(size_t count, pthread_t* threads); simulation_t* simulation_create() { simulation_t* simulation = (simulation_t*) calloc(1, sizeof(simulation_t)); if (simulation) { simulation->unit_count = 0; simulation->producer_count = 0; simulation->consumer_count = 0; simulation->producer_min_delay = 0; simulation->producer_max_delay = 0; simulation->consumer_min_delay = 0; simulation->consumer_max_delay = 0; queue_init(&simulation->queue); simulation->next_unit = 0; simulation->consumed_count = 0; } return simulation; } void simulation_destroy(simulation_t* simulation) { assert(simulation); queue_destroy(&simulation->queue); free(simulation); } int simulation_run(simulation_t* simulation, int argc, char* argv[]) { int error = analyze_arguments(simulation, argc, argv); if (error == EXIT_SUCCESS) { unsigned int seed = 0; getrandom(&seed, sizeof(seed), GRND_NONBLOCK); srandom(seed); struct timespec start_time; clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time); error = create_consumers_producers(simulation); struct timespec finish_time; clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time); double elapsed = (finish_time.tv_sec - start_time.tv_sec) + (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9; printf("execution time: %.9lfs\n", elapsed); } return error; } int analyze_arguments(simulation_t* simulation, int argc, char* argv[]) { int error = EXIT_SUCCESS; if (argc == 8) { if (sscanf(argv[1], "%zu", &simulation->unit_count) != 1 || simulation->unit_count == 0) { fprintf(stderr, "error: invalid unit count\n"); error = ERR_UNIT_COUNT; } else if (sscanf(argv[2], "%zu", &simulation->producer_count) != 1 || simulation->producer_count == 0) { fprintf(stderr, "error: invalid producer count\n"); error = ERR_PRODUCER_COUNT; } else if (sscanf(argv[3], "%zu", &simulation->consumer_count) != 1 || simulation->consumer_count == 0) { fprintf(stderr, "error: invalid consumer count\n"); error = ERR_CONSUMER_COUNT; } else if (sscanf(argv[4], "%u", &simulation->producer_min_delay) != 1) { fprintf(stderr, "error: invalid min producer delay\n"); error = ERR_MIN_PROD_DELAY; } else if (sscanf(argv[5], "%u", &simulation->producer_max_delay) != 1) { fprintf(stderr, "error: invalid max producer delay\n"); error = ERR_MAX_PROD_DELAY; } else if (sscanf(argv[6], "%u", &simulation->consumer_min_delay) != 1) { fprintf(stderr, "error: invalid min consumer delay\n"); error = ERR_MIN_CONS_DELAY; } else if (sscanf(argv[7], "%u", &simulation->consumer_max_delay) != 1) { fprintf(stderr, "error: invalid max consumer delay\n"); error = ERR_MAX_CONS_DELAY; } } else { fprintf(stderr, "usage: producer_consumer buffer_capacity rounds" " producer_min_delay producer_max_delay" " consumer_min_delay consumer_max_delay\n"); error = ERR_NO_ARGS; } return error; } pthread_t* create_threads(size_t count, void*(*subroutine)(void*), void* data) { pthread_t* threads = (pthread_t*) calloc(count, sizeof(pthread_t)); if (threads) { for (size_t index = 0; index < count; ++index) { if (pthread_create(&threads[index], /*attr*/ NULL, subroutine, data) == EXIT_SUCCESS) { } else { fprintf(stderr, "error: could not create thread %zu\n", index); join_threads(index, threads); return NULL; } } } return threads; } int join_threads(size_t count, pthread_t* threads) { int error = EXIT_SUCCESS; for (size_t index = 0; index < count; ++index) { // todo: sum could not be right error += pthread_join(threads[index], /*value_ptr*/ NULL); } free(threads); return error; } int create_consumers_producers(simulation_t* simulation) { assert(simulation); int error = EXIT_SUCCESS; pthread_t* producers = create_threads(simulation->producer_count, produce , simulation); pthread_t* consumers = create_threads(simulation->consumer_count, consume , simulation); if (producers && consumers) { join_threads(simulation->producer_count, producers); join_threads(simulation->consumer_count, consumers); } else { fprintf(stderr, "error: could not create threads\n"); error = ERR_CREATE_THREAD; } return error; }