From 6d65af528815070dac9ec816524d5832a2e8da79 Mon Sep 17 00:00:00 2001 From: "Semere M. Mebrahtom" Date: Thu, 2 Apr 2026 19:53:23 +0200 Subject: [PATCH] mostly done; helgrind issue not fixed --- Makefile | 15 +-- coders/coder.c | 103 +++++++++++++++++++++ coders/codexion.h | 67 ++++++++++---- coders/heap.c | 26 +++--- coders/initialization.c | 85 +++++++++++++++++ coders/main.c | 196 +++------------------------------------- coders/monitor.c | 60 ++++++++++++ coders/schedulers.c | 28 ++++++ coders/utils.c | 32 ++++++- 9 files changed, 381 insertions(+), 231 deletions(-) create mode 100644 coders/coder.c create mode 100644 coders/initialization.c create mode 100644 coders/monitor.c create mode 100644 coders/schedulers.c diff --git a/Makefile b/Makefile index 7575f22..f3dd0a5 100644 --- a/Makefile +++ b/Makefile @@ -6,17 +6,10 @@ INCLUDES = coders/codexion.h OBJS = $(SRCS:.c=.o) CC = cc -CFLAGS = -Wall -Wextra -Werror -pthread -g -fsanitize=thread -# CFLAGS = -Wall -Wextra -Werror -# number_of_coders -# time_to_burnout -# time_to_compile -# time_to_debug -# time_to_refactor -# number_of_compiles_required -# dongle_cooldown -# scheduler -ARGS = 4 800 200 100 10 3 0 edf +# CFLAGS = -Wall -Wextra -Werror -pthread -g -fsanitize=thread +CFLAGS = -Wall -Wextra -Werror + +ARGS = 4 800 200 100 10 3 0 fifo all: $(NAME) diff --git a/coders/coder.c b/coders/coder.c new file mode 100644 index 0000000..3fa72d9 --- /dev/null +++ b/coders/coder.c @@ -0,0 +1,103 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* coder.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: semebrah +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */ +/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "codexion.h" +#include + +static void acquire_dongle(t_coder *coder, t_dongle *dongle) +{ + t_entry *entry; + long remaining; + + entry = malloc(sizeof(t_entry)); + entry->coder = coder; + entry->queued_at = now(); + pthread_mutex_lock(&coder->info_mutex); + entry->deadline = coder->last_compile + coder->state->args.time_to_burnout; + pthread_mutex_unlock(&coder->info_mutex); + pthread_mutex_lock(&dongle->condmutex); + enqueue(dongle->heap, entry); + while (((t_entry *)peek(dongle->heap))->coder != coder) + pthread_cond_wait(&dongle->cond, &dongle->condmutex); + remaining = (dongle->last_used + coder->state->args.dongle_cooldown) + - now(); + pthread_mutex_unlock(&dongle->condmutex); + if (remaining > 0) + usleep(remaining * 1000); + print("%ld %d has taken a dongle\n", coder->state, coder->idx); +} + +static void release_dongle(t_coder *coder, t_dongle *dongle) +{ + pthread_mutex_lock(&dongle->condmutex); + if (((t_entry *)peek(dongle->heap))->coder == coder) + { + dongle->last_used = now(); + free(dequeue(dongle->heap)); + pthread_cond_signal(&dongle->cond); + } + pthread_mutex_unlock(&dongle->condmutex); +} + +static void compile_op(t_coder *coder, t_state *state) +{ + t_dongle *first; + t_dongle *second; + + if (coder->right_dongle->idx < coder->left_dongle->idx) + { + first = coder->left_dongle; + second = coder->right_dongle; + } + else + { + first = coder->right_dongle; + second = coder->left_dongle; + } + acquire_dongle(coder, first); + acquire_dongle(coder, second); + pthread_mutex_lock(&coder->info_mutex); + coder->last_compile = now(); + coder->compiles_done += 1; + pthread_mutex_unlock(&coder->info_mutex); + print("%ld %d is compiling\n", state, coder->idx); + usleep(state->args.time_to_compile * 1000L); + release_dongle(coder, first); + release_dongle(coder, second); +} + +void *coder_routine(void *param) +{ + t_coder *coder; + t_state *state; + int i; + + coder = param; + state = coder->state; + i = 0; + while (i < state->args.compiles_todo) + { + if (is_over(state)) + return (NULL); + compile_op(coder, state); + if (is_over(state)) + return (NULL); + print("%ld %d is debugging\n", state, coder->idx); + usleep(state->args.time_to_debug * 1000L); + if (is_over(state)) + return (NULL); + print("%ld %d is refactoring\n", state, coder->idx); + usleep(state->args.time_to_refactor * 1000L); + i++; + } + return (NULL); +} diff --git a/coders/codexion.h b/coders/codexion.h index c872aba..9a80540 100644 --- a/coders/codexion.h +++ b/coders/codexion.h @@ -12,14 +12,24 @@ #ifndef CODEXION_H # define CODEXION_H + # include # include # include +# include + +# ifndef HEAP_SIZE +# define HEAP_SIZE 2 +# endif typedef struct s_state t_state; -typedef struct s_args t_args; -typedef struct s_dongle t_dongle; -typedef struct s_coder t_coder; + +typedef struct s_minheap +{ + int length; + void *array[HEAP_SIZE]; + int (*cmp)(void *, void *); +} t_minheap; typedef struct s_args { @@ -28,7 +38,7 @@ typedef struct s_args int time_to_compile; int time_to_debug; int time_to_refactor; - int number_of_compiles_required; + int compiles_todo; int dongle_cooldown; char *scheduler; } t_args; @@ -36,8 +46,10 @@ typedef struct s_args typedef struct s_dongle { int idx; - pthread_mutex_t lock; long last_used; + t_minheap *heap; + pthread_mutex_t condmutex; + pthread_cond_t cond; } t_dongle; typedef struct s_coder @@ -64,23 +76,44 @@ typedef struct s_state pthread_t monitor; } t_state; +typedef struct s_entry +{ + t_coder *coder; + long queued_at; + long deadline; +} t_entry; + +// utils.c +typedef struct s_state t_state; t_args *parse_arguments(int count, char **args); +long now(void); +void print(char *str, t_state *state, int coder_idx); + +// initialization.c +t_state init_state(t_args *args); +t_dongle *init_dongles(t_args *args, t_state *state); +t_coder *init_coders(t_args *args, t_state *state); +t_minheap *init_heap(int (*cmp)(void *, void *)); // heap.c -# ifndef HEAP_SIZE -# define HEAP_SIZE 25 -# endif - -typedef struct s_minheap -{ - int length; - void *array[HEAP_SIZE]; - int (*cmp)(void *, void *); -} t_minheap; - -t_minheap *init_heap(int (*cmp)(void *, void *)); void *peek(t_minheap *heap); void enqueue(t_minheap *heap, void *val); void *dequeue(t_minheap *heap); +// coder.c +void *coder_routine(void *param); + +// monitor.c +bool is_over(t_state *state); +void *monitor_routine(void *param); + +// schedulers.c +int fifo(void *t1, void *t2); +int edf(void *t1, void *t2); + +// main.c +int cleanup(t_args *args, t_coder *coders, + t_dongle *dongles); +int main(int argc, char **argv); + #endif diff --git a/coders/heap.c b/coders/heap.c index 1047322..db8ee8b 100644 --- a/coders/heap.c +++ b/coders/heap.c @@ -1,6 +1,16 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* heap.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: semebrah +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */ +/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */ +/* */ +/* ************************************************************************** */ + #include "codexion.h" -#include -#include static void sift_up(t_minheap *heap, int i, int (*cmp)(void *, void *)) { @@ -49,18 +59,6 @@ static void sift_down(t_minheap *heap, int i, int (*cmp)(void *, void *)) } } -t_minheap *init_heap(int (*cmp)(void *, void *)) -{ - t_minheap *heap; - - heap = malloc(sizeof(t_minheap)); - if (!heap) - return (NULL); - heap->length = 0; - heap->cmp = cmp; - return (heap); -} - void *peek(t_minheap *heap) { if (!heap || !heap->length) diff --git a/coders/initialization.c b/coders/initialization.c new file mode 100644 index 0000000..4658f85 --- /dev/null +++ b/coders/initialization.c @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* initialization.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: semebrah +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */ +/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "codexion.h" +#include +#include + +t_state init_state(t_args *args) +{ + t_state state; + + state.start = now(); + state.args = *args; + state.is_over = false; + pthread_mutex_init(&state.print_mutex, NULL); + pthread_mutex_init(&state.over_mutex, NULL); + return (state); +} + +t_dongle *init_dongles(t_args *args, t_state *state) +{ + int i; + t_dongle *dongles; + + dongles = malloc(sizeof(t_dongle) * args->number_of_coders); + if (!dongles) + return (NULL); + i = -1; + while (++i < args->number_of_coders) + { + dongles[i].idx = i; + pthread_mutex_init(&dongles[i].condmutex, NULL); + pthread_cond_init(&dongles[i].cond, NULL); + dongles[i].last_used = state->start - args->dongle_cooldown; + if (!strcmp(state->args.scheduler, "fifo")) + dongles[i].heap = init_heap(fifo); + else + dongles[i].heap = init_heap(edf); + } + return (dongles); +} + +t_coder *init_coders(t_args *args, t_state *state) +{ + t_coder *coders; + int i; + + coders = malloc(sizeof(t_coder) * args->number_of_coders); + if (!coders) + return (NULL); + i = -1; + while (++i < args->number_of_coders) + { + coders[i].idx = i; + coders[i].compiles_done = 0; + coders[i].last_compile = state->start; + coders[i].left_dongle = &state->dongles[i]; + coders[i].right_dongle = &state->dongles[(i + 1) + % args->number_of_coders]; + coders[i].state = state; + pthread_mutex_init(&coders[i].info_mutex, NULL); + } + return (coders); +} + +t_minheap *init_heap(int (*cmp)(void *, void *)) +{ + t_minheap *heap; + + heap = malloc(sizeof(t_minheap)); + if (!heap) + return (NULL); + heap->length = 0; + heap->cmp = cmp; + return (heap); +} diff --git a/coders/main.c b/coders/main.c index 2c1c211..25dbabf 100644 --- a/coders/main.c +++ b/coders/main.c @@ -13,201 +13,28 @@ #include "codexion.h" #include #include -#include #include #include #include -long now(void) -{ - struct timeval current; - - gettimeofday(¤t, NULL); - return (current.tv_sec * 1000L + current.tv_usec / 1000); -} - -void print(char *str, t_state *state, int coder_idx) -{ - pthread_mutex_lock(&state->print_mutex); - printf(str, now() - state->start, coder_idx + 1); - pthread_mutex_unlock(&state->print_mutex); -} - -bool is_over(t_state *state) -{ - bool is_over; - - pthread_mutex_lock(&state->over_mutex); - is_over = state->is_over; - pthread_mutex_unlock(&state->over_mutex); - return (is_over); -} - -void compile_op(t_coder *coder, t_state *state) -{ - t_dongle *first; - t_dongle *second; - - if (coder->right_dongle->idx < coder->left_dongle->idx) - { - first = coder->left_dongle; - second = coder->right_dongle; - } - else - { - first = coder->right_dongle; - second = coder->left_dongle; - } - pthread_mutex_lock(&first->lock); - first->last_used = now(); - print("%ld %d has taken a dongle\n", state, coder->idx); - pthread_mutex_lock(&second->lock); - second->last_used = now(); - print("%ld %d has taken a dongle\n", state, coder->idx); - pthread_mutex_lock(&coder->info_mutex); - coder->last_compile = now(); - coder->compiles_done += 1; - pthread_mutex_unlock(&coder->info_mutex); - print("%ld %d is compiling\n", state, coder->idx); - usleep(state->args.time_to_compile * 1000L); - pthread_mutex_unlock(&first->lock); - pthread_mutex_unlock(&second->lock); -} - -void debug_op(t_coder *coder, t_state *state) -{ - print("%ld %d is debugging\n", state, coder->idx); - usleep(state->args.time_to_debug * 1000L); -} - -void refactor_op(t_coder *coder, t_state *state) -{ - print("%ld %d is refactoring\n", state, coder->idx); - usleep(state->args.time_to_refactor * 1000L); -} - -void *run(void *param) -{ - t_coder *coder; - t_state *state; - int i; - - coder = param; - state = coder->state; - i = 0; - while (i < state->args.number_of_compiles_required) - { - if (is_over(state)) - return (NULL); - compile_op(coder, state); - if (is_over(state)) - return (NULL); - debug_op(coder, state); - if (is_over(state)) - return (NULL); - refactor_op(coder, state); - i++; - } - return (NULL); -} - -void *monitor(void *param) -{ - t_state *state; - int i; - long last; - int compiles_done; - - state = param; - compiles_done = 0; - while (compiles_done < state->args.number_of_compiles_required - && !is_over(state)) - { - usleep(1000); - i = -1; - while (++i < state->args.number_of_coders) - { - pthread_mutex_lock(&state->coders[i].info_mutex); - last = state->coders[i].last_compile; - compiles_done = state->coders[i].compiles_done; - pthread_mutex_unlock(&state->coders[i].info_mutex); - if (now() - last >= state->args.time_to_burnout) - { - pthread_mutex_lock(&state->over_mutex); - state->is_over = true; - pthread_mutex_unlock(&state->over_mutex); - print("%ld %d has burned out\n", state, state->coders[i].idx); - return (NULL); - } - } - } - return (NULL); -} - int cleanup(t_args *args, t_coder *coders, t_dongle *dongles) { - if (args) - free(args); + int i; + if (coders) free(coders); if (dongles) + { + i = 0; + while (i < args->number_of_coders) + free(dongles[i++].heap); free(dongles); + } + if (args) + free(args); return (0); } -t_state init_state(t_args *args) -{ - t_state state; - - state.start = now(); - state.args = *args; - state.is_over = false; - pthread_mutex_init(&state.print_mutex, NULL); - pthread_mutex_init(&state.over_mutex, NULL); - return (state); -} - -t_dongle *init_dongles(t_args *args, t_state *state) -{ - int i; - t_dongle *dongles; - - dongles = malloc(sizeof(t_dongle) * args->number_of_coders); - if (!dongles) - return (NULL); - i = -1; - while (++i < args->number_of_coders) - { - dongles[i].idx = i; - pthread_mutex_init(&dongles[i].lock, NULL); - dongles[i].last_used = state->start - args->dongle_cooldown; - } - return (dongles); -} - -t_coder *init_coders(t_args *args, t_state *state) -{ - t_coder *coders; - int i; - - coders = malloc(sizeof(t_coder) * args->number_of_coders); - if (!coders) - return (NULL); - i = -1; - while (++i < args->number_of_coders) - { - coders[i].idx = i; - coders[i].compiles_done = 0; - coders[i].last_compile = state->start; - coders[i].left_dongle = &state->dongles[i]; - coders[i].right_dongle = &state->dongles[(i + 1) - % args->number_of_coders]; - coders[i].state = state; - pthread_mutex_init(&coders[i].info_mutex, NULL); - } - return (coders); -} - int main(int argc, char **argv) { int i; @@ -224,8 +51,9 @@ int main(int argc, char **argv) return (cleanup(args, state.coders, state.dongles)); i = -1; while (++i < args->number_of_coders) - pthread_create(&state.coders[i].thread, NULL, run, &state.coders[i]); - pthread_create(&state.monitor, NULL, monitor, &state); + pthread_create(&state.coders[i].thread, NULL, coder_routine, + &state.coders[i]); + pthread_create(&state.monitor, NULL, monitor_routine, &state); i = -1; while (++i < args->number_of_coders) pthread_join(state.coders[i].thread, NULL); diff --git a/coders/monitor.c b/coders/monitor.c new file mode 100644 index 0000000..e858944 --- /dev/null +++ b/coders/monitor.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* monitor.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: semebrah +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */ +/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "codexion.h" + +static void stop_prog(t_state *state, int i) +{ + pthread_mutex_lock(&state->over_mutex); + state->is_over = true; + pthread_mutex_unlock(&state->over_mutex); + print("%ld %d has burned out\n", state, state->coders[i].idx); +} + +bool is_over(t_state *state) +{ + bool is_over; + + pthread_mutex_lock(&state->over_mutex); + is_over = state->is_over; + pthread_mutex_unlock(&state->over_mutex); + return (is_over); +} + +void *monitor_routine(void *param) +{ + t_state *state; + int i; + int done_coders; + t_args args; + + state = param; + args = state->args; + done_coders = 0; + while (done_coders < args.number_of_coders && !is_over(state)) + { + done_coders = 0; + i = -1; + while (++i < state->args.number_of_coders) + { + pthread_mutex_lock(&state->coders[i].info_mutex); + if (state->coders[i].compiles_done == args.compiles_todo) + done_coders++; + pthread_mutex_unlock(&state->coders[i].info_mutex); + if (now() + - state->coders[i].last_compile >= state->args.time_to_burnout) + return (stop_prog(state, i), NULL); + } + usleep(1000); + } + return (NULL); +} diff --git a/coders/schedulers.c b/coders/schedulers.c new file mode 100644 index 0000000..ab202dc --- /dev/null +++ b/coders/schedulers.c @@ -0,0 +1,28 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* scheduler.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: semebrah +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */ +/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "codexion.h" + +int fifo(void *t1, void *t2) +{ + t_entry *entry1; + t_entry *entry2; + + entry1 = t1; + entry2 = t2; + return (entry1->queued_at - entry2->queued_at); +} + +int edf(void *t1, void *t2) +{ + return (((t_entry *)t1)->deadline - ((t_entry *)t2)->deadline); +} diff --git a/coders/utils.c b/coders/utils.c index b222fc3..045edfa 100644 --- a/coders/utils.c +++ b/coders/utils.c @@ -5,18 +5,17 @@ /* +:+ +:+ +:+ */ /* By: semebrah +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ -/* Created: 2026/03/22 18:07:24 by semebrah #+# #+# */ +/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */ /* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */ /* */ /* ************************************************************************** */ #include "codexion.h" -#include #include #include #include -int isnumeric(char *str) +static int isnumeric(char *str) { size_t i; @@ -42,7 +41,7 @@ t_args *parse_arguments(int count, char **args) while (++i < 7) { if (!isnumeric(args[i])) - return (NULL); + return (free(data), NULL); args_int[i] = atoi(args[i]); } data->scheduler = args[7]; @@ -51,7 +50,30 @@ t_args *parse_arguments(int count, char **args) data->time_to_compile = args_int[2]; data->time_to_debug = args_int[3]; data->time_to_refactor = args_int[4]; - data->number_of_compiles_required = args_int[5]; + data->compiles_todo = args_int[5]; data->dongle_cooldown = args_int[6]; return (data); } + +long now(void) +{ + struct timeval current; + + gettimeofday(¤t, NULL); + return (current.tv_sec * 1000L + current.tv_usec / 1000); +} + +void print(char *str, t_state *state, int coder_idx) +{ + bool is_over; + + pthread_mutex_lock(&state->over_mutex); + is_over = state->is_over; + pthread_mutex_unlock(&state->over_mutex); + if (!is_over) + { + pthread_mutex_lock(&state->print_mutex); + printf(str, now() - state->start, coder_idx); + pthread_mutex_unlock(&state->print_mutex); + } +}