mostly done; helgrind issue not fixed

This commit is contained in:
Semere M. Mebrahtom 2026-04-02 19:53:23 +02:00
parent b1b32525a5
commit 6d65af5288
Signed by: semere
GPG key ID: 7FC937214DF30488
9 changed files with 381 additions and 231 deletions

View file

@ -6,17 +6,10 @@ INCLUDES = coders/codexion.h
OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o)
CC = cc CC = cc
CFLAGS = -Wall -Wextra -Werror -pthread -g -fsanitize=thread # CFLAGS = -Wall -Wextra -Werror -pthread -g -fsanitize=thread
# CFLAGS = -Wall -Wextra -Werror CFLAGS = -Wall -Wextra -Werror
# number_of_coders
# time_to_burnout ARGS = 4 800 200 100 10 3 0 fifo
# 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
all: $(NAME) all: $(NAME)

103
coders/coder.c Normal file
View file

@ -0,0 +1,103 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* coder.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */
/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */
/* */
/* ************************************************************************** */
#include "codexion.h"
#include <stdlib.h>
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);
}

View file

@ -12,14 +12,24 @@
#ifndef CODEXION_H #ifndef CODEXION_H
# define CODEXION_H # define CODEXION_H
# include <pthread.h> # include <pthread.h>
# include <stdbool.h> # include <stdbool.h>
# include <sys/time.h> # include <sys/time.h>
# include <unistd.h>
# ifndef HEAP_SIZE
# define HEAP_SIZE 2
# endif
typedef struct s_state t_state; typedef struct s_state t_state;
typedef struct s_args t_args;
typedef struct s_dongle t_dongle; typedef struct s_minheap
typedef struct s_coder t_coder; {
int length;
void *array[HEAP_SIZE];
int (*cmp)(void *, void *);
} t_minheap;
typedef struct s_args typedef struct s_args
{ {
@ -28,7 +38,7 @@ typedef struct s_args
int time_to_compile; int time_to_compile;
int time_to_debug; int time_to_debug;
int time_to_refactor; int time_to_refactor;
int number_of_compiles_required; int compiles_todo;
int dongle_cooldown; int dongle_cooldown;
char *scheduler; char *scheduler;
} t_args; } t_args;
@ -36,8 +46,10 @@ typedef struct s_args
typedef struct s_dongle typedef struct s_dongle
{ {
int idx; int idx;
pthread_mutex_t lock;
long last_used; long last_used;
t_minheap *heap;
pthread_mutex_t condmutex;
pthread_cond_t cond;
} t_dongle; } t_dongle;
typedef struct s_coder typedef struct s_coder
@ -64,23 +76,44 @@ typedef struct s_state
pthread_t monitor; pthread_t monitor;
} t_state; } 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); 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 // 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 *peek(t_minheap *heap);
void enqueue(t_minheap *heap, void *val); void enqueue(t_minheap *heap, void *val);
void *dequeue(t_minheap *heap); 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 #endif

View file

@ -1,6 +1,16 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* heap.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */
/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */
/* */
/* ************************************************************************** */
#include "codexion.h" #include "codexion.h"
#include <stdbool.h>
#include <stdlib.h>
static void sift_up(t_minheap *heap, int i, int (*cmp)(void *, void *)) 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) void *peek(t_minheap *heap)
{ {
if (!heap || !heap->length) if (!heap || !heap->length)

85
coders/initialization.c Normal file
View file

@ -0,0 +1,85 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* initialization.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/03/22 18:07:14 by semebrah #+# #+# */
/* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */
/* */
/* ************************************************************************** */
#include "codexion.h"
#include <stdlib.h>
#include <string.h>
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);
}

View file

@ -13,201 +13,28 @@
#include "codexion.h" #include "codexion.h"
#include <pthread.h> #include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
long now(void)
{
struct timeval current;
gettimeofday(&current, 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) int cleanup(t_args *args, t_coder *coders, t_dongle *dongles)
{ {
if (args) int i;
free(args);
if (coders) if (coders)
free(coders); free(coders);
if (dongles) if (dongles)
{
i = 0;
while (i < args->number_of_coders)
free(dongles[i++].heap);
free(dongles); free(dongles);
}
if (args)
free(args);
return (0); 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 main(int argc, char **argv)
{ {
int i; int i;
@ -224,8 +51,9 @@ int main(int argc, char **argv)
return (cleanup(args, state.coders, state.dongles)); return (cleanup(args, state.coders, state.dongles));
i = -1; i = -1;
while (++i < args->number_of_coders) while (++i < args->number_of_coders)
pthread_create(&state.coders[i].thread, NULL, run, &state.coders[i]); pthread_create(&state.coders[i].thread, NULL, coder_routine,
pthread_create(&state.monitor, NULL, monitor, &state); &state.coders[i]);
pthread_create(&state.monitor, NULL, monitor_routine, &state);
i = -1; i = -1;
while (++i < args->number_of_coders) while (++i < args->number_of_coders)
pthread_join(state.coders[i].thread, NULL); pthread_join(state.coders[i].thread, NULL);

60
coders/monitor.c Normal file
View file

@ -0,0 +1,60 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* monitor.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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);
}

28
coders/schedulers.c Normal file
View file

@ -0,0 +1,28 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* scheduler.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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);
}

View file

@ -5,18 +5,17 @@
/* +:+ +:+ +:+ */ /* +:+ +:+ +:+ */
/* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */ /* By: semebrah <semebrah@student.42berlin.de> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* 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 */ /* Updated: 2026/03/22 18:07:31 by semebrah ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "codexion.h" #include "codexion.h"
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
int isnumeric(char *str) static int isnumeric(char *str)
{ {
size_t i; size_t i;
@ -42,7 +41,7 @@ t_args *parse_arguments(int count, char **args)
while (++i < 7) while (++i < 7)
{ {
if (!isnumeric(args[i])) if (!isnumeric(args[i]))
return (NULL); return (free(data), NULL);
args_int[i] = atoi(args[i]); args_int[i] = atoi(args[i]);
} }
data->scheduler = args[7]; 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_compile = args_int[2];
data->time_to_debug = args_int[3]; data->time_to_debug = args_int[3];
data->time_to_refactor = args_int[4]; 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]; data->dongle_cooldown = args_int[6];
return (data); return (data);
} }
long now(void)
{
struct timeval current;
gettimeofday(&current, 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);
}
}