mirror of
https://gitlab.com/klmp200/LO41.git
synced 2024-11-23 17:23:21 +00:00
219 lines
7.1 KiB
C
219 lines
7.1 KiB
C
//
|
|
// Created by Antoine Bartuccio on 05/06/2018.
|
|
//
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <unistd.h>
|
|
#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;i<this->passengers->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 == RUNNING && 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->get_state(this) == RUNNING){
|
|
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;i<building->waiting_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);
|
|
}
|
|
}else if(this->get_state(this) == BROKEN){
|
|
building->ask_elevator_reparation(building, this);
|
|
}else{
|
|
//CRASH("ERROR : Undefined behaviour\n");
|
|
}
|
|
|
|
}
|
|
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, RUNNING);
|
|
|
|
return new_elevator;
|
|
}
|