commit a37cbf88f3a1b3a78ea10cb4a957c6c211f2bc77 Author: Camille Chauvet Date: Thu Apr 13 13:00:39 2023 +0000 init diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..10ee4b8 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +SRCS = parsing.c \ + utils/ft_isnum.c \ + utils/ft_atoi.c \ + main.c \ + time.c \ + print.c \ + data.c \ + philo.c \ + philos.c \ + threads.c + +OBJS = ${SRCS:.c=.o} + +NAME = philo + +CC = clang + +FLAGS = -Wall -Wextra -Werror -g + +%.o: %.c + ${CC} ${FLAGS} -c -o $@ $< + +${NAME}: ${OBJS} + ${CC} ${OBJS} -o ${NAME} + +all: ${NAME} + +clean: + rm -f ${OBJS} + +fclean: clean + rm -f ${NAME} + +re: fclean + make all + +.PHONY: all clean fclean re diff --git a/data.c b/data.c new file mode 100644 index 0000000..9573ec1 --- /dev/null +++ b/data.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include "./data.h" +#include "philo.h" +#include "philos.h" +#include "struct.h" + +bool data_init(t_data *data) +{ + data->forks = malloc(sizeof(bool) * data->nb_philos); + if (data->forks == NULL) + return (1); + data->philos = malloc(sizeof(t_philo) * data->nb_philos); + if (data->philos == NULL) + { + free(data->forks); + return (1); + } + data->threads = malloc(sizeof(pthread_t) * data->nb_philos); + if (data->forks == NULL) + { + free(data->philos); + free(data->forks); + return (1); + } + data->stop = 0; + data->nb_meals = 0; + return (0); +} + +void data_destroyer(t_data *data) +{ + free(data->threads); + free(data->forks); + pthread_mutex_destroy(&data->nb_meal_mutex); + pthread_mutex_destroy(&data->forks_mutex); + pthread_mutex_destroy(&data->stop_mutex); + philos_destroyer(data); +} diff --git a/data.h b/data.h new file mode 100644 index 0000000..1f5604c --- /dev/null +++ b/data.h @@ -0,0 +1,5 @@ +# include "./struct.h" + +bool data_init(t_data *data); +void data_destroyer(t_data *data); + diff --git a/main.c b/main.c new file mode 100644 index 0000000..a2b15f8 --- /dev/null +++ b/main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include "./philos.h" +#include "./data.h" +#include "./parsing.h" +#include "./threads.h" +#include "./time.h" +#include "./print.h" +#include "./struct.h" + +size_t get_min_meal(t_data *data) +{ + size_t i; + size_t min; + size_t value; + t_philo *philo; + + philo = data->philos[0]; + min = philo->nb_meal; + i = 1; + while (i < data->nb_philos) + { + philo = data->philos[i]; + pthread_mutex_lock(&philo->nb_meal_mutex); + value = philo->nb_meal; + pthread_mutex_unlock(&philo->nb_meal_mutex); + if (min > value) + min = value; + i++; + } + return (min); +} + +void stop(t_data *data) +{ + pthread_mutex_lock(&data->stop_mutex); + data->stop = 1; + pthread_mutex_unlock(&data->stop_mutex); +} + +void check_routine(t_data *data) +{ + size_t i; + bool ok; + t_philo *philo; + + while (true) + { + if ((ssize_t) get_min_meal(data) == data->nb_meals) + stop(data); + + i = 0; + while (i < data->nb_philos) + { + philo = data->philos[i]; + pthread_mutex_lock(&philo->last_eat_mutex); + ok = !(philo->last_eat + data->life_expectency > get_time()); + pthread_mutex_unlock(&philo->last_eat_mutex); + if (ok == 1) + { + print_died(philo); + return ; + } + i++; + } + } +} + +int main(int ac, char **av) +{ + t_data data; + + if (parsing(&data, av + 1, ac - 1)) + return (1); + if (data_init(&data)) + return (1); + if (philos_init(&data)) + { + data_destroyer(&data); + return (1); + } + if (threads_init(&data)) + { + data_destroyer(&data); + return (1); + } + check_routine(&data); + data_destroyer(&data); +} diff --git a/parsing.c b/parsing.c new file mode 100644 index 0000000..773fd55 --- /dev/null +++ b/parsing.c @@ -0,0 +1,48 @@ +#include "utils/utils.h" +#include "./data.h" +#include +#include +#include + +static bool check_amount_of_argument(size_t n) +{ + return (n < 4 || n > 5); +} + +static bool check_value(char **av, size_t n) +{ + size_t i; + + i = 0; + while (i < n) + { + if (ft_isnum(av[i]) == 0) + return (1); + i++; + } + return (0); +} + +static void set_value(t_data *data, char **args, size_t n) +{ + data->nb_philos = ft_atoi(args[0]); + data->life_expectency = ft_atoi(args[1]); + data->eat_time = ft_atoi(args[2]); + data->sleep_time = ft_atoi(args[3]); + if (n == 5) + data->nb_meals = ft_atoi(args[4]); + else + data->nb_meals = -1; +} + +bool parsing(t_data *data, char **args, size_t n) +{ + if (check_amount_of_argument(n) + || check_value(args, n)) + { + write(2, "Argument error !\n", 16); + return (1); + } + set_value(data, args, n); + return (0); +} diff --git a/parsing.h b/parsing.h new file mode 100644 index 0000000..b817f98 --- /dev/null +++ b/parsing.h @@ -0,0 +1,4 @@ +#include "./data.h" + +bool parsing(t_data *data, char **args, size_t n); + diff --git a/philo.c b/philo.c new file mode 100644 index 0000000..f574fbc --- /dev/null +++ b/philo.c @@ -0,0 +1,114 @@ +#include "philo.h" +#include "struct.h" +#include "time.h" +#include "data.h" +#include +#include +#include +#include "./print.h" + +void philo_destroyer(t_philo *philo) +{ + pthread_mutex_destroy(&philo->nb_meal_mutex); + pthread_mutex_destroy(&philo->last_sleep_mutex); + pthread_mutex_destroy(&philo->last_eat_mutex); + free(philo); +} + +bool check(t_data *data) +{ + bool stop; + + pthread_mutex_lock(&data->stop_mutex); + stop = data->stop; + pthread_mutex_unlock(&data->stop_mutex); + return (stop); +} + +void eat(t_philo *philo, t_data *data) +{ + print_take_a_fork(philo); + print_take_a_fork(philo); + print_eating(philo); + usleep(data->eat_time * 1000); + pthread_mutex_lock(&philo->nb_meal_mutex); + philo->nb_meal++; + pthread_mutex_unlock(&philo->nb_meal_mutex); + pthread_mutex_lock(&data->forks_mutex); + data->forks[philo->id] = 1; + data->forks[(philo->id + 1) % (data->nb_philos) + 1] = 1; + pthread_mutex_unlock(&data->forks_mutex); +} + +bool philo_eat(t_philo *philo, t_data *data) +{ + bool left_fork; + bool right_fork; + + left_fork = 0; + right_fork = 0; + while (left_fork == 0 || right_fork == 0) + { + if (check(data)) + return (1); + pthread_mutex_lock(&data->forks_mutex); + left_fork = data->forks[philo->id]; + right_fork = data->forks[(philo->id + 1) % (data->nb_philos) + 1]; + if (right_fork && left_fork) + { + data->forks[philo->id] = !left_fork; + data->forks[(philo->id + 1) % (data->nb_philos) + 1] = !right_fork; + } + pthread_mutex_unlock(&data->forks_mutex); + } + eat(philo, data); + pthread_mutex_lock(&philo->last_eat_mutex); + philo->last_eat = get_time(); + pthread_mutex_unlock(&philo->last_eat_mutex); + return (0); +} + +void philo_sleep(t_data *data, t_philo *philo) +{ + print_sleeping(philo); + usleep(data->sleep_time * 1000); +} + + +void *philo_routine(void *arg) +{ + t_philo *philo; + t_data *data; + + philo = arg; + data = philo->data; + while (true) + { + print_thinking(philo); + check(data); + philo_eat(philo, data); + check(data); + print_thinking(philo); + if (check(data)) + return (NULL); + philo_sleep(data, philo); + } + return (NULL); +} + +t_philo *philo_init(t_data *data) +{ + t_philo *philo; + static size_t id = 0; + + philo = malloc(sizeof(t_philo)); + if (philo == NULL) + return (NULL); + philo->id = id++; + philo->data = data; + philo->nb_meal = 0; + pthread_mutex_init(&philo->nb_meal_mutex, NULL); + pthread_mutex_init(&philo->nb_meal_mutex, NULL); + pthread_mutex_init(&philo->nb_meal_mutex, NULL); + return (philo); +} diff --git a/philo.h b/philo.h new file mode 100644 index 0000000..7450b4e --- /dev/null +++ b/philo.h @@ -0,0 +1,22 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cchauvet +# include +# include +# include +# include "./data.h" + +t_philo *philo_init(t_data *data); +void philo_destroyer(t_philo *philo); +void *philo_routine(void *arg); + diff --git a/philos.c b/philos.c new file mode 100644 index 0000000..5708861 --- /dev/null +++ b/philos.c @@ -0,0 +1,39 @@ +#include "./philo.h" +#include "struct.h" +#include +#include + +int philos_init(t_data *data) +{ + size_t i; + + i = 0; + while (i < data->nb_philos) + { + data->philos[i] = philo_init(data); + if (data->philos[i] == NULL) + { + while (i > 0) + { + philo_destroyer(data->philos[i]); + i--; + } + return (1); + } + i++; + } + return (0); +} + +void philos_destroyer(t_data *data) +{ + size_t i; + + i = 0; + while (i < data->nb_philos) + { + philo_destroyer(data->philos[i]); + i++; + } + free(data->philos); +} diff --git a/philos.h b/philos.h new file mode 100644 index 0000000..1be6aa0 --- /dev/null +++ b/philos.h @@ -0,0 +1,5 @@ +# include +# include "./data.h" + +bool philos_init(t_data *data); +void philos_destroyer(t_data *data); diff --git a/print.c b/print.c new file mode 100644 index 0000000..f1a9904 --- /dev/null +++ b/print.c @@ -0,0 +1,41 @@ +#include "philo.h" +#include +#include +#include +#include "./time.h" + +static void print(size_t id, char *str) +{ + static pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER; + size_t time; + + time = get_time(); + pthread_mutex_lock(&print_mutex); + printf("%zu %zu %s\n", time, id, str); + pthread_mutex_unlock(&print_mutex); +} + +void print_take_a_fork(t_philo *philo) +{ + print(philo->id, "has taken a fork"); +} + +void print_eating(t_philo *philo) +{ + print(philo->id, "is eating"); +} + +void print_sleeping(t_philo *philo) +{ + print(philo->id, "is sleeping"); +} + +void print_thinking(t_philo *philo) +{ + print(philo->id, "is thinking"); +} + +void print_died(t_philo *philo) +{ + print(philo->id, "is died"); +} diff --git a/print.h b/print.h new file mode 100644 index 0000000..313fdbb --- /dev/null +++ b/print.h @@ -0,0 +1,7 @@ +# include "./philo.h" + +void print_eating(t_philo *philo); +void print_take_a_fork(t_philo *philo); +void print_sleeping(t_philo *philo); +void print_thinking(t_philo *philo); +void print_died(t_philo *philo); diff --git a/struct.h b/struct.h new file mode 100644 index 0000000..d42783f --- /dev/null +++ b/struct.h @@ -0,0 +1,38 @@ +#ifndef STRUCT_H +# define STRUCT_H +# include +# include +# include + +typedef struct s_data +{ + size_t eat_time; + size_t sleep_time; + size_t life_expectency; + size_t nb_philos; + ssize_t nb_meals; + void **philos; + pthread_t *threads; + pthread_mutex_t forks_mutex; + bool *forks; + pthread_mutex_t stop_mutex; + bool stop; +} t_data; + +typedef struct s_philo +{ + size_t id; + pthread_mutex_t nb_meal_mutex; + size_t nb_meal; + pthread_mutex_t last_eat_mutex; + size_t last_eat; + pthread_mutex_t last_sleep_mutex; + size_t last_sleep; + t_data *data; +} t_philo; + +t_philo *philo_create(t_data *data); +t_philo *philo_destoyer(t_philo *philo); +void *philo_routine(void *arg); + +#endif diff --git a/threads.c b/threads.c new file mode 100644 index 0000000..1677d9c --- /dev/null +++ b/threads.c @@ -0,0 +1,20 @@ +#include "philo.h" +#include "struct.h" +#include +#include +#include + +bool threads_init(t_data *data) +{ + size_t i; + + i = 0; + while (i < data->nb_philos) + { + if (pthread_create(&data->threads[i], NULL, philo_routine, data->philos[i])) + return (true); + pthread_detach(data->threads[i]); + i++; + } + return (false); +} diff --git a/threads.h b/threads.h new file mode 100644 index 0000000..4d14787 --- /dev/null +++ b/threads.h @@ -0,0 +1,6 @@ +# include "./data.h" +#include "struct.h" +# include + +bool threads_init(t_data *data); + diff --git a/time.c b/time.c new file mode 100644 index 0000000..b1b8cb7 --- /dev/null +++ b/time.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +size_t get_time(void) +{ + size_t timedefault = 0; + size_t time; + struct timeval tv; + + gettimeofday(&tv, NULL); + time = tv.tv_sec * 1000000 + tv.tv_usec; + if (timedefault == 0) + timedefault = time; + return ((time - timedefault) / 1000); +} diff --git a/time.h b/time.h new file mode 100644 index 0000000..c8c4cef --- /dev/null +++ b/time.h @@ -0,0 +1,3 @@ +# include + +size_t get_time(void); diff --git a/utils/ft_atoi.c b/utils/ft_atoi.c new file mode 100644 index 0000000..e8b20c1 --- /dev/null +++ b/utils/ft_atoi.c @@ -0,0 +1,39 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_atoi.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cchauvet + +int ft_atoi(const char *str) +{ + int out; + char sign; + size_t i; + + sign = 1; + i = 0; + while (str[i] == '-' || str[i]== '+') + { + if (str[i] == '-') + sign = -1; + if (str[i] == '+') + sign = 1; + i++; + } + out = 0; + while (str[i] >= '0' && str[i] <= '9') + { + out = out * 10 + str[i] - 48; + i++; + } + return (out * sign); +} diff --git a/utils/ft_isnum.c b/utils/ft_isnum.c new file mode 100644 index 0000000..f78e9ad --- /dev/null +++ b/utils/ft_isnum.c @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_isnum.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cchauvet '9' || str[i] < '0') + return (0); + i++; + } + return (1); +} diff --git a/utils/utils.h b/utils/utils.h new file mode 100644 index 0000000..28d5e05 --- /dev/null +++ b/utils/utils.h @@ -0,0 +1,21 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* utils.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cchauvet +# include + +bool ft_isnum(char str[]); +int ft_atoi(const char str[]); + +#endif