1
0
mirror of https://gitlab.com/klmp200/LO41.git synced 2024-11-14 21:03:23 +00:00
LO41/Elevator/Elevator.c

194 lines
6.5 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)
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("L'ascenseur %s recoit le visiteur %s à l'étage %d\nIl y a maintenant %d passagers dans l'ascenseur %s\n", this->name,
passenger->get_name(passenger),
this->get_floor(this),
this->passengers->get_size(this->passengers), this->name);
/*if (this->passengers->get_size(this->passengers) >= MAX_ELEVATOR_CAPACITY)
this->set_state(this, SLEEPING);*/
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("Le résident %s sort de l'ascenseur %s à l'étage %d\n", passenger->get_name(passenger), this->name, this->get_floor(this));
else if (passenger->type == VISITOR)
printf("Le visiteur %s sort de l'ascenseur %s à l'étage %d\n", passenger->get_name(passenger), this->name, this->get_floor(this));
this->passengers->remove_inside(this->passengers, passenger, passenger->compare);
printf("Ascenseur %s : j'ai encore %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*/){
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 *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;
AGENT_OPTIONS
printf("Initialisation de l'ascenseur %s\n", this->name);
for (;;){
building->signal_elevator_at_floor(data->main_building, this->get_floor(this));
usleep(500000);
if(this->target_floor == this->get_floor(this)){
next_passenger_stop = this->get_next_passenger_stop(this);
next_call = building->get_next_call(building, this->floor);
if (!(next_passenger_stop == this->get_floor(this) || next_call == this->get_floor(this))){
printf("Ascenseur %s attends pour déposer ou prendre un pasager supplémentaire\n", this->name);
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 en route vers l'étage %d\n", this->name, this->target_floor);
/*printf("DEBUG : Next passenger stop : %d\n", next_passenger_stop);
printf("DEBUG : Next call from user : %d\n", next_call);
printf("\n\n");*/
fflush(stdout);
}
}
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;
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
);
new_elevator->set_floor(new_elevator, 0);
new_elevator->set_state(new_elevator, WAITING);
return new_elevator;
}