// // Created by Antoine Bartuccio on 05/06/2018. // #include #include #include #include "Building.h" #include "../Resident/Resident.h" #include "../Visitor/Visitor.h" #define LINE_BUFFER 256 SYNCHRONIZED_GETTER(Building, int*, waiting_floors) void remove_end_char(char * string, char character){ size_t string_size = strlen(string); if (string[string_size - 1] == character) string[string_size - 1] = '\0'; } /** * Get the best call for the elevator *@param THIS(Building) : this *@param elevator_floor : actual floor of the requesting elevator *@returns the closest floor where a client is calling as an int. If no client is calling, returns -1. */ int get_next_call_Building(THIS(Building), int elevator_floor){ pthread_mutex_lock(this->mutex_func_get_next_call); int* waiting_floors = this->get_waiting_floors(this); int i; float best_diff = INFINITY; int next_target = -1; for(i=0; i 0){ if(abs(elevator_floor - i) < best_diff && elevator_floor != i/*beware*/){ best_diff = abs(elevator_floor - i); next_target = i; } } } pthread_mutex_unlock(this->mutex_func_get_next_call); return next_target; } List * split(char * line, char * separator){ List * split = NEW(List); char * to_delete = strdup(line); char * to_delete_back = to_delete; char * token = NULL; while((token = strsep(&to_delete, separator)) != NULL) split->insert_tail(split, (void*) token, sizeof(char) * strlen(token)); free(to_delete_back); return split; } void parse_residents_Building(THIS(Building), char * file){ /* File format is name;appartment_floor;destination */ FILE * f = fopen(file, "r"); List * line_split = NULL; Resident * resident = NULL; size_t len = LINE_BUFFER; char * line = NULL; char * trash; int i = 0; if (f == NULL) { CRASH("File for residents does not exist"); } while (getline(&line, &len, f) > 0) { remove_end_char(line, '\n'); line_split = split(line, ";"); resident = NEW(Resident, i, line_split->get_element_data(line_split, 0), (int) strtol(line_split->get_element_data(line_split, 1), &trash, 10), (int) strtol(line_split->get_element_data(line_split, 2), &trash, 10)); this->residents->insert_tail(this->residents, resident, sizeof(Resident)); resident->name = NULL; DELETE(resident); DELETE(line_split); i++; } free(line); fclose(f); } void parse_visitors_Building(THIS(Building), char * file){ /* File format is name;contact_name */ FILE * f = fopen(file, "r"); List * line_split = NULL; Visitor * visitor = NULL; size_t len = LINE_BUFFER; char * line = NULL; int i = 0; if (f == NULL) { CRASH("File for visitors does not exist"); } while (getline(&line, &len, f) > 0) { remove_end_char(line, '\n'); line_split = split(line, ";"); visitor = NEW(Visitor, i, line_split->get_element_data(line_split, 0), line_split->get_element_data(line_split, 1)); this->visitors->insert_tail(this->visitors, visitor, sizeof(Visitor)); visitor->contact_name = NULL; visitor->name = NULL; DELETE(visitor); DELETE(line_split); i++; } free(line); fclose(f); } void free_resident(void* data){ Resident * r = (Resident *) data; DELETE(r); } void free_visitor(void* data){ Visitor * v = (Visitor *) data; DELETE(v); } void _free__Building(THIS(Building)){ int i = 0; this->residents->clear_custom(this->residents, free_resident); this->visitors->clear_custom(this->visitors, free_visitor); pthread_mutex_unlock(this->mutex_cond_get_inside_elevator); pthread_mutex_destroy(this->mutex_cond_get_inside_elevator); pthread_mutex_unlock(this->mutex_cond_get_outside_elevator); pthread_mutex_destroy(this->mutex_cond_get_outside_elevator); pthread_mutex_unlock(this->mutex_func_get_inside_elevator); pthread_mutex_destroy(this->mutex_func_get_inside_elevator); pthread_mutex_unlock(this->mutex_func_get_next_call); pthread_mutex_destroy(this->mutex_func_get_next_call); pthread_mutex_unlock(&this->mutex_waiting_floors); pthread_mutex_destroy(&this->mutex_waiting_floors); pthread_mutex_unlock(&this->mutex_repair); pthread_mutex_destroy(&this->mutex_repair); DELETE(this->residents); DELETE(this->visitors); for (i=0; ielevators[i]); for (i=0; icondition_floors[i]); free(this->condition_floors[i]); } free(this->condition_floors); free(this->mutex_cond_get_inside_elevator); free(this->mutex_cond_get_outside_elevator); free(this->mutex_func_get_inside_elevator); free(this->mutex_func_get_next_call); free(this->elevators); free(this); } /** * Tries to make @passenger enter an elevator, passenger being at @current_floor * @THIS(Building) * @current_floor the floor where the passenger is trying to enter the elevator * @passenger the passenger to put in the elevator * @returns an elevator number ( between 0 and ELEVATOR_NB - 1, inclusive ), -1 if no elevator was found ready to accept the passenger */ int get_inside_elevator_Building(THIS(Building), int current_floor, Passenger * passenger){ int i; /* Make assumption that a waiting elevator is not full */ pthread_mutex_lock(this->mutex_func_get_inside_elevator); printf("Passager %s : J'essaye de rentrer dans un ascenseur, à l'étage %d ( id : %d )\n", passenger->get_name(passenger), current_floor, passenger->get_id(passenger)); for (i=0; ielevators[i]->can_get_inside(this->elevators[i], current_floor)){ this->elevators[i]->add_passenger(this->elevators[i], passenger); pthread_mutex_unlock(this->mutex_func_get_inside_elevator); return i; } } pthread_mutex_unlock(this->mutex_func_get_inside_elevator); return -1; } void go_to_floor_Building(THIS(Building), int origin, int destination, Passenger * passenger){ int elevator_number; if (origin < 0 || origin >= FLOORS) {CRASH("You are trying to start from a non existing floor\n");} if (destination < 0 || destination >= FLOORS) {CRASH("You are trying to reach a non existing floor\n");} this->waiting_floors[origin]++;//on ajoute à la liste des attentes pthread_mutex_lock(this->mutex_cond_get_inside_elevator); pthread_cond_wait(this->condition_floors[origin], this->mutex_cond_get_inside_elevator); pthread_mutex_unlock(this->mutex_cond_get_inside_elevator); elevator_number = this->get_inside_elevator(this, origin, passenger); if (elevator_number != -1){ //passenger accepted in elevator this->waiting_floors[origin]--;//on retire de la liste des attentes pthread_mutex_lock(this->mutex_cond_get_outside_elevator); pthread_cond_wait(this->condition_floors[destination], this->mutex_cond_get_outside_elevator); pthread_mutex_unlock(this->mutex_cond_get_outside_elevator); this->elevators[elevator_number]->remove_passenger(this->elevators[elevator_number], passenger); }else{ if (passenger->type == RESIDENT) printf("Résident %s : L'ascenseur à l'étage %d était plein et je n'ai pas pu monter\n", passenger->get_name(passenger), origin); else if (passenger->type == VISITOR) printf("Visiteur %s : L'ascenseur à l'étage %d était plein et je n'ai pas pu monter\n", passenger->get_name(passenger), origin); //reloading fire this->waiting_floors[origin]--; this->go_to_floor(this, origin, destination, passenger); } } int use_call_box_Building(THIS(Building), char * resident_name){ /* Return negative number if not found */ Element * current = this->residents->get_head(this->residents); while (current != NULL){ if (!strcmp(((Resident *) current->get_data(current))->name, resident_name)) return ((Resident *) current->get_data(current))->apartment_floor; current = current->get_next(current); } return -1; } void signal_elevator_at_floor_Building(THIS(Building), int floor){ pthread_cond_signal(this->condition_floors[floor]); } void ask_elevator_reparation_Building(THIS(Building), Elevator* elevator){ printf("Technicien : l'ascenseur %s attend pour se faire réparer\n", elevator->name); pthread_mutex_lock(&this->mutex_repair); usleep(500000); elevator->repair(elevator); pthread_mutex_unlock(&this->mutex_repair); printf("Technicien : l'ascenseur %s est maintenant réparé\n", elevator->name); } Building *_init_Building(char * residents_file, char * visitors_file){ Building * new_building = malloc_or_die(sizeof(Building)); char elevator_name[] = "@"; int i; new_building->floors = FLOORS; for (i=0; iwaiting_floors[i] = 0; pthread_mutex_init(&new_building->mutex_waiting_floors, NULL); pthread_mutex_init(&new_building->mutex_repair, NULL); new_building->elevators = malloc_or_die(sizeof(Elevator*) * ELEVATOR_NB); new_building->mutex_cond_get_inside_elevator = malloc_or_die(sizeof(pthread_mutex_t)); new_building->mutex_cond_get_outside_elevator = malloc_or_die(sizeof(pthread_mutex_t)); new_building->mutex_func_get_inside_elevator = malloc_or_die(sizeof(pthread_mutex_t)); new_building->mutex_func_get_next_call = malloc_or_die(sizeof(pthread_mutex_t)); pthread_mutex_init(new_building->mutex_cond_get_inside_elevator, NULL); pthread_mutex_init(new_building->mutex_cond_get_outside_elevator, NULL); pthread_mutex_init(new_building->mutex_func_get_inside_elevator, NULL); pthread_mutex_init(new_building->mutex_func_get_next_call, NULL); new_building->condition_floors = malloc_or_die(sizeof(pthread_cond_t*) * FLOORS); new_building->residents = NEW(List); new_building->visitors = NEW(List); for (i=0; ielevators[i] = NEW(Elevator, elevator_name); } for (i=0; icondition_floors[i] = malloc_or_die((sizeof(pthread_cond_t))); pthread_cond_init(new_building->condition_floors[i], NULL); } LINK_ALL(Building, new_building, parse_residents, parse_visitors, get_inside_elevator, use_call_box, go_to_floor, get_next_call, get_waiting_floors, signal_elevator_at_floor, ask_elevator_reparation ) if (residents_file != NULL) new_building->parse_residents(new_building, residents_file); if (visitors_file != NULL) new_building->parse_visitors(new_building, visitors_file); return new_building; }