/** * @file supervisor.c * @author Ivaylo Ivanov 11777707 * @date 11.01.2018 * * @brief Supervisor program module. * * The supervisor sets up the shared memory and the semaphores and initializes the circular buffer required * for the communication with the generators. It then waits for the generators to write solutions to the * circular buffer. * The supervisor program takes no arguments. * Once initialization is complete, the supervisor reads the solutions from the circular buffer and remembers the best solution so far, i.e. the solution with the least edges. Every time a better solution than the * previous best solution is found, the supervisor writes the new solution to standard output. If a generator * writes a solution with 0 edges to the circular buffer, then the graph is acyclic and the supervisor terminates. Otherwise the supervisor keeps reading results from the circular buffer until it receives a SIGINT * or a SIGTERM signal. * Before terminating, the supervisor notifies all generators that they should terminate as well. This can * be done by setting a variable in the shared memory, which is checked by the generator processes before * writing to the buffer. The supervisor then unlinks all shared resources and exits. * * SYNOPSIS * supervisor * **/ #include "shared/shm.c" #include "shared/sem.c" #include "shared/structs.c" void clean_up(void); int main(int argc, char *argv[]) { if(argc > 1) { fprintf(stderr, "ERROR: Command takes no arguments"); exit(EXIT_FAILURE); } if(atexit(clean_up) != 0) { fprintf(stderr, "ERROR: Cannot set exit function\n"); exit(EXIT_FAILURE); } process_signal(); /// Open shared memory objects buffer_shmfd = create_shmfd(BUFF_SHM_NAME); truncate_shm(buffer_shmfd, BUFF_SIZE); circ_buffer = (buffer_t *)open_shm(buffer_shmfd, sizeof(buffer_t)); /// Open semaphores free_sem = open_sem(FREE_SEM_NAME, BUFF_SIZE, 0); use_sem = open_sem(USE_SEM_NAME, 0, 0); mutex = open_sem(MUTEX_NAME, 1, 0); int free_space = 0; int use_space = 0; int r_pos = 0; ///< Position of the circular buffer to read from circ_buffer -> best_arc_len = __INT8_MAX__; fb_arc_set_t fb_arc; while(terminate == false) { /// Get the values of the semaphores getval_sem(free_sem, &free_space); getval_sem(use_sem, &use_space); wait_sem(use_sem); /// Loop until we find a place that has been written to while(circ_buffer->sets[r_pos].valid == false) { r_pos = (r_pos + 1) % BUFF_SIZE; } /// Get the valid set and save it fb_arc = circ_buffer->sets[r_pos]; circ_buffer->sets[r_pos].valid = false; post_sem(free_sem); ///< Free the semaphore r_pos = (r_pos + 1) % BUFF_SIZE; ///< Increase read position if(fb_arc.edge_num == 0) { /// If the graph is acyclic, set the terminate flag puts("The graph is acyclic!"); signal_handler(SIGINT); } else if(fb_arc.edge_num < circ_buffer->best_arc_len) { /// Save ther best feedback arc length and print a solution circ_buffer -> best_arc_len = fb_arc.edge_num; printf("Solution with %d edges: ", circ_buffer -> best_arc_len); for(int i=0; i < fb_arc.edge_num; i++) { printf("%d-%d ", fb_arc.edges[i].u, fb_arc.edges[i].v); } printf("\n"); } } exit(EXIT_SUCCESS); } /** * @brief Function to that cleans up the resources * @details The function closes and destroys all semaphores, * closes and destroys all shared memory objects and * closes the file descriptors * @param none * @return none **/ void clean_up(void) { /// Close and destory semaphores close_sem(free_sem); close_sem(use_sem); close_sem(mutex); destroy_sem(FREE_SEM_NAME); destroy_sem(USE_SEM_NAME); destroy_sem(MUTEX_NAME); /// Close and destroy shared memory objects close_shm(circ_buffer, sizeof(buffer_t)); destroy_shm(BUFF_SHM_NAME, buffer_shmfd); }