mirror of
https://gitlab.com/klmp200/LO41.git
synced 2024-11-25 18:44:20 +00:00
commit
9ccec46143
@ -2,18 +2,45 @@
|
|||||||
// Created by Antoine Bartuccio on 05/06/2018.
|
// Created by Antoine Bartuccio on 05/06/2018.
|
||||||
//
|
//
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
#include "Building.h"
|
#include "Building.h"
|
||||||
#include "../Resident/Resident.h"
|
#include "../Resident/Resident.h"
|
||||||
#include "../Visitor/Visitor.h"
|
#include "../Visitor/Visitor.h"
|
||||||
|
|
||||||
#define LINE_BUFFER 256
|
#define LINE_BUFFER 256
|
||||||
|
|
||||||
|
SYNCHRONIZED_GETTER(Building, int*, waiting_floors)
|
||||||
|
|
||||||
void remove_end_char(char * string, char character){
|
void remove_end_char(char * string, char character){
|
||||||
size_t string_size = strlen(string);
|
size_t string_size = strlen(string);
|
||||||
if (string[string_size - 1] == character)
|
if (string[string_size - 1] == character)
|
||||||
string[string_size - 1] = '\0';
|
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<FLOORS; i++){
|
||||||
|
if(waiting_floors[i] > 0){
|
||||||
|
if(abs(elevator_floor - i) < best_diff){
|
||||||
|
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(char * line, char * separator){
|
||||||
List * split = NEW(List);
|
List * split = NEW(List);
|
||||||
char * to_delete = strdup(line);
|
char * to_delete = strdup(line);
|
||||||
@ -118,6 +145,12 @@ void _free__Building(THIS(Building)){
|
|||||||
pthread_mutex_unlock(this->mutex_func_get_inside_elevator);
|
pthread_mutex_unlock(this->mutex_func_get_inside_elevator);
|
||||||
pthread_mutex_destroy(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);
|
||||||
|
|
||||||
DELETE(this->residents);
|
DELETE(this->residents);
|
||||||
DELETE(this->visitors);
|
DELETE(this->visitors);
|
||||||
for (i=0; i<ELEVATOR_NB; i++)
|
for (i=0; i<ELEVATOR_NB; i++)
|
||||||
@ -130,6 +163,7 @@ void _free__Building(THIS(Building)){
|
|||||||
free(this->mutex_cond_get_inside_elevator);
|
free(this->mutex_cond_get_inside_elevator);
|
||||||
free(this->mutex_cond_get_outside_elevator);
|
free(this->mutex_cond_get_outside_elevator);
|
||||||
free(this->mutex_func_get_inside_elevator);
|
free(this->mutex_func_get_inside_elevator);
|
||||||
|
free(this->mutex_func_get_next_call);
|
||||||
free(this->elevators);
|
free(this->elevators);
|
||||||
|
|
||||||
free(this);
|
free(this);
|
||||||
@ -142,17 +176,14 @@ void _free__Building(THIS(Building)){
|
|||||||
* @passenger the passenger to put in 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
|
* @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 get_inside_elevator_Building(THIS(Building), int current_floor, Passenger * passenger){
|
||||||
int i;
|
int i;
|
||||||
/* Make assumption that a waiting elevator is not full */
|
/* Make assumption that a waiting elevator is not full */
|
||||||
pthread_mutex_lock(this->mutex_func_get_inside_elevator);
|
pthread_mutex_lock(this->mutex_func_get_inside_elevator);
|
||||||
printf("Test d'entrée à l'étage %d de %s : id %d\n", current_floor, passenger.visitor->name, passenger.visitor->id);
|
printf("Test d'entrée à l'étage %d de %s : id %d\n", current_floor, passenger->get_name(passenger), passenger->get_id(passenger));
|
||||||
for (i=0; i<ELEVATOR_NB; i++){
|
for (i=0; i<ELEVATOR_NB; i++){
|
||||||
if (this->elevators[i]->can_get_inside(this->elevators[i], current_floor)){
|
if (this->elevators[i]->can_get_inside(this->elevators[i], current_floor)){
|
||||||
/* pour faire taire le compilateur le temps que je revienne sur cette fonction */
|
|
||||||
//if (passenger.type == VISITOR) TODO : ???
|
|
||||||
this->elevators[i]->add_passenger(this->elevators[i], passenger);
|
this->elevators[i]->add_passenger(this->elevators[i], passenger);
|
||||||
/* Il faut faire des trucs ici */
|
|
||||||
pthread_mutex_unlock(this->mutex_func_get_inside_elevator);
|
pthread_mutex_unlock(this->mutex_func_get_inside_elevator);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -161,36 +192,28 @@ int get_inside_elevator_Building(THIS(Building), int current_floor, Passenger pa
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void go_to_floor_Building(THIS(Building), int origin, int destination, Passenger passenger){
|
void go_to_floor_Building(THIS(Building), int origin, int destination, Passenger * passenger){
|
||||||
int elevator_number;
|
int elevator_number;
|
||||||
|
|
||||||
if (origin < 0 || origin >= FLOORS) {CRASH("You are trying to start from a non existing floor\n");}
|
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");}
|
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_cond_wait(this->condition_floors[origin], this->mutex_cond_get_inside_elevator);
|
pthread_cond_wait(this->condition_floors[origin], this->mutex_cond_get_inside_elevator);
|
||||||
|
|
||||||
elevator_number = this->get_inside_elevator(this, origin, passenger);
|
elevator_number = this->get_inside_elevator(this, origin, passenger);
|
||||||
|
|
||||||
if (elevator_number != -1){ //passenger accepted in elevator
|
if (elevator_number != -1){ //passenger accepted in elevator
|
||||||
if (passenger.type == RESIDENT)
|
this->waiting_floors[origin]--;//on retire de la liste des attentes
|
||||||
printf("Le résident %s rentre dans l'ascenseur %s depuis l'étage %d\n", passenger.resident->name,
|
|
||||||
this->elevators[elevator_number]->name, origin);
|
|
||||||
else if (passenger.type == VISITOR)
|
|
||||||
printf("Le visiteur %s rentre dans l'ascenseur %s depuis l'étage %d\n", passenger.visitor->name,
|
|
||||||
this->elevators[elevator_number]->name, origin);
|
|
||||||
|
|
||||||
pthread_cond_wait(this->condition_floors[destination], this->mutex_cond_get_outside_elevator);
|
pthread_cond_wait(this->condition_floors[destination], this->mutex_cond_get_outside_elevator);
|
||||||
if (passenger.type == RESIDENT)
|
this->elevators[elevator_number]->remove_passenger(this->elevators[elevator_number], passenger);
|
||||||
printf("Le résident %s sort de l'ascenseur %s à l'étage %d\n", passenger.resident->name,
|
|
||||||
this->elevators[elevator_number]->name, destination);
|
|
||||||
else if (passenger.type == VISITOR)
|
|
||||||
printf("Le visiteur %s sort de l'ascenseur %s à l'étage %d\n", passenger.visitor->name,
|
|
||||||
this->elevators[elevator_number]->name, destination);
|
|
||||||
}else{
|
}else{
|
||||||
if (passenger.type == RESIDENT)
|
if (passenger->type == RESIDENT)
|
||||||
printf("Le résident %s à l'étage %d n'a pas pu rentrer dans un ascenseur. Préempté !\n", passenger.resident->name, origin);
|
printf("Le résident %s à l'étage %d n'a pas pu rentrer dans un ascenseur. Préempté !\n", passenger->get_name(passenger), origin);
|
||||||
else if (passenger.type == VISITOR)
|
else if (passenger->type == VISITOR)
|
||||||
printf("Le visiteur %s à l'étage %d n'a pas pu rentrer dans un ascenseur. Préempté !\n", passenger.visitor->name, origin);
|
printf("Le visiteur %s à l'étage %d n'a pas pu rentrer dans un ascenseur. Préempté !\n", passenger->get_name(passenger), origin);
|
||||||
}//todo : else, remettre en attente ?
|
//reloading fire
|
||||||
|
this->go_to_floor(this, origin, destination, passenger);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,17 +236,23 @@ Building *_init_Building(char * residents_file, char * visitors_file){
|
|||||||
Building * new_building = malloc_or_die(sizeof(Building));
|
Building * new_building = malloc_or_die(sizeof(Building));
|
||||||
char elevator_name[] = "@";
|
char elevator_name[] = "@";
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
new_building->floors = FLOORS;
|
new_building->floors = FLOORS;
|
||||||
|
|
||||||
|
for (i=0; i<FLOORS; i++)
|
||||||
|
new_building->waiting_floors[i] = 0;
|
||||||
|
pthread_mutex_init(&new_building->mutex_waiting_floors, NULL);
|
||||||
|
|
||||||
new_building->elevators = malloc_or_die(sizeof(Elevator*) * ELEVATOR_NB);
|
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_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_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_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_inside_elevator, NULL);
|
||||||
pthread_mutex_init(new_building->mutex_cond_get_outside_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_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->condition_floors = malloc_or_die(sizeof(pthread_cond_t*) * FLOORS);
|
||||||
new_building->residents = NEW(List);
|
new_building->residents = NEW(List);
|
||||||
@ -240,12 +269,14 @@ Building *_init_Building(char * residents_file, char * visitors_file){
|
|||||||
|
|
||||||
|
|
||||||
LINK_ALL(Building, new_building,
|
LINK_ALL(Building, new_building,
|
||||||
parse_residents,
|
parse_residents,
|
||||||
parse_visitors,
|
parse_visitors,
|
||||||
get_inside_elevator,
|
get_inside_elevator,
|
||||||
use_call_box,
|
use_call_box,
|
||||||
go_to_floor,
|
go_to_floor,
|
||||||
signal_elevator_at_floor
|
get_next_call,
|
||||||
|
get_waiting_floors,
|
||||||
|
signal_elevator_at_floor
|
||||||
)
|
)
|
||||||
|
|
||||||
if (residents_file != NULL)
|
if (residents_file != NULL)
|
||||||
|
@ -17,22 +17,27 @@
|
|||||||
|
|
||||||
typedef struct o_Building {
|
typedef struct o_Building {
|
||||||
PRIVATE int floors;
|
PRIVATE int floors;
|
||||||
|
PRIVATE int waiting_floors[FLOORS];
|
||||||
PRIVATE List * residents;
|
PRIVATE List * residents;
|
||||||
PRIVATE List * visitors;
|
PRIVATE List * visitors;
|
||||||
PRIVATE Elevator ** elevators;
|
PRIVATE Elevator ** elevators;
|
||||||
|
PRIVATE pthread_mutex_t mutex_waiting_floors;
|
||||||
PRIVATE pthread_mutex_t * mutex_cond_get_inside_elevator;
|
PRIVATE pthread_mutex_t * mutex_cond_get_inside_elevator;
|
||||||
PRIVATE pthread_mutex_t * mutex_cond_get_outside_elevator;
|
PRIVATE pthread_mutex_t * mutex_cond_get_outside_elevator;
|
||||||
PRIVATE pthread_mutex_t * mutex_func_get_inside_elevator;
|
PRIVATE pthread_mutex_t * mutex_func_get_inside_elevator;
|
||||||
|
PRIVATE pthread_mutex_t * mutex_func_get_next_call;
|
||||||
PRIVATE pthread_cond_t ** condition_floors;
|
PRIVATE pthread_cond_t ** condition_floors;
|
||||||
|
|
||||||
PRIVATE void (*parse_residents)(_THIS(Building), char * file);
|
PRIVATE void (*parse_residents)(_THIS(Building), char * file);
|
||||||
PRIVATE void (*parse_visitors)(_THIS(Building), char * file);
|
PRIVATE void (*parse_visitors)(_THIS(Building), char * file);
|
||||||
PRIVATE int (*get_inside_elevator)(_THIS(Building), int current_floor, Passenger passenger);
|
PRIVATE int (*get_inside_elevator)(_THIS(Building), int current_floor, Passenger * passenger);
|
||||||
|
|
||||||
PUBLIC int (*use_call_box)(_THIS(Building), char * resident_name);
|
PUBLIC int (*use_call_box)(_THIS(Building), char * resident_name);
|
||||||
PUBLIC void (*signal_elevator_at_floor)(_THIS(Building), int floor);
|
PUBLIC void (*signal_elevator_at_floor)(_THIS(Building), int floor);
|
||||||
|
PUBLIC int (*get_next_call)(_THIS(Building), int elevator_floor);
|
||||||
|
PUBLIC int* (*get_waiting_floors)(_THIS(Building));
|
||||||
|
|
||||||
SYNCHRONIZE PUBLIC void (*go_to_floor)(_THIS(Building), int origin, int destination, Passenger passenger);
|
SYNCHRONIZE PUBLIC void (*go_to_floor)(_THIS(Building), int origin, int destination, Passenger * passenger);
|
||||||
|
|
||||||
DESTRUCTOR(Building);
|
DESTRUCTOR(Building);
|
||||||
} Building;
|
} Building;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "Elevator.h"
|
#include "Elevator.h"
|
||||||
#include "../SharedData/SharedData.h"
|
#include "../SharedData/SharedData.h"
|
||||||
|
|
||||||
@ -29,17 +30,35 @@ void _free__Elevator(THIS(Elevator)){
|
|||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_passenger_Elevator(THIS(Elevator), Passenger passenger){
|
void add_passenger_Elevator(THIS(Elevator), Passenger * passenger){
|
||||||
pthread_mutex_lock(&this->mutex_passengers);
|
pthread_mutex_lock(&this->mutex_passengers);
|
||||||
this->passengers->insert_tail(this->passengers, ((void *)&passenger), sizeof(Passenger));
|
this->passengers->insert_tail(this->passengers, ((void *)passenger), sizeof(Passenger));
|
||||||
printf("L'ascenseur %s recoit le visiteur %s\nIl y a maintenant %d passagers dans l'ascenseur %s\n", this->name,
|
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.type == VISITOR ? passenger.visitor->get_name(passenger.visitor) : passenger.resident->get_name(passenger.resident),
|
passenger->get_name(passenger),
|
||||||
this->passengers->get_size(this->passengers), this->name);
|
this->get_floor(this),
|
||||||
|
this->passengers->get_size(this->passengers), this->name);
|
||||||
if (this->passengers->get_size(this->passengers) >= MAX_ELEVATOR_CAPACITY)
|
if (this->passengers->get_size(this->passengers) >= MAX_ELEVATOR_CAPACITY)
|
||||||
this->set_state(this, SLEEPING);
|
this->set_state(this, SLEEPING);
|
||||||
pthread_mutex_unlock(&this->mutex_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("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 get_number_of_passengers_Elevator(THIS(Elevator)){
|
||||||
int num;
|
int num;
|
||||||
pthread_mutex_lock(&this->mutex_passengers);
|
pthread_mutex_lock(&this->mutex_passengers);
|
||||||
@ -51,10 +70,10 @@ int get_number_of_passengers_Elevator(THIS(Elevator)){
|
|||||||
/**
|
/**
|
||||||
* 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.
|
* 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
|
* @THIS(Elevator) a pointer the current Elevator
|
||||||
* @return the found floor as an int. If no passengers are in the elevator, returns 0 ( as the elevator should come back to floor 0 ).
|
* @return the found floor as an int. If no passengers are in the elevator, returns -1.
|
||||||
* @todo should consider passenger calling the elevator
|
* @todo should consider passenger calling the elevator
|
||||||
*/
|
*/
|
||||||
int get_next_floor_Elevator(THIS(Elevator)){
|
int get_next_passenger_stop_Elevator(THIS(Elevator)){
|
||||||
int i, next_floor, temp_floor;
|
int i, next_floor, temp_floor;
|
||||||
float min_diff;
|
float min_diff;
|
||||||
Element* temp_element;
|
Element* temp_element;
|
||||||
@ -63,13 +82,13 @@ int get_next_floor_Elevator(THIS(Elevator)){
|
|||||||
pthread_mutex_lock(&this->mutex_floor);
|
pthread_mutex_lock(&this->mutex_floor);
|
||||||
|
|
||||||
min_diff = INFINITY;
|
min_diff = INFINITY;
|
||||||
next_floor = 0;
|
next_floor = -1;
|
||||||
|
|
||||||
for(i=0;i<this->passengers->get_size(this->passengers);i++){
|
for(i=0;i<this->passengers->get_size(this->passengers);i++){
|
||||||
temp_element = this->passengers->get_element(this->passengers, i);
|
temp_element = this->passengers->get_element(this->passengers, i);
|
||||||
temp_passenger = (Passenger*) temp_element->get_data(temp_element);
|
temp_passenger = (Passenger*) temp_element->get_data(temp_element);
|
||||||
temp_floor = temp_passenger->type == RESIDENT ? temp_passenger->resident->destination : temp_passenger->visitor->destination;
|
temp_floor = temp_passenger->get_destination(temp_passenger);
|
||||||
if(abs(this->floor - temp_floor) < min_diff && temp_floor != this->floor){
|
if(abs(this->floor - temp_floor) < min_diff /*&& temp_floor != this->floor*/){
|
||||||
min_diff = abs(this->floor - temp_floor);
|
min_diff = abs(this->floor - temp_floor);
|
||||||
next_floor = temp_floor;
|
next_floor = temp_floor;
|
||||||
}
|
}
|
||||||
@ -105,13 +124,31 @@ void *runnable_Elevator(void * void_this){
|
|||||||
/* This is where the thread logic will be implemented */
|
/* This is where the thread logic will be implemented */
|
||||||
Elevator * this = (Elevator*) void_this;
|
Elevator * this = (Elevator*) void_this;
|
||||||
SharedData * data = GET_INSTANCE(SharedData);
|
SharedData * data = GET_INSTANCE(SharedData);
|
||||||
|
Building * building = data->main_building;
|
||||||
|
|
||||||
|
int next_call;
|
||||||
|
int next_passenger_stop;
|
||||||
|
|
||||||
AGENT_OPTIONS
|
AGENT_OPTIONS
|
||||||
|
|
||||||
printf("Je suis l'ascenseur %s\n", this->name);
|
printf("Initialisation de l'ascenseur %s\n", this->name);
|
||||||
for (;;){
|
for (;;){
|
||||||
data->main_building->signal_elevator_at_floor(data->main_building, this->get_floor(this));
|
building->signal_elevator_at_floor(data->main_building, this->get_floor(this));
|
||||||
this->set_floor(this, this->get_next_floor(this));
|
if(this->target_floor == this->get_floor(this)){
|
||||||
|
if((next_passenger_stop = this->get_next_passenger_stop(this)) != -1){
|
||||||
|
this->target_floor = next_passenger_stop;
|
||||||
|
}else if((next_call = building->get_next_call(building, this->floor)) != -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;
|
return NULL;
|
||||||
@ -121,21 +158,23 @@ Elevator *_init_Elevator(char * name){
|
|||||||
Elevator * new_elevator = malloc_or_die(sizeof(Elevator));
|
Elevator * new_elevator = malloc_or_die(sizeof(Elevator));
|
||||||
new_elevator->name = strdup(name);
|
new_elevator->name = strdup(name);
|
||||||
new_elevator->passengers = NEW(List);
|
new_elevator->passengers = NEW(List);
|
||||||
|
new_elevator->target_floor = 0;
|
||||||
pthread_mutex_init(&new_elevator->mutex_passengers, NULL);
|
pthread_mutex_init(&new_elevator->mutex_passengers, NULL);
|
||||||
pthread_mutex_init(&new_elevator->mutex_state, NULL);
|
pthread_mutex_init(&new_elevator->mutex_state, NULL);
|
||||||
pthread_mutex_init(&new_elevator->mutex_floor, NULL);
|
pthread_mutex_init(&new_elevator->mutex_floor, NULL);
|
||||||
|
|
||||||
LINK_ALL(Elevator, new_elevator,
|
LINK_ALL(Elevator, new_elevator,
|
||||||
runnable,
|
runnable,
|
||||||
get_number_of_passengers,
|
get_number_of_passengers,
|
||||||
get_next_floor,
|
get_next_passenger_stop,
|
||||||
can_get_inside,
|
can_get_inside,
|
||||||
add_passenger,
|
remove_passenger,
|
||||||
get_state,
|
add_passenger,
|
||||||
set_state,
|
get_state,
|
||||||
get_floor,
|
set_state,
|
||||||
set_floor,
|
get_floor,
|
||||||
repair
|
set_floor,
|
||||||
|
repair
|
||||||
);
|
);
|
||||||
|
|
||||||
new_elevator->set_floor(new_elevator, 0);
|
new_elevator->set_floor(new_elevator, 0);
|
||||||
|
@ -20,6 +20,7 @@ typedef struct o_Elevator {
|
|||||||
PRIVATE List * passengers;
|
PRIVATE List * passengers;
|
||||||
PRIVATE char * name;
|
PRIVATE char * name;
|
||||||
PRIVATE int floor;
|
PRIVATE int floor;
|
||||||
|
PRIVATE int target_floor;
|
||||||
PRIVATE pthread_mutex_t mutex_passengers;
|
PRIVATE pthread_mutex_t mutex_passengers;
|
||||||
PRIVATE pthread_mutex_t mutex_state;
|
PRIVATE pthread_mutex_t mutex_state;
|
||||||
PRIVATE pthread_mutex_t mutex_floor;
|
PRIVATE pthread_mutex_t mutex_floor;
|
||||||
@ -28,11 +29,12 @@ typedef struct o_Elevator {
|
|||||||
|
|
||||||
SYNCHRONIZE PRIVATE void (*set_state)(_THIS(Elevator), ELEVATOR_STATE var);
|
SYNCHRONIZE PRIVATE void (*set_state)(_THIS(Elevator), ELEVATOR_STATE var);
|
||||||
SYNCHRONIZE PRIVATE void (*set_floor)(_THIS(Elevator), int var);
|
SYNCHRONIZE PRIVATE void (*set_floor)(_THIS(Elevator), int var);
|
||||||
SYNCHRONIZE PRIVATE int (*get_next_floor)(_THIS(Elevator));
|
SYNCHRONIZE PRIVATE int (*get_next_passenger_stop)(_THIS(Elevator));
|
||||||
|
|
||||||
SYNCHRONIZE PUBLIC void (*repair)(_THIS(Elevator));
|
SYNCHRONIZE PUBLIC void (*repair)(_THIS(Elevator));
|
||||||
SYNCHRONIZE PUBLIC int (*get_number_of_passengers)(_THIS(Elevator));
|
SYNCHRONIZE PUBLIC int (*get_number_of_passengers)(_THIS(Elevator));
|
||||||
SYNCHRONIZE PUBLIC void (*add_passenger)(_THIS(Elevator), Passenger passenger);
|
SYNCHRONIZE PUBLIC void (*remove_passenger) (_THIS(Elevator), Passenger * passenger);
|
||||||
|
SYNCHRONIZE PUBLIC void (*add_passenger)(_THIS(Elevator), Passenger * passenger);
|
||||||
SYNCHRONIZE PUBLIC ELEVATOR_STATE (*get_state)(_THIS(Elevator));
|
SYNCHRONIZE PUBLIC ELEVATOR_STATE (*get_state)(_THIS(Elevator));
|
||||||
SYNCHRONIZE PUBLIC int (*get_floor)(_THIS(Elevator));
|
SYNCHRONIZE PUBLIC int (*get_floor)(_THIS(Elevator));
|
||||||
SYNCHRONIZE PUBLIC int (*can_get_inside)(_THIS(Elevator), int floor);
|
SYNCHRONIZE PUBLIC int (*can_get_inside)(_THIS(Elevator), int floor);
|
||||||
|
82
List/List.c
82
List/List.c
@ -140,6 +140,56 @@ void insert_inside_List(THIS(List), void * data, size_t data_size, int index){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove element with specified data in the list
|
||||||
|
* @param this THIS(List)
|
||||||
|
* @param data_to_remove pointer to data you want to remove
|
||||||
|
* @param compare a compare function, return true or false and takes two void * pointers
|
||||||
|
* @return true or false, depending on if the element was found in the list
|
||||||
|
*/
|
||||||
|
int remove_inside_List(THIS(List), void * data_to_remove, int (*compare)(void*, void*)){
|
||||||
|
Element* temp_element = this->head;
|
||||||
|
|
||||||
|
while(temp_element != NULL){
|
||||||
|
if(compare(data_to_remove, temp_element->data)){
|
||||||
|
if(temp_element == this->head){
|
||||||
|
this->remove_head(this);
|
||||||
|
}else if (temp_element == this->tail){
|
||||||
|
this->remove_tail(this);
|
||||||
|
}else{
|
||||||
|
if(temp_element->previous != NULL)
|
||||||
|
temp_element->previous->next = temp_element->next;
|
||||||
|
if(temp_element->next != NULL)
|
||||||
|
temp_element->next->previous = temp_element->previous;
|
||||||
|
DELETE(temp_element);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
temp_element = temp_element->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if data_to_find exist in list
|
||||||
|
* @param this THIS(List)
|
||||||
|
* @param data_to_find pointer to data you want to find inside
|
||||||
|
* @param compare a compare function, return true or false and takes two void * pointers
|
||||||
|
* @return true or false if the element is within the list or not
|
||||||
|
*/
|
||||||
|
int contains_List(THIS(List), void * data_to_find, int (*compare)(void *, void *)){
|
||||||
|
Element * current = this->head;
|
||||||
|
|
||||||
|
while (current != NULL){
|
||||||
|
if (compare(data_to_find, current->data)){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void remove_head_List(THIS(List)){
|
void remove_head_List(THIS(List)){
|
||||||
DELETE(this->head);
|
DELETE(this->head);
|
||||||
}
|
}
|
||||||
@ -156,21 +206,23 @@ List *_init_List(){
|
|||||||
l->custom_free = free;
|
l->custom_free = free;
|
||||||
|
|
||||||
LINK_ALL(List, l,
|
LINK_ALL(List, l,
|
||||||
get_head,
|
get_head,
|
||||||
get_tail,
|
get_tail,
|
||||||
get_size,
|
get_size,
|
||||||
get_head_data,
|
get_head_data,
|
||||||
get_tail_data,
|
get_tail_data,
|
||||||
get_element,
|
get_element,
|
||||||
get_element_data,
|
get_element_data,
|
||||||
set_custom_free,
|
set_custom_free,
|
||||||
insert_inside,
|
remove_inside,
|
||||||
insert_tail,
|
insert_inside,
|
||||||
insert_head,
|
insert_tail,
|
||||||
clear_custom,
|
insert_head,
|
||||||
clear,
|
clear_custom,
|
||||||
remove_head,
|
clear,
|
||||||
remove_tail
|
remove_head,
|
||||||
|
remove_tail,
|
||||||
|
contains
|
||||||
)
|
)
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ struct o_List {
|
|||||||
PUBLIC void* (*get_element_data)(_THIS(List), int index);
|
PUBLIC void* (*get_element_data)(_THIS(List), int index);
|
||||||
|
|
||||||
PUBLIC int (*get_size)(_THIS(List));
|
PUBLIC int (*get_size)(_THIS(List));
|
||||||
|
PUBLIC int (*contains)(_THIS(List), void * data_to_find, int (*compare)(void *, void *));
|
||||||
|
PUBLIC int (*remove_inside)(_THIS(List), void * data_to_remove, int (*compare)(void*, void*));
|
||||||
|
|
||||||
PUBLIC void (*set_custom_free)(_THIS(List), void (*custom_free)(void *));
|
PUBLIC void (*set_custom_free)(_THIS(List), void (*custom_free)(void *));
|
||||||
PUBLIC void (*insert_inside)(_THIS(List), void * data, size_t data_size, int index);
|
PUBLIC void (*insert_inside)(_THIS(List), void * data, size_t data_size, int index);
|
||||||
|
@ -4,6 +4,19 @@
|
|||||||
|
|
||||||
#include "Passenger.h"
|
#include "Passenger.h"
|
||||||
|
|
||||||
|
int compare_Passenger(void * passenger1, void * passenger2){
|
||||||
|
return (strcmp(((Passenger*) passenger1)->get_name((Passenger*) passenger1),
|
||||||
|
((Passenger*) passenger2)->get_name((Passenger*) passenger2)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_destination_Passenger(THIS(Passenger)){
|
||||||
|
if (this->type == RESIDENT)
|
||||||
|
return this->resident->get_destination(this->resident);
|
||||||
|
if (this->type == VISITOR)
|
||||||
|
return this->visitor->get_destination(this->visitor);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int get_id_Passenger(THIS(Passenger)){
|
int get_id_Passenger(THIS(Passenger)){
|
||||||
if (this->type == RESIDENT)
|
if (this->type == RESIDENT)
|
||||||
return this->resident->get_id(this->resident);
|
return this->resident->get_id(this->resident);
|
||||||
@ -33,22 +46,25 @@ void _free__Passenger(THIS(Passenger)){
|
|||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Passenger *_init_Passenger(void *passenger, PASSENGER_TYPE type){
|
Passenger *_init_Passenger(void* passenger_data, PASSENGER_TYPE type){
|
||||||
Passenger * new_passenger = malloc_or_die(sizeof(Passenger));
|
Passenger * new_passenger = malloc_or_die(sizeof(Passenger));
|
||||||
|
|
||||||
new_passenger->resident = NULL;
|
new_passenger->resident = NULL;
|
||||||
new_passenger->visitor = NULL;
|
new_passenger->visitor = NULL;
|
||||||
new_passenger->type = type;
|
new_passenger->type = type;
|
||||||
if (type == RESIDENT)
|
if (type == RESIDENT)
|
||||||
new_passenger->resident = (Resident*) passenger;
|
new_passenger->resident = (Resident*) passenger_data;
|
||||||
|
|
||||||
if (type == VISITOR)
|
if (type == VISITOR)
|
||||||
new_passenger->visitor = (Visitor*) passenger;
|
new_passenger->visitor = (Visitor*) passenger_data;
|
||||||
|
|
||||||
|
//new_passenger->compare = compare_Passenger;
|
||||||
LINK_ALL(Passenger, new_passenger,
|
LINK_ALL(Passenger, new_passenger,
|
||||||
get_id,
|
get_id,
|
||||||
get_name,
|
get_name,
|
||||||
runnable
|
get_destination,
|
||||||
|
compare,
|
||||||
|
runnable
|
||||||
)
|
)
|
||||||
|
|
||||||
return new_passenger;
|
return new_passenger;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "../Resident/Resident.h"
|
#include "../Resident/Resident.h"
|
||||||
#include "../Visitor/Visitor.h"
|
#include "../Visitor/Visitor.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
typedef enum {RESIDENT, VISITOR} PASSENGER_TYPE;
|
typedef enum {RESIDENT, VISITOR} PASSENGER_TYPE;
|
||||||
|
|
||||||
@ -19,11 +20,13 @@ typedef struct o_Passenger {
|
|||||||
|
|
||||||
PUBLIC char * (*get_name)(_THIS(Passenger));
|
PUBLIC char * (*get_name)(_THIS(Passenger));
|
||||||
PUBLIC int (*get_id)(_THIS(Passenger));
|
PUBLIC int (*get_id)(_THIS(Passenger));
|
||||||
|
PUBLIC int (*get_destination)(_THIS(Passenger));
|
||||||
PUBLIC void * (*runnable)(void* void_this);
|
PUBLIC void * (*runnable)(void* void_this);
|
||||||
|
PUBLIC int (*compare)(void * passenger1, void * passenger2);//yeah I know, but i needed int (*) (void*, void*)
|
||||||
|
|
||||||
DESTRUCTOR(Passenger);
|
DESTRUCTOR(Passenger);
|
||||||
} Passenger;
|
} Passenger;
|
||||||
|
|
||||||
Passenger *_init_Passenger(void *passenger, PASSENGER_TYPE type);
|
Passenger *_init_Passenger(void* passenger_data, PASSENGER_TYPE type);
|
||||||
|
|
||||||
#endif //LO41_PASSENGER_H
|
#endif //LO41_PASSENGER_H
|
||||||
|
@ -5,24 +5,35 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "Resident.h"
|
#include "Resident.h"
|
||||||
|
#include "../SharedData/SharedData.h"
|
||||||
|
|
||||||
GETTER(Resident, char *, name);
|
GETTER(Resident, char *, name);
|
||||||
|
GETTER(Resident, int, destination);
|
||||||
GETTER(Resident, int, id);
|
GETTER(Resident, int, id);
|
||||||
GETTER(Resident, int, apartment_floor);
|
GETTER(Resident, int, apartment_floor);
|
||||||
|
|
||||||
void * runnable_Resident(void * void_this){
|
void * runnable_Resident(void * void_this){
|
||||||
Resident * this = (Resident*) void_this;
|
Resident * this = (Resident*) void_this;
|
||||||
|
SharedData* data = GET_INSTANCE(SharedData);
|
||||||
|
Passenger * passenger = NEW(Passenger, (void*) this, RESIDENT);
|
||||||
|
|
||||||
AGENT_OPTIONS
|
AGENT_OPTIONS;
|
||||||
|
|
||||||
|
this->passenger = passenger;
|
||||||
|
passenger->resident = this;
|
||||||
|
passenger->type = RESIDENT;
|
||||||
|
|
||||||
printf("Je suis le resident %s et je suis a l'etage %d en direction de l'etage %d\n",
|
printf("Je suis le resident %s et je suis a l'etage %d en direction de l'etage %d\n",
|
||||||
this->name, this->apartment_floor, this->destination);
|
this->name, this->apartment_floor, this->destination);
|
||||||
|
data->main_building->go_to_floor(data->main_building, this->position, this->destination, passenger);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _free__Resident(THIS(Resident)){
|
void _free__Resident(THIS(Resident)){
|
||||||
if (this->name != NULL)
|
if (this->name != NULL)
|
||||||
free(this->name);
|
free(this->name);
|
||||||
|
if(this->passenger != NULL)
|
||||||
|
free(this->passenger);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,12 +45,14 @@ Resident *_init_Resident(int id, char* name, int apartment_floor, int destinatio
|
|||||||
new_resident->apartment_floor = apartment_floor;
|
new_resident->apartment_floor = apartment_floor;
|
||||||
new_resident->position = new_resident->apartment_floor;
|
new_resident->position = new_resident->apartment_floor;
|
||||||
new_resident->destination = destination;
|
new_resident->destination = destination;
|
||||||
|
new_resident->passenger = NULL;
|
||||||
|
|
||||||
LINK_ALL(Resident, new_resident,
|
LINK_ALL(Resident, new_resident,
|
||||||
get_name,
|
get_name,
|
||||||
get_id,
|
get_destination,
|
||||||
runnable,
|
get_id,
|
||||||
get_apartment_floor
|
runnable,
|
||||||
|
get_apartment_floor
|
||||||
)
|
)
|
||||||
|
|
||||||
return new_resident;
|
return new_resident;
|
||||||
|
@ -13,11 +13,13 @@ typedef struct o_Resident {
|
|||||||
PRIVATE int destination;
|
PRIVATE int destination;
|
||||||
PRIVATE int position;
|
PRIVATE int position;
|
||||||
PRIVATE char* name;
|
PRIVATE char* name;
|
||||||
|
PRIVATE void* passenger;
|
||||||
|
|
||||||
PUBLIC void * (*runnable)(void * void_this);
|
PUBLIC void * (*runnable)(void * void_this);
|
||||||
PUBLIC char * (*get_name)(_THIS(Resident));
|
PUBLIC char * (*get_name)(_THIS(Resident));
|
||||||
PUBLIC int (*get_id)(_THIS(Resident));
|
PUBLIC int (*get_id)(_THIS(Resident));
|
||||||
PUBLIC int (*get_apartment_floor)(_THIS(Resident));
|
PUBLIC int (*get_apartment_floor)(_THIS(Resident));
|
||||||
|
PUBLIC int (*get_destination)(_THIS(Resident));
|
||||||
|
|
||||||
DESTRUCTOR(Resident);
|
DESTRUCTOR(Resident);
|
||||||
} Resident;
|
} Resident;
|
||||||
|
@ -7,17 +7,18 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
GETTER(Visitor, char*, name);
|
GETTER(Visitor, char*, name);
|
||||||
|
GETTER(Visitor, int, destination);
|
||||||
GETTER(Visitor, int, id);
|
GETTER(Visitor, int, id);
|
||||||
|
|
||||||
void * runnable_Visitor(void * void_this){
|
void * runnable_Visitor(void * void_this){
|
||||||
Visitor *this = (Visitor*) void_this;
|
Visitor *this = (Visitor*) void_this;
|
||||||
SharedData * data = GET_INSTANCE(SharedData);
|
SharedData * data = GET_INSTANCE(SharedData);
|
||||||
Passenger passenger;
|
Passenger * passenger = NEW(Passenger, (void*) this, VISITOR);
|
||||||
|
|
||||||
AGENT_OPTIONS
|
AGENT_OPTIONS;
|
||||||
|
this->passenger = (void*) passenger;
|
||||||
|
|
||||||
passenger.visitor = this;
|
passenger->visitor = this;
|
||||||
passenger.type = VISITOR;
|
|
||||||
|
|
||||||
printf("Bonjour, je suis %s et je souhaite rendre visite a %s\n", this->name, this->contact_name);
|
printf("Bonjour, je suis %s et je souhaite rendre visite a %s\n", this->name, this->contact_name);
|
||||||
printf("Bip, %s appel a l'interphone\n%s habite a l'etage %d\n", this->name, this->contact_name, (this->destination = data->use_call_box(data, this->contact_name)));
|
printf("Bip, %s appel a l'interphone\n%s habite a l'etage %d\n", this->name, this->contact_name, (this->destination = data->use_call_box(data, this->contact_name)));
|
||||||
@ -30,6 +31,8 @@ void _free__Visitor(THIS(Visitor)){
|
|||||||
free(this->name);
|
free(this->name);
|
||||||
if (this->contact_name != NULL)
|
if (this->contact_name != NULL)
|
||||||
free(this->contact_name);
|
free(this->contact_name);
|
||||||
|
if (this->passenger != NULL)
|
||||||
|
free(this->passenger);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +42,7 @@ Visitor *_init_Visitor(int id, char* name, char * contact_name){
|
|||||||
new_visitor->id = id;
|
new_visitor->id = id;
|
||||||
new_visitor->position = 0;
|
new_visitor->position = 0;
|
||||||
new_visitor->destination = -1;
|
new_visitor->destination = -1;
|
||||||
|
new_visitor->passenger = NULL;
|
||||||
|
|
||||||
if (contact_name != NULL)
|
if (contact_name != NULL)
|
||||||
new_visitor->contact_name = strdup(contact_name);
|
new_visitor->contact_name = strdup(contact_name);
|
||||||
@ -46,9 +50,10 @@ Visitor *_init_Visitor(int id, char* name, char * contact_name){
|
|||||||
new_visitor->contact_name = NULL;
|
new_visitor->contact_name = NULL;
|
||||||
|
|
||||||
LINK_ALL(Visitor, new_visitor,
|
LINK_ALL(Visitor, new_visitor,
|
||||||
get_name,
|
get_name,
|
||||||
get_id,
|
get_destination,
|
||||||
runnable
|
get_id,
|
||||||
|
runnable
|
||||||
);
|
);
|
||||||
|
|
||||||
return new_visitor;
|
return new_visitor;
|
||||||
|
@ -13,10 +13,12 @@ typedef struct o_Visitor {
|
|||||||
PRIVATE char * contact_name;
|
PRIVATE char * contact_name;
|
||||||
PRIVATE int position;
|
PRIVATE int position;
|
||||||
PRIVATE int destination;
|
PRIVATE int destination;
|
||||||
|
PRIVATE void * passenger;
|
||||||
|
|
||||||
PUBLIC void * (*runnable)(void* void_this);
|
PUBLIC void * (*runnable)(void* void_this);
|
||||||
PUBLIC char * (*get_name)(_THIS(Visitor));
|
PUBLIC char * (*get_name)(_THIS(Visitor));
|
||||||
PUBLIC int (*get_id)(_THIS(Visitor));
|
PUBLIC int (*get_id)(_THIS(Visitor));
|
||||||
|
PUBLIC int (*get_destination)(_THIS(Visitor));
|
||||||
|
|
||||||
DESTRUCTOR(Visitor);
|
DESTRUCTOR(Visitor);
|
||||||
} Visitor;
|
} Visitor;
|
||||||
|
Loading…
Reference in New Issue
Block a user