// // Created by Antoine Bartuccio on 05/06/2018. // #include #include #include #include "Elevator.h" #include "../SharedData/SharedData.h" SYNCHRONIZED_GETTER(Elevator, ELEVATOR_STATE, state) SYNCHRONIZED_SETTER(Elevator, ELEVATOR_STATE, state) SYNCHRONIZED_GETTER(Elevator, int, floor) SYNCHRONIZED_SETTER(Elevator, int, floor) SETTER(Elevator, int, thread_number); void _free__Elevator(THIS(Elevator)){ DELETE(this->passengers); if (this->name != NULL) free(this->name); pthread_mutex_unlock(&this->mutex_passengers); pthread_mutex_destroy(&this->mutex_passengers); pthread_mutex_unlock(&this->mutex_state); pthread_mutex_destroy(&this->mutex_state); pthread_mutex_unlock(&this->mutex_floor); pthread_mutex_destroy(&this->mutex_floor); free(this); } void add_passenger_Elevator(THIS(Elevator), Passenger * passenger){ pthread_mutex_lock(&this->mutex_passengers); this->passengers->insert_tail(this->passengers, ((void *)passenger), sizeof(Passenger)); printf("Ascenseur %s : Je recoit le passager %s à l'étage %d\nAscenseur %s : J'ai désormais %d passager(s) à mon bord\n", this->name, passenger->get_name(passenger), this->get_floor(this), this->name, this->passengers->get_size(this->passengers)); pthread_mutex_unlock(&this->mutex_passengers); } /** * Remove a passenger from an elevator. Efectively remove him from the elevator's passenger list. * @SYNCHRONIZED passengers : this elevator's list of passenger is accessed via mutex * @param THIS(Elevator) : this * @param passenger : the passenger to remove */ void remove_passenger_Elevator(THIS(Elevator), Passenger * passenger){ pthread_mutex_lock(&this->mutex_passengers); if (passenger->type == RESIDENT) printf("Ascenseur %s : Le résident %s sort à l'étage %d\n", this->name, passenger->get_name(passenger), this->get_floor(this)); else if (passenger->type == VISITOR) printf("Ascenseur %s : Le passager %s sort à l'étage %d\n", this->name, passenger->get_name(passenger), this->get_floor(this)); this->passengers->remove_inside(this->passengers, passenger, passenger->compare); printf("Ascenseur %s : Il reste encore à mon bord %d passagers\n", this->name, this->passengers->get_size(this->passengers)); pthread_mutex_unlock(&this->mutex_passengers); } int get_number_of_passengers_Elevator(THIS(Elevator)){ int num; pthread_mutex_lock(&this->mutex_passengers); num = this->passengers->get_size(this->passengers); pthread_mutex_unlock(&this->mutex_passengers); return num; } /** * Search the closest floor where the elevator should stop. In practice ( for now ), it means that this function returns the closest floor amongs it's passengers destinations. * @THIS(Elevator) a pointer the current Elevator * @return the found floor as an int. If no passengers are in the elevator, returns -1. * @todo should consider passenger calling the elevator */ int get_next_passenger_stop_Elevator(THIS(Elevator)){ int i, next_floor, temp_floor; float min_diff; Element* temp_element; Passenger* temp_passenger; pthread_mutex_lock(&this->mutex_passengers); pthread_mutex_lock(&this->mutex_floor); min_diff = INFINITY; next_floor = -1; for(i=0;ipassengers->get_size(this->passengers);i++){ temp_element = this->passengers->get_element(this->passengers, i); temp_passenger = (Passenger*) temp_element->get_data(temp_element); temp_floor = temp_passenger->get_destination(temp_passenger); if(abs(this->floor - temp_floor) < min_diff && temp_floor != this->floor/*beware*/){ min_diff = abs(this->floor - temp_floor); next_floor = temp_floor; } } pthread_mutex_unlock(&this->mutex_passengers); pthread_mutex_unlock(&this->mutex_floor); return next_floor; } int can_get_inside_Elevator(THIS(Elevator), int floor){ int permission; pthread_mutex_lock(&this->mutex_passengers); pthread_mutex_lock(&this->mutex_state); pthread_mutex_lock(&this->mutex_floor); permission = (this->passengers->get_size(this->passengers) < MAX_ELEVATOR_CAPACITY && /*this->state == WAITING &&*/ this->floor == floor); //if(this->floor != floor) //printf("DEBUG : Cause de la préemption : l'ascenseur %s n'est pas là !\n", this->name); pthread_mutex_unlock(&this->mutex_floor); pthread_mutex_unlock(&this->mutex_state); pthread_mutex_unlock(&this->mutex_passengers); return permission; } void repair_Elevator(THIS(Elevator)){ this->set_state(this, RUNNING); } void damage_Elevator(THIS(Elevator)){ this->set_state(this, BROKEN); } void *runnable_Elevator(void * void_this){ /* This is where the thread logic will be implemented */ Elevator * this = (Elevator*) void_this; SharedData * data = GET_INSTANCE(SharedData); Building * building = data->main_building; int next_call; int next_passenger_stop; int i; AGENT_OPTIONS printf("Ascenseur %s : Initialisation...\n", this->name); while (data->is_active_passengers_left(data)){ usleep(250000); if(this->target_floor == this->get_floor(this)){ pthread_mutex_lock(&this->mutex_passengers);//on débarque les passagers Element* temp_element = this->passengers->head; while(temp_element != NULL){ Passenger* temp_passenger = ((Passenger*) temp_element->data); if(temp_passenger->get_destination(temp_passenger) == this->get_floor(this)){ building->signal_elevator_at_floor(building, this->get_floor(this)); } temp_element = temp_element->next; } pthread_mutex_unlock(&this->mutex_passengers); for(i=0;iwaiting_floors[this->get_floor(this)];i++){ //on embarque les passagers building->signal_elevator_at_floor(building, this->get_floor(this)); } next_passenger_stop = this->get_next_passenger_stop(this); next_call = building->get_next_call(building, this->get_floor(this)); if(next_passenger_stop != -1){ this->target_floor = next_passenger_stop; }else if(next_call != -1){ this->target_floor = next_call; } } if(this->get_floor(this) != this->target_floor){ this->set_floor(this, this->target_floor); printf("Ascenseur %s : Je suis en route vers l'étage %d\n", this->name, this->target_floor); } } data->unregister_thread(data, this->thread_number); return NULL; } Elevator *_init_Elevator(char * name){ Elevator * new_elevator = malloc_or_die(sizeof(Elevator)); new_elevator->name = strdup(name); new_elevator->passengers = NEW(List); new_elevator->target_floor = 0; new_elevator->thread_number = -1; pthread_mutex_init(&new_elevator->mutex_passengers, NULL); pthread_mutex_init(&new_elevator->mutex_state, NULL); pthread_mutex_init(&new_elevator->mutex_floor, NULL); LINK_ALL(Elevator, new_elevator, runnable, get_number_of_passengers, get_next_passenger_stop, can_get_inside, remove_passenger, add_passenger, get_state, set_state, get_floor, set_floor, repair, damage, set_thread_number ); new_elevator->set_floor(new_elevator, 0); new_elevator->set_state(new_elevator, WAITING); return new_elevator; }