Fixed test 10, added exercices: death_monitor and philosophers_args
This commit is contained in:
parent
69d8209b12
commit
cae865cd92
@ -6,37 +6,29 @@
|
|||||||
/* By: ruiferna <ruiferna@student.42porto.com> +#+ +:+ +#+ */
|
/* By: ruiferna <ruiferna@student.42porto.com> +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/10/09 20:16:37 by ruiferna #+# #+# */
|
/* Created: 2025/10/09 20:16:37 by ruiferna #+# #+# */
|
||||||
/* Updated: 2025/10/09 21:23:37 by ruiferna ### ########.fr */
|
/* Updated: 2025/10/10 20:51:41 by ruiferna ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include "simple_philosophers.h"
|
#include "simple_philosophers.h"
|
||||||
|
|
||||||
#define WORKERS 4
|
#define WORKERS 900
|
||||||
|
|
||||||
static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
int get_random_sleep_duration() {
|
int get_random_sleep_duration() {
|
||||||
// Seed variable to ensure unique seed per thread
|
|
||||||
unsigned int seed;
|
unsigned int seed;
|
||||||
|
|
||||||
// Acquire mutex to ensure thread-safe random number generation
|
|
||||||
pthread_mutex_lock(&random_mutex);
|
pthread_mutex_lock(&random_mutex);
|
||||||
|
|
||||||
// Use thread-safe method to generate seed
|
|
||||||
seed = time(NULL) ^ pthread_self();
|
seed = time(NULL) ^ pthread_self();
|
||||||
|
/* produce a duration between 1000 and 4000 ms (1-4 seconds) */
|
||||||
// Generate random number between 1000-4000 milliseconds
|
int duration = 1000 + rand_r(&seed) % 6001;
|
||||||
int duration = 1000 + rand_r(&seed) % 3001;
|
|
||||||
|
|
||||||
// Release mutex
|
|
||||||
pthread_mutex_unlock(&random_mutex);
|
pthread_mutex_unlock(&random_mutex);
|
||||||
|
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
typedef struct {
|
{
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
struct timeval last_activity_time;
|
struct timeval last_activity_time;
|
||||||
int alive; // 1 if alive, 0 if dead
|
int alive; // 1 if alive, 0 if dead
|
||||||
@ -60,6 +52,7 @@ void *worker_routine(void *arg)
|
|||||||
int sleep_time;
|
int sleep_time;
|
||||||
|
|
||||||
shared = (t_shared *) arg;
|
shared = (t_shared *) arg;
|
||||||
|
/* assign a unique id in range [0, WORKERS-1] */
|
||||||
pthread_mutex_lock(&shared->mutex_id);
|
pthread_mutex_lock(&shared->mutex_id);
|
||||||
shared->id += 1;
|
shared->id += 1;
|
||||||
worker_id = shared->id;
|
worker_id = shared->id;
|
||||||
@ -76,9 +69,39 @@ void *worker_routine(void *arg)
|
|||||||
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *monitor_routine(void *arg)
|
||||||
|
{
|
||||||
|
t_shared *shared;
|
||||||
|
long long time_diff;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
shared = (t_shared *) arg;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
while (i < WORKERS)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&shared->workers_mutexes[i]);
|
||||||
|
time_diff = get_current_time() - shared->last_updated[i];
|
||||||
|
pthread_mutex_unlock(&shared->workers_mutexes[i]);
|
||||||
|
if (time_diff > 3000)
|
||||||
|
{
|
||||||
|
printf("Worker %i died.\n", i);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
/* sleep once per full scan to keep checks frequent and non-blocking */
|
||||||
|
precise_sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
t_shared shared;
|
t_shared shared;
|
||||||
|
pthread_t monitor;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -101,12 +124,15 @@ int main()
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
pthread_create(&monitor, NULL, monitor_routine, &shared);
|
||||||
while (i < WORKERS)
|
pthread_join(monitor, NULL);
|
||||||
{
|
|
||||||
pthread_join(shared.workers[i], NULL);
|
// i = 0;
|
||||||
i++;
|
// while (i < WORKERS)
|
||||||
}
|
// {
|
||||||
|
// pthread_join(shared.workers[i], NULL);
|
||||||
|
// i++;
|
||||||
|
// }
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|||||||
383
rendu/philosophers_args.c
Normal file
383
rendu/philosophers_args.c
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
/* ************************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* ::: :::::::: */
|
||||||
|
/* philosophers_args.c :+: :+: :+: */
|
||||||
|
/* +:+ +:+ +:+ */
|
||||||
|
/* By: ruiferna <ruiferna@student.42porto.com> +#+ +:+ +#+ */
|
||||||
|
/* +#+#+#+#+#+ +#+ */
|
||||||
|
/* Created: 2025/10/12 00:00:00 by ruiferna #+# #+# */
|
||||||
|
/* Updated: 2025/10/12 01:23:53 by ruiferna ### ########.fr */
|
||||||
|
/* */
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct s_philo
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
int meals_eaten;
|
||||||
|
long long last_meal_time;
|
||||||
|
pthread_mutex_t meal_mutex;
|
||||||
|
struct s_shared *shared;
|
||||||
|
} t_philo;
|
||||||
|
|
||||||
|
typedef struct s_shared
|
||||||
|
{
|
||||||
|
int num_philos;
|
||||||
|
int time_to_die;
|
||||||
|
int time_to_eat;
|
||||||
|
int time_to_sleep;
|
||||||
|
int must_eat_count;
|
||||||
|
int has_must_eat;
|
||||||
|
int simulation_stop;
|
||||||
|
long long start_time;
|
||||||
|
pthread_mutex_t *forks;
|
||||||
|
pthread_mutex_t printf_mutex;
|
||||||
|
pthread_mutex_t stop_mutex;
|
||||||
|
t_philo *philos;
|
||||||
|
} t_shared;
|
||||||
|
|
||||||
|
long long get_current_time(void)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return ((tv.tv_sec * 1000LL) + (tv.tv_usec / 1000LL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void precise_sleep(int ms)
|
||||||
|
{
|
||||||
|
long long start_time;
|
||||||
|
|
||||||
|
start_time = get_current_time();
|
||||||
|
while ((get_current_time() - start_time) < ms)
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_message(t_shared *shared, int philo_id, char *message)
|
||||||
|
{
|
||||||
|
long long timestamp;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&shared->stop_mutex);
|
||||||
|
if (!shared->simulation_stop)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&shared->stop_mutex);
|
||||||
|
pthread_mutex_lock(&shared->printf_mutex);
|
||||||
|
timestamp = get_current_time() - shared->start_time;
|
||||||
|
printf("%lld %d %s\n", timestamp, philo_id, message);
|
||||||
|
pthread_mutex_unlock(&shared->printf_mutex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pthread_mutex_unlock(&shared->stop_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_stop(t_shared *shared)
|
||||||
|
{
|
||||||
|
int stop;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&shared->stop_mutex);
|
||||||
|
stop = shared->simulation_stop;
|
||||||
|
pthread_mutex_unlock(&shared->stop_mutex);
|
||||||
|
return (stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void philo_eat(t_philo *philo)
|
||||||
|
{
|
||||||
|
int left_fork;
|
||||||
|
int right_fork;
|
||||||
|
int first;
|
||||||
|
int second;
|
||||||
|
|
||||||
|
left_fork = philo->id - 1;
|
||||||
|
right_fork = philo->id % philo->shared->num_philos;
|
||||||
|
first = left_fork;
|
||||||
|
second = right_fork;
|
||||||
|
if (first > second)
|
||||||
|
{
|
||||||
|
first = right_fork;
|
||||||
|
second = left_fork;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&philo->shared->forks[first]);
|
||||||
|
print_message(philo->shared, philo->id, "has taken a fork");
|
||||||
|
if (philo->shared->num_philos == 1)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&philo->shared->forks[first]);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&philo->shared->forks[second]);
|
||||||
|
print_message(philo->shared, philo->id, "has taken a fork");
|
||||||
|
pthread_mutex_lock(&philo->meal_mutex);
|
||||||
|
philo->last_meal_time = get_current_time();
|
||||||
|
pthread_mutex_unlock(&philo->meal_mutex);
|
||||||
|
print_message(philo->shared, philo->id, "is eating");
|
||||||
|
precise_sleep(philo->shared->time_to_eat);
|
||||||
|
pthread_mutex_lock(&philo->meal_mutex);
|
||||||
|
philo->meals_eaten++;
|
||||||
|
pthread_mutex_unlock(&philo->meal_mutex);
|
||||||
|
pthread_mutex_unlock(&philo->shared->forks[second]);
|
||||||
|
pthread_mutex_unlock(&philo->shared->forks[first]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *philo_routine(void *arg)
|
||||||
|
{
|
||||||
|
t_philo *philo;
|
||||||
|
|
||||||
|
philo = (t_philo *)arg;
|
||||||
|
if (philo->id % 2 == 0)
|
||||||
|
precise_sleep(50);
|
||||||
|
while (!check_stop(philo->shared))
|
||||||
|
{
|
||||||
|
print_message(philo->shared, philo->id, "is thinking");
|
||||||
|
philo_eat(philo);
|
||||||
|
if (check_stop(philo->shared))
|
||||||
|
break ;
|
||||||
|
print_message(philo->shared, philo->id, "is sleeping");
|
||||||
|
precise_sleep(philo->shared->time_to_sleep);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_death(t_shared *shared)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
long long current_time;
|
||||||
|
long long time_since_meal;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < shared->num_philos)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&shared->philos[i].meal_mutex);
|
||||||
|
current_time = get_current_time();
|
||||||
|
time_since_meal = current_time - shared->philos[i].last_meal_time;
|
||||||
|
pthread_mutex_unlock(&shared->philos[i].meal_mutex);
|
||||||
|
if (time_since_meal > shared->time_to_die)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&shared->stop_mutex);
|
||||||
|
shared->simulation_stop = 1;
|
||||||
|
pthread_mutex_unlock(&shared->stop_mutex);
|
||||||
|
pthread_mutex_lock(&shared->printf_mutex);
|
||||||
|
printf("%lld %d died\n", current_time - shared->start_time,
|
||||||
|
shared->philos[i].id);
|
||||||
|
pthread_mutex_unlock(&shared->printf_mutex);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_all_ate(t_shared *shared)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int all_done;
|
||||||
|
|
||||||
|
if (!shared->has_must_eat)
|
||||||
|
return (0);
|
||||||
|
i = 0;
|
||||||
|
all_done = 1;
|
||||||
|
while (i < shared->num_philos)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&shared->philos[i].meal_mutex);
|
||||||
|
if (shared->philos[i].meals_eaten < shared->must_eat_count)
|
||||||
|
all_done = 0;
|
||||||
|
pthread_mutex_unlock(&shared->philos[i].meal_mutex);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (all_done)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&shared->stop_mutex);
|
||||||
|
shared->simulation_stop = 1;
|
||||||
|
pthread_mutex_unlock(&shared->stop_mutex);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *monitor_routine(void *arg)
|
||||||
|
{
|
||||||
|
t_shared *shared;
|
||||||
|
|
||||||
|
shared = (t_shared *)arg;
|
||||||
|
while (!check_stop(shared))
|
||||||
|
{
|
||||||
|
if (check_death(shared))
|
||||||
|
break ;
|
||||||
|
if (check_all_ate(shared))
|
||||||
|
break ;
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ft_atoi(const char *str)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
i = 0;
|
||||||
|
while (str[i] >= '0' && str[i] <= '9')
|
||||||
|
{
|
||||||
|
result = result * 10 + (str[i] - '0');
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_valid_number(const char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (!str || str[0] == '\0')
|
||||||
|
return (0);
|
||||||
|
while (str[i])
|
||||||
|
{
|
||||||
|
if (str[i] < '0' || str[i] > '9')
|
||||||
|
return (0);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_arguments(int argc, char **argv, t_shared *shared)
|
||||||
|
{
|
||||||
|
if (argc != 5 && argc != 6)
|
||||||
|
{
|
||||||
|
printf("Usage: %s number_of_philosophers time_to_die time_to_eat time_to_sleep [number_of_times_must_eat]\n",
|
||||||
|
argv[0]);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if (!is_valid_number(argv[1]) || !is_valid_number(argv[2])
|
||||||
|
|| !is_valid_number(argv[3]) || !is_valid_number(argv[4]))
|
||||||
|
return (0);
|
||||||
|
shared->num_philos = ft_atoi(argv[1]);
|
||||||
|
shared->time_to_die = ft_atoi(argv[2]);
|
||||||
|
shared->time_to_eat = ft_atoi(argv[3]);
|
||||||
|
shared->time_to_sleep = ft_atoi(argv[4]);
|
||||||
|
if (shared->num_philos <= 0 || shared->time_to_die <= 0
|
||||||
|
|| shared->time_to_eat <= 0 || shared->time_to_sleep <= 0)
|
||||||
|
return (0);
|
||||||
|
if (argc == 6)
|
||||||
|
{
|
||||||
|
if (!is_valid_number(argv[5]))
|
||||||
|
return (0);
|
||||||
|
shared->must_eat_count = ft_atoi(argv[5]);
|
||||||
|
if (shared->must_eat_count <= 0)
|
||||||
|
return (0);
|
||||||
|
shared->has_must_eat = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
shared->has_must_eat = 0;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_shared(t_shared *shared)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
shared->simulation_stop = 0;
|
||||||
|
shared->forks = malloc(sizeof(pthread_mutex_t) * shared->num_philos);
|
||||||
|
if (!shared->forks)
|
||||||
|
return (0);
|
||||||
|
shared->philos = malloc(sizeof(t_philo) * shared->num_philos);
|
||||||
|
if (!shared->philos)
|
||||||
|
{
|
||||||
|
free(shared->forks);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while (i < shared->num_philos)
|
||||||
|
{
|
||||||
|
pthread_mutex_init(&shared->forks[i], NULL);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pthread_mutex_init(&shared->printf_mutex, NULL);
|
||||||
|
pthread_mutex_init(&shared->stop_mutex, NULL);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_philosophers(t_shared *shared)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
long long current_time;
|
||||||
|
|
||||||
|
current_time = get_current_time();
|
||||||
|
shared->start_time = current_time;
|
||||||
|
i = 0;
|
||||||
|
while (i < shared->num_philos)
|
||||||
|
{
|
||||||
|
shared->philos[i].id = i + 1;
|
||||||
|
shared->philos[i].meals_eaten = 0;
|
||||||
|
shared->philos[i].last_meal_time = current_time;
|
||||||
|
shared->philos[i].shared = shared;
|
||||||
|
pthread_mutex_init(&shared->philos[i].meal_mutex, NULL);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup(t_shared *shared, pthread_t *threads)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < shared->num_philos)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&shared->forks[i]);
|
||||||
|
pthread_mutex_destroy(&shared->philos[i].meal_mutex);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pthread_mutex_destroy(&shared->printf_mutex);
|
||||||
|
pthread_mutex_destroy(&shared->stop_mutex);
|
||||||
|
free(shared->forks);
|
||||||
|
free(shared->philos);
|
||||||
|
free(threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
t_shared shared;
|
||||||
|
pthread_t *threads;
|
||||||
|
pthread_t monitor;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&shared, 0, sizeof(t_shared));
|
||||||
|
if (!parse_arguments(argc, argv, &shared))
|
||||||
|
{
|
||||||
|
printf("Error: Invalid arguments\n");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (!init_shared(&shared))
|
||||||
|
{
|
||||||
|
printf("Error: Initialization failed\n");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
init_philosophers(&shared);
|
||||||
|
threads = malloc(sizeof(pthread_t) * shared.num_philos);
|
||||||
|
if (!threads)
|
||||||
|
{
|
||||||
|
cleanup(&shared, NULL);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
while (i < shared.num_philos)
|
||||||
|
{
|
||||||
|
pthread_create(&threads[i], NULL, philo_routine, &shared.philos[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pthread_create(&monitor, NULL, monitor_routine, &shared);
|
||||||
|
i = 0;
|
||||||
|
while (i < shared.num_philos)
|
||||||
|
{
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pthread_join(monitor, NULL);
|
||||||
|
cleanup(&shared, threads);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
@ -78,12 +78,13 @@ echo -e "${YELLOW}Using executable at: $EXE_PATH${NC}"
|
|||||||
|
|
||||||
# Test 1: Basic execution (no one should die)
|
# Test 1: Basic execution (no one should die)
|
||||||
echo -n "Test 1: Basic case - 5 800 200 200... "
|
echo -n "Test 1: Basic case - 5 800 200 200... "
|
||||||
timeout 10 "$EXE_PATH" 5 800 200 200 > /tmp/philo_test1.txt 2>&1
|
timeout 3 "$EXE_PATH" 5 800 200 200 > /tmp/philo_test1.txt 2>&1
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
|
|
||||||
if [ $EXIT_CODE -eq 0 ]; then
|
# Exit code 124 means timeout (which is expected for infinite simulation)
|
||||||
|
if [ $EXIT_CODE -eq 124 ] || [ $EXIT_CODE -eq 0 ]; then
|
||||||
OUTPUT=$(cat /tmp/philo_test1.txt)
|
OUTPUT=$(cat /tmp/philo_test1.txt)
|
||||||
if ! echo "$OUTPUT" | grep -qiE "die"; then
|
if ! echo "$OUTPUT" | grep -qiE "died"; then
|
||||||
echo -e "${GREEN}✓ PASSED${NC}"
|
echo -e "${GREEN}✓ PASSED${NC}"
|
||||||
((PASSED++))
|
((PASSED++))
|
||||||
else
|
else
|
||||||
@ -92,7 +93,7 @@ if [ $EXIT_CODE -eq 0 ]; then
|
|||||||
((FAILED++))
|
((FAILED++))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${RED}✗ FAILED (timeout or crash)${NC}"
|
echo -e "${RED}✗ FAILED (crash - exit code $EXIT_CODE)${NC}"
|
||||||
((FAILED++))
|
((FAILED++))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -165,15 +166,21 @@ fi
|
|||||||
# Test 6: Check for memory leaks with valgrind
|
# Test 6: Check for memory leaks with valgrind
|
||||||
if command -v valgrind &> /dev/null; then
|
if command -v valgrind &> /dev/null; then
|
||||||
echo -n "Test 6: Memory leak check... "
|
echo -n "Test 6: Memory leak check... "
|
||||||
VALGRIND_OUTPUT=$(valgrind --leak-check=full --error-exitcode=42 "$EXE_PATH" 4 410 200 200 2>&1)
|
# Use a limited run with meal count to ensure program terminates
|
||||||
if [ $? -ne 42 ]; then
|
VALGRIND_OUTPUT=$(timeout 10 valgrind --leak-check=full --error-exitcode=42 "$EXE_PATH" 4 410 200 200 5 2>&1)
|
||||||
|
VALGRIND_EXIT=$?
|
||||||
|
# Exit code 124 is timeout, 42 is memory leak
|
||||||
|
if [ $VALGRIND_EXIT -eq 0 ]; then
|
||||||
echo -e "${GREEN}✓ PASSED${NC}"
|
echo -e "${GREEN}✓ PASSED${NC}"
|
||||||
((PASSED++))
|
((PASSED++))
|
||||||
else
|
elif [ $VALGRIND_EXIT -eq 42 ]; then
|
||||||
echo -e "${RED}✗ FAILED${NC}"
|
echo -e "${RED}✗ FAILED${NC}"
|
||||||
echo "Memory leaks detected!"
|
echo "Memory leaks detected!"
|
||||||
echo "$VALGRIND_OUTPUT" | grep -A 5 "LEAK SUMMARY"
|
echo "$VALGRIND_OUTPUT" | grep -A 5 "LEAK SUMMARY"
|
||||||
((FAILED++))
|
((FAILED++))
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ TIMEOUT/ERROR (exit code $VALGRIND_EXIT)${NC}"
|
||||||
|
echo "Skipping this test"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${YELLOW}⊘ Test 6: Valgrind not installed, skipping memory test${NC}"
|
echo -e "${YELLOW}⊘ Test 6: Valgrind not installed, skipping memory test${NC}"
|
||||||
@ -194,7 +201,8 @@ if command -v gcc &> /dev/null; then
|
|||||||
TSAN_EXE="$PROJECT_ROOT/$(basename "$EXE_PATH")_tsan"
|
TSAN_EXE="$PROJECT_ROOT/$(basename "$EXE_PATH")_tsan"
|
||||||
gcc -Wall -Wextra -Werror -pthread -fsanitize=thread -g "$SOURCE_FILE" -o "$TSAN_EXE" 2>/dev/null
|
gcc -Wall -Wextra -Werror -pthread -fsanitize=thread -g "$SOURCE_FILE" -o "$TSAN_EXE" 2>/dev/null
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
TSAN_OUTPUT=$(timeout 15 "$TSAN_EXE" 4 410 200 200 2>&1)
|
# Use meal limit to ensure program terminates
|
||||||
|
TSAN_OUTPUT=$(timeout 10 "$TSAN_EXE" 4 410 200 200 5 2>&1)
|
||||||
if echo "$TSAN_OUTPUT" | grep -q "WARNING: ThreadSanitizer: data race"; then
|
if echo "$TSAN_OUTPUT" | grep -q "WARNING: ThreadSanitizer: data race"; then
|
||||||
echo -e "${RED}✗ FAILED${NC}"
|
echo -e "${RED}✗ FAILED${NC}"
|
||||||
echo "Data race detected!"
|
echo "Data race detected!"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user