--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* main.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <marvin@42.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2024/03/05 12:49:40 by ljiriste #+# #+# */
+/* Updated: 2024/03/07 17:51:19 by ljiriste ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+
+// unsigned long would be more apropriate for min_eats_num
+// but for the ease of parsing I'm using size_t
+typedef struct s_settings
+{
+ int end;
+ size_t min_eats_num;
+ size_t philo_count;
+ suseconds_t time_to_die;
+ suseconds_t time_to_eat;
+ suseconds_t time_to_sleep;
+ suseconds_t program_start;
+ pthread_mutex_t terminal;
+} t_settings;
+
+typedef struct s_philo
+{
+ size_t times_eaten;
+ size_t id;
+ suseconds_t last_eaten;
+ pthread_mutex_t *forks[2];
+ t_settings *settings;
+} t_philo;
+
+suseconds_t cur_time_sus(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+void thread_print(t_settings *set, size_t id, const char *message)
+{
+ pthread_mutex_lock(&set->terminal);
+ if (set->end)
+ {
+ pthread_mutex_unlock(&set->terminal);
+ return ;
+ }
+ printf("%li %li %s\n", (cur_time_sus() - set->program_start) / 1000, id, message);
+ pthread_mutex_unlock(&set->terminal);
+ return ;
+}
+
+void philo_sleep(t_settings *set, size_t id)
+{
+ thread_print(set, id, "is sleeping");
+ usleep(set->time_to_sleep);
+ return ;
+}
+
+void philo_think(t_settings *set, size_t id)
+{
+ thread_print(set, id, "is thinking");
+ return ;
+}
+
+int philo_eat(t_philo *philo)
+{
+ pthread_mutex_lock(philo->forks[0]);
+ thread_print(philo->settings, philo->id, "has taken a fork");
+ pthread_mutex_lock(philo->forks[1]);
+ thread_print(philo->settings, philo->id, "has taken a fork");
+ thread_print(philo->settings, philo->id, "is eating");
+ philo->last_eaten = cur_time_sus();
+ usleep(philo->settings->time_to_eat);
+ pthread_mutex_unlock(philo->forks[0]);
+ pthread_mutex_unlock(philo->forks[1]);
+ return (0);
+}
+
+void *be_a_philosopher(void *inp)
+{
+ t_philo *philo;
+
+ philo = (t_philo *)inp;
+ philo->last_eaten = philo->settings->program_start;
+ while (!philo->settings->end)
+ {
+ philo_think(philo->settings, philo->id);
+ if (philo_eat(philo) == 1)
+ break ;
+ ++philo->times_eaten;
+ if (philo->times_eaten == philo->settings->min_eats_num)
+ return (NULL);
+ philo_sleep(philo->settings, philo->id);
+ }
+ return (NULL);
+}
+
+pthread_mutex_t *init_forks(size_t count)
+{
+ pthread_mutex_t *forks;
+
+ forks = malloc(sizeof(pthread_mutex_t) * count);
+ if (!forks)
+ return (NULL);
+ while (count > 0)
+ {
+ pthread_mutex_init(&forks[--count], NULL);
+ }
+ return (forks);
+}
+
+t_philo *build_philos(pthread_mutex_t *forks, t_settings *set)
+{
+ t_philo *philos;
+ size_t count;
+
+ if (!forks)
+ return (NULL);
+ count = set->philo_count;
+ philos = malloc(sizeof(t_philo) * count);
+ if (!philos)
+ return (NULL);
+ philos[0].forks[1] = forks + count - 1;
+ while (count > 0)
+ {
+ --count;
+ philos[count].id = count + 1;
+ philos->times_eaten = 0;
+ philos[count].settings = set;
+ philos[count].forks[0] = forks + count - count % 2;
+ if (count > 0)
+ philos[count].forks[1] = forks + count - (count + 1) % 2;
+ }
+ return philos;
+}
+
+size_t ft_atos(const char *str)
+{
+ size_t res;
+
+ res = 0;
+ while (*str == ' ')
+ ++str;
+ if (*str == '+')
+ ++str;
+ while ('0' <= *str && *str <= '9')
+ {
+ res *= 10;
+ res += *str - '0';
+ ++str;
+ }
+ return (res);
+}
+
+static size_t size_needed(int n)
+{
+ size_t res;
+
+ res = 1;
+ if (n == 0)
+ return (2);
+ if (n < 0)
+ ++res;
+ while (n != 0)
+ {
+ ++res;
+ n /= 10;
+ }
+ return (res);
+}
+
+char *ft_stoa(int n)
+{
+ size_t size;
+ char *res;
+
+ size = size_needed(n);
+ res = malloc(size * sizeof(char));
+ if (res == NULL)
+ return (res);
+ res[--size] = '\0';
+ if (n == 0 && res)
+ res[0] = '0';
+ else if (n < 0 && res)
+ {
+ res[0] = '-';
+ res[--size] = '0' - (n % 10);
+ n = -(n / 10);
+ }
+ while (n > 0 && res)
+ {
+ res[--size] = '0' + (n % 10);
+ n /= 10;
+ }
+ return (res);
+}
+
+int ft_strcmp(const char *s1, const char *s2)
+{
+ size_t i;
+
+ i = 0;
+ while (s1[i] == s2[i] && s1[i] && s2[i])
+ ++i;
+ return ((unsigned char)s1[i] - (unsigned char)s2[i]);
+}
+
+int parse_args(const char *arg, size_t *val)
+{
+ int res;
+ char *check_str;
+
+ *val = ft_atos(arg);
+ check_str = ft_stoa(*val);
+ while (*arg == ' ' || *arg == '+')
+ ++arg;
+ res = ft_strcmp(check_str, arg);
+ free(check_str);
+ return (res);
+}
+
+int parse_arg(const char *arg, suseconds_t *val)
+{
+ size_t tmp;
+
+ if (parse_args(arg, &tmp))
+ return (1);
+ *val = tmp;
+ if (*val != ((*val * 1000) / 1000))
+ return (1);
+ *val *= 1000;
+ return (0);
+}
+
+int parse_input(int argc, char **argv, t_settings *set)
+{
+ int res;
+
+ if (argc != 5 && argc != 6)
+ return (0);
+ res = 0;
+ res = res || parse_args(argv[1], &set->philo_count);
+ res = res || parse_arg(argv[2], &set->time_to_die);
+ res = res || parse_arg(argv[3], &set->time_to_eat);
+ res = res || parse_arg(argv[4], &set->time_to_sleep);
+ if (argc == 6)
+ res = res || parse_args(argv[5], &set->min_eats_num);
+ else
+ set->min_eats_num = 0;
+ return (res);
+}
+
+int init_settings(int argc, char **argv, t_settings *set)
+{
+ pthread_mutex_init(&set->terminal, NULL);
+ set->end = 0;
+ return (parse_input(argc, argv, set));
+}
+
+
+void cleanup(pthread_mutex_t *forks, t_philo *philos, pthread_t *threads, t_settings *set)
+{
+ size_t count;
+
+ count = set->philo_count;
+ while (count > 0)
+ {
+ --count;
+ pthread_mutex_destroy(&forks[count]);
+ }
+ pthread_mutex_destroy(&set->terminal);
+ free(forks);
+ free(philos);
+ free(threads);
+ return ;
+}
+
+void create_philos(t_philo *philos, pthread_t *threads, size_t count)
+{
+ while (count > 0)
+ {
+ --count;
+ pthread_create(threads + count, NULL, be_a_philosopher, philos + count);
+ }
+ return ;
+}
+
+void check_death(t_philo *philos, t_settings *set)
+{
+ suseconds_t oldest;
+ suseconds_t now;
+ size_t i;
+
+ while (1)
+ {
+ i = 0;
+ now = cur_time_sus();
+ while (i < set->philo_count)
+ {
+ oldest = philos[0].last_eaten;
+ if((now - philos[i].last_eaten) > set->time_to_die)
+ {
+ pthread_mutex_lock(&set->terminal);
+ printf("%li %lu %s\n", (cur_time_sus() - set->program_start) / 1000, i + 1, "died");
+ set->end = 1;
+ pthread_mutex_unlock(&set->terminal);
+ return ;
+ }
+ if (oldest > philos[i].last_eaten)
+ oldest = philos[i].last_eaten;
+ ++i;
+ }
+ now = cur_time_sus();
+ //usleep(now - oldest);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ t_settings settings;
+ pthread_mutex_t *forks;
+ pthread_t *threads;
+ t_philo *philos;
+
+ if (init_settings(argc, argv, &settings))
+ return (1);
+ threads = malloc(sizeof(pthread_t) * settings.philo_count);
+ forks = init_forks(settings.philo_count);
+ philos = build_philos(forks, &settings);
+ if (!forks || !threads || !philos)
+ {
+ cleanup(forks, philos, threads, &settings);
+ return (2);
+ }
+ settings.program_start = cur_time_sus();
+ create_philos(philos, threads, settings.philo_count);
+ usleep(settings.time_to_die / 10);
+ check_death(philos, &settings);
+ cleanup(forks, philos, threads, &settings);
+ return (0);
+}