From: Lukas Jiriste Date: Fri, 10 May 2024 06:52:38 +0000 (+0200) Subject: Copy the philo as a base for the bonus X-Git-Url: https://git.ljiriste.work/?a=commitdiff_plain;h=60f1edc5cf2c87b9edd7b65a6e9d8eb3f57fbe06;p=42%2Fphilosophers.git Copy the philo as a base for the bonus It may be easier to repurpose the code for the bonus. --- diff --git a/philo_bonus/Makefile b/philo_bonus/Makefile new file mode 100644 index 0000000..d2b2550 --- /dev/null +++ b/philo_bonus/Makefile @@ -0,0 +1,41 @@ +CC := gcc + +CFLAGS := -Wall -Wextra -Werror -Wpedantic +-std=c99 +NAME := philo + +INCDIR := . +SRCDIR := . +SRCS := main.c \ + philo.c \ + helpers.c \ + parsing.c \ + parsing_misc.c \ + pars_arg.c \ + inner_pars_arg.c \ + mem_management.c \ + mutex.c \ + +SRCS := $(addprefix $(SRCDIR)/, $(SRCS)) +OBJS := $(SRCS:%.c=%.o) +CFLAGS += $(addprefix -I, $(INCDIR)) + +all : $(NAME) + +debug : CFLAGS += -g +debug : $(NAME) + +$(NAME) : $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $@ + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean : + $(RM) $(OBJS) + +fclean : + $(RM) $(OBJS) $(NAME) + +re : fclean + $(MAKE) diff --git a/philo_bonus/helpers.c b/philo_bonus/helpers.c new file mode 100644 index 0000000..35f974a --- /dev/null +++ b/philo_bonus/helpers.c @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* helpers.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/09 09:13:40 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 11:59:36 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philo.h" +#include +#include + +int end(t_settings *set) +{ + int res; + + mutex_lock(&set->end_lock); + res = set->end; + mutex_unlock(&set->end_lock); + return (res); +} + +useconds_t usecs_since_start(struct timeval start) +{ + struct timeval time; + + gettimeofday(&time, NULL); + return ((time.tv_sec - start.tv_sec) * 1000000 + + time.tv_usec - start.tv_usec); +} + +void print_timestamp(t_philo *philo, const char *str) +{ + mutex_lock(&philo->settings->terminal_lock); + printf("%u %lu %s\n", usecs_since_start(philo->settings->start) + / 1000, philo->id, str); + mutex_unlock(&philo->settings->terminal_lock); + return ; +} + +int report(t_philo *philo, const char *str) +{ + if (!end(philo->settings)) + { + print_timestamp(philo, str); + return (0); + } + return (1); +} diff --git a/philo_bonus/inner_pars_arg.c b/philo_bonus/inner_pars_arg.c new file mode 100644 index 0000000..ac1b753 --- /dev/null +++ b/philo_bonus/inner_pars_arg.c @@ -0,0 +1,31 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* inner_pars_arg.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/28 11:35:59 by ljiriste #+# #+# */ +/* Updated: 2024/03/28 11:36:24 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parsing.h" +#include + +// Maybe this should be changed so that it only changes +// res when the parse is successful? +int inner_parse_arg(t_big_uint *res, const char *arg) +{ + char *tmp; + + *res = ft_atobui(arg); + tmp = ft_buitoa(*res); + if (!same_number(tmp, arg)) + { + free(tmp); + return (1); + } + free(tmp); + return (0); +} diff --git a/philo_bonus/main.c b/philo_bonus/main.c new file mode 100644 index 0000000..11c1ceb --- /dev/null +++ b/philo_bonus/main.c @@ -0,0 +1,131 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/22 11:19:48 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 12:31:31 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philo.h" +#include +#include +#include +#include + +static int seat_philosophers(t_diner *diner, pthread_t *threads) +{ + size_t i; + + gettimeofday(&diner->setting.start, NULL); + i = 0; + while (i < diner->setting.philo_count) + { + if (pthread_create(threads + i, NULL, + be_a_philosopher, diner->philos + i)) + { + mutex_lock(&diner->setting.end_lock); + diner->setting.end = 1; + mutex_unlock(&diner->setting.end_lock); + while (i > 0) + { + pthread_join(threads[--i], NULL); + } + return (1); + } + ++i; + } + return (0); +} + +static int is_dead(t_philo *philo) +{ + mutex_lock(&philo->philo_lock); + if (usecs_since_start(philo->settings->start) - philo->last_eaten + > philo->settings->time_to_die) + { + mutex_unlock(&philo->philo_lock); + return (1); + } + mutex_unlock(&philo->philo_lock); + return (0); +} + +static int all_full(t_diner *diner) +{ + size_t i; + unsigned int min_eaten; + + if (!diner->setting.should_check_hunger) + return (0); + i = 0; + min_eaten = UINT_MAX; + while (i < diner->setting.philo_count) + { + mutex_lock(&diner->philos[i].philo_lock); + if (min_eaten > diner->philos[i].num_eaten) + min_eaten = diner->philos[i].num_eaten; + mutex_unlock(&diner->philos[i].philo_lock); + ++i; + } + return (min_eaten >= diner->setting.min_eat_num); +} + +static enum e_end watch_philosophers(t_diner *diner) +{ + size_t i; + + while (1) + { + i = 0; + while (i < diner->setting.philo_count) + { + if (is_dead(diner->philos + i)) + { + mutex_lock(&diner->setting.end_lock); + diner->setting.end = 1; + mutex_unlock(&diner->setting.end_lock); + print_timestamp(diner->philos + i, "died"); + return (death); + } + ++i; + } + if (all_full(diner)) + { + mutex_lock(&diner->setting.end_lock); + diner->setting.end = 1; + mutex_unlock(&diner->setting.end_lock); + return (well_fed); + } + } +} + +int main(int argc, char **argv) +{ + t_diner diner; + pthread_t *threads; + enum e_end res; + + if (parse_input(&diner.setting, argc, argv)) + { + return (1); + } + if (init(&diner, &threads)) + { + cleanup(&diner, threads); + return (2); + } + if (seat_philosophers(&diner, threads)) + { + cleanup(&diner, threads); + return (3); + } + res = watch_philosophers(&diner); + cleanup(&diner, threads); + if (res == well_fed) + printf("All philosophers are well fed.\n"); + return (0); +} diff --git a/philo_bonus/mem_management.c b/philo_bonus/mem_management.c new file mode 100644 index 0000000..c459048 --- /dev/null +++ b/philo_bonus/mem_management.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* mem_management.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/28 09:39:55 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 12:41:33 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philo.h" +#include +#include +#include + +// Shortcircuiting does no harm here as when any mutex_init fails +// the program will end anyway. +int init(t_diner *diner, pthread_t **threads) +{ + const size_t count = diner->setting.philo_count; + size_t i; + + init_mutex(&diner->setting.terminal_lock, NULL); + init_mutex(&diner->setting.end_lock, NULL); + diner->philos = malloc(sizeof(*diner->philos) * count); + diner->forks = malloc(sizeof(*diner->forks) * count); + *threads = malloc(sizeof(**threads) * count); + if (!diner->philos || !diner->forks || !*threads) + return (1); + i = 0; + while (i < count) + { + init_mutex(diner->forks + i, NULL); + init_mutex(&diner->philos[i].philo_lock, NULL); + diner->philos[i].forks[i % 2] = diner->forks + i; + diner->philos[i].forks[(i + 1) % 2] = diner->forks + + (i + 1) % count; + diner->philos[i].settings = &diner->setting; + diner->philos[i].last_eaten = 0; + diner->philos[i].id = i + 1; + diner->philos[i].num_eaten = 0; + ++i; + } + return (!all_mutexes_initialized(diner)); +} + +void cleanup(t_diner *diner, pthread_t *threads) +{ + const size_t count = diner->setting.philo_count; + size_t i; + + i = 0; + if (diner->philos) + { + while (i < count) + { + pthread_join(threads[i], NULL); + destroy_mutex(&diner->philos[i++].philo_lock); + } + } + i = 0; + if (diner->forks) + while (i < count) + destroy_mutex(diner->forks + (i++)); + destroy_mutex(&diner->setting.terminal_lock); + destroy_mutex(&diner->setting.end_lock); + free(diner->philos); + free(diner->forks); + free(threads); + return ; +} diff --git a/philo_bonus/mutex.c b/philo_bonus/mutex.c new file mode 100644 index 0000000..6073e71 --- /dev/null +++ b/philo_bonus/mutex.c @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* mutex.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/28 10:35:16 by ljiriste #+# #+# */ +/* Updated: 2024/03/28 15:12:37 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philo.h" +#include + +int init_mutex(t_mutex *mutex, pthread_mutexattr_t *attr) +{ + mutex->is_init = !(pthread_mutex_init(&mutex->mutex, attr)); + return (mutex->is_init); +} + +void destroy_mutex(t_mutex *mutex) +{ + if (mutex->is_init) + pthread_mutex_destroy(&mutex->mutex); + mutex->is_init = 0; +} + +int mutex_lock(t_mutex *mutex) +{ + if (!mutex->is_init) + return (1); + return (pthread_mutex_lock(&mutex->mutex)); +} + +int mutex_unlock(t_mutex *mutex) +{ + if (!mutex->is_init) + return (1); + return (pthread_mutex_unlock(&mutex->mutex)); +} + +int all_mutexes_initialized(t_diner *diner) +{ + int res; + size_t i; + + res = 1; + res = res && diner->setting.terminal_lock.is_init; + res = res && diner->setting.end_lock.is_init; + i = 0; + while (i < diner->setting.philo_count) + { + res = res && diner->forks[i].is_init; + res = res && diner->philos[i].philo_lock.is_init; + ++i; + } + return (res); +} diff --git a/philo_bonus/pars_arg.c b/philo_bonus/pars_arg.c new file mode 100644 index 0000000..c9b7986 --- /dev/null +++ b/philo_bonus/pars_arg.c @@ -0,0 +1,84 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pars_arg.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/28 11:29:47 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 10:38:14 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parsing.h" +#include +#include + +int parse_arg_usec(useconds_t *res, const char *arg) +{ + t_big_uint tmp; + + if (inner_parse_arg(&tmp, arg)) + return (1); + tmp *= 1000; + if (tmp > (useconds_t)-1) + return (1); + *res = (useconds_t)tmp; + return (0); +} + +#if SIZE_MAX > UINT_MAX + +int parse_arg_size(size_t *res, const char *arg) +{ + t_big_uint tmp; + + if (inner_parse_arg(&tmp, arg)) + return (1); + if (tmp > (size_t)-1) + return (1); + *res = (size_t)tmp; + return (0); +} + +#else + +int parse_arg_size(size_t *res, const char *arg) +{ + t_big_uint tmp; + + if (inner_parse_arg(&tmp, arg)) + return (1); + *res = (size_t)tmp; + return (0); +} + +#endif //SIZE_MAX > UINT_MAX + +#if UINT_MAX > SIZE_MAX + +int parse_arg_uint(unsigned int *res, const char *arg) +{ + t_big_uint tmp; + + if (inner_parse_arg(&tmp, arg)) + return (1); + if (tmp > (unsigned int)-1) + return (1); + *res = (unsigned int)tmp; + return (0); +} + +#else + +int parse_arg_uint(unsigned int *res, const char *arg) +{ + t_big_uint tmp; + + if (inner_parse_arg(&tmp, arg)) + return (1); + *res = (unsigned int)tmp; + return (0); +} + +#endif //UINT_MAX > SIZE_MAX diff --git a/philo_bonus/parsing.c b/philo_bonus/parsing.c new file mode 100644 index 0000000..ec9a39f --- /dev/null +++ b/philo_bonus/parsing.c @@ -0,0 +1,43 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parsing.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/26 09:31:35 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 12:35:58 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parsing.h" +#include "philo.h" +#include +#include + +int is_sane(t_settings *settings) +{ + return (settings->philo_count > 0); +} + +int parse_input(t_settings *settings, int argc, char **argv) +{ + if (argc != 5 && argc != 6) + return (1); + settings->end = 0; + settings->should_check_hunger = 0; + if (parse_arg_size(&settings->philo_count, argv[1]) + || parse_arg_usec(&settings->time_to_die, argv[2]) + || parse_arg_usec(&settings->time_to_eat, argv[3]) + || parse_arg_usec(&settings->time_to_sleep, argv[4])) + { + return (1); + } + if (argc == 6) + { + if (parse_arg_uint(&settings->min_eat_num, argv[5])) + return (1); + settings->should_check_hunger = 1; + } + return (!is_sane(settings)); +} diff --git a/philo_bonus/parsing.h b/philo_bonus/parsing.h new file mode 100644 index 0000000..727331e --- /dev/null +++ b/philo_bonus/parsing.h @@ -0,0 +1,45 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parsing.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/28 11:24:41 by ljiriste #+# #+# */ +/* Updated: 2024/03/28 11:40:04 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PARSING_H +# define PARSING_H + +# include +# include +# include + +// This done to make parsing easier/non-repetitive +// but it cannot be a part of parsing.c as more files depend on it +// +// This assumes useconds_t is not the biggest type +// The assumption is made because it is not easy to check +# if SIZE_MAX > UINT_MAX + +typedef size_t t_big_uint; + +# else + +typedef unsigned int t_big_uint; + +# endif //SIZE_MAX > UINT_MAX + +t_big_uint ft_atobui(const char *str); +char *ft_buitoa(t_big_uint num); +int same_number(const char *num1, const char *num2); + +int inner_parse_arg(t_big_uint *res, const char *arg); + +int parse_arg_usec(useconds_t *res, const char *arg); +int parse_arg_size(size_t *res, const char *arg); +int parse_arg_uint(unsigned int *res, const char *arg); + +#endif //PARSING_H diff --git a/philo_bonus/parsing_misc.c b/philo_bonus/parsing_misc.c new file mode 100644 index 0000000..747648a --- /dev/null +++ b/philo_bonus/parsing_misc.c @@ -0,0 +1,75 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parsing_misc.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/26 10:42:02 by ljiriste #+# #+# */ +/* Updated: 2024/03/28 11:53:49 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "parsing.h" +#include + +t_big_uint ft_atobui(const char *str) +{ + t_big_uint res; + + res = 0; + if (!str) + return (res); + while (*str == ' ' || *str == '+') + ++str; + while ('0' <= *str && *str <= '9') + { + res *= 10; + res += *str - '0'; + ++str; + } + return (res); +} + +char *ft_buitoa(t_big_uint num) +{ + char *res; + size_t size; + t_big_uint tmp; + + tmp = num; + size = 0; + while (tmp > 0) + { + ++size; + tmp /= 10; + } + if (size == 0) + size = 1; + res = malloc(size + 1); + if (!res) + return (NULL); + res[size--] = '\0'; + if (num == 0) + res[0] = '0'; + while (num > 0) + { + res[size--] = '0' + num % 10; + num /= 10; + } + return (res); +} + +int same_number(const char *num1, const char *num2) +{ + while (*num1 == ' ' || *num1 == '+' || *num1 == '0') + ++num1; + while (*num2 == ' ' || *num2 == '+' || *num2 == '0') + ++num2; + while (*num1 && *num2 && *num1 == *num2) + { + ++num1; + ++num2; + } + return (!((int)*num1 - (int)*num2)); +} diff --git a/philo_bonus/philo.c b/philo_bonus/philo.c new file mode 100644 index 0000000..6dfa0fb --- /dev/null +++ b/philo_bonus/philo.c @@ -0,0 +1,61 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/09 08:45:21 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 10:25:46 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "philo.h" +#include + +static void philo_think(t_philo *philo) +{ + report(philo, "is thinking"); + return ; +} + +static void philo_eat(t_philo *philo) +{ + mutex_lock(philo->forks[0]); + if (report(philo, "has taken a fork")) + { + mutex_unlock(philo->forks[0]); + return ; + } + mutex_lock(philo->forks[1]); + report(philo, "has taken a fork"); + mutex_lock(&philo->philo_lock); + philo->last_eaten = usecs_since_start(philo->settings->start); + ++philo->num_eaten; + mutex_unlock(&philo->philo_lock); + if (!report(philo, "is eating")) + usleep(philo->settings->time_to_eat); + mutex_unlock(philo->forks[0]); + mutex_unlock(philo->forks[1]); + return ; +} + +static void philo_sleep(t_philo *philo) +{ + if (!report(philo, "is sleeping")) + usleep(philo->settings->time_to_sleep); + return ; +} + +void *be_a_philosopher(void *void_philo) +{ + t_philo *const philo = void_philo; + + while (!end(philo->settings)) + { + philo_think(philo); + philo_eat(philo); + philo_sleep(philo); + } + return (NULL); +} diff --git a/philo_bonus/philo.h b/philo_bonus/philo.h new file mode 100644 index 0000000..ad3ffc9 --- /dev/null +++ b/philo_bonus/philo.h @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* philo.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/03/22 11:10:17 by ljiriste #+# #+# */ +/* Updated: 2024/05/09 12:21:57 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PHILO_H +# define PHILO_H + +# include +# include +# include +# include + +typedef struct s_mutex +{ + int is_init; + pthread_mutex_t mutex; +} t_mutex; + +// The .start member holds the result of gettimeofday +// Every other member that holds time info counts +// microseconds from that point (in other structures also) +typedef struct s_settings +{ + int end; + int should_check_hunger; + unsigned int min_eat_num; + useconds_t time_to_die; + useconds_t time_to_eat; + useconds_t time_to_sleep; + size_t philo_count; + struct timeval start; + t_mutex terminal_lock; + t_mutex end_lock; +} t_settings; + +typedef struct s_philosopher +{ + unsigned int num_eaten; + size_t id; + useconds_t last_eaten; + t_settings *settings; + t_mutex *forks[2]; + t_mutex philo_lock; +} t_philo; + +typedef struct s_diner +{ + t_settings setting; + t_philo *philos; + t_mutex *forks; +} t_diner; + +enum e_end +{ + death, + well_fed, +}; + +int parse_input(t_settings *settings, int argc, char **argv); + +int init(t_diner *diner, pthread_t **threads); +void cleanup(t_diner *diner, pthread_t *threads); + +int init_mutex(t_mutex *mutex, pthread_mutexattr_t *attr); +void destroy_mutex(t_mutex *mutex); +int mutex_lock(t_mutex *mutex); +int mutex_unlock(t_mutex *mutex); +int all_mutexes_initialized(t_diner *diner); + +int end(t_settings *set); +useconds_t usecs_since_start(struct timeval start); +int report(t_philo *philo, const char *str); +void print_timestamp(t_philo *philo, const char *str); + +void *be_a_philosopher(void *philo); + +#endif //PHILO_H