180 lines
5.3 KiB
C
180 lines
5.3 KiB
C
/* ************************************************************************** */
|
|
/* */
|
|
/* ::: :::::::: */
|
|
/* state_monitor.c :+: :+: :+: */
|
|
/* +:+ +:+ +:+ */
|
|
/* By: ruiferna <ruiferna@student.42porto.com> +#+ +:+ +#+ */
|
|
/* +#+#+#+#+#+ +#+ */
|
|
/* Created: 2025/10/07 20:54:07 by ruiferna #+# #+# */
|
|
/* Updated: 2025/10/07 22:07:12 by ruiferna ### ########.fr */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
|
|
#include <stdio.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <stdbool.h> // Para usar bool, true, false
|
|
|
|
#define NUM_WORKERS 3
|
|
#define WORK_DURATION 2000
|
|
#define REST_DURATION 1000
|
|
#define THINK_DURATION 1500
|
|
#define STUCK_THRESHOLD 3000
|
|
|
|
bool g_simulation_running = true;
|
|
|
|
typedef enum e_state {
|
|
WORKING,
|
|
RESTING,
|
|
THINKING
|
|
} State;
|
|
|
|
const char* state_to_string(State state) {
|
|
switch (state) {
|
|
case WORKING: return "WORKING";
|
|
case RESTING: return "RESTING";
|
|
case THINKING: return "THINKING";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
typedef struct s_worker
|
|
{
|
|
int id;
|
|
long long init_time;
|
|
long long last_state_update;
|
|
State current_state;
|
|
pthread_mutex_t data_mutex;
|
|
} t_worker;
|
|
|
|
|
|
long long get_current_time()
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv,NULL);
|
|
return ((tv.tv_sec * 1000LL) + (tv.tv_usec / 1000LL));
|
|
}
|
|
|
|
|
|
long long time_diff(long long start, long long end)
|
|
{
|
|
return (end - start);
|
|
}
|
|
|
|
|
|
void precise_sleep(int ms)
|
|
{
|
|
long long start_time = get_current_time();
|
|
while ((get_current_time() - start_time) < ms)
|
|
{
|
|
usleep(100);
|
|
}
|
|
}
|
|
|
|
// ROTINA DO MONITOR
|
|
void *monitor_routine(void *arg)
|
|
{
|
|
t_worker *workers = (t_worker *)arg;
|
|
|
|
while (g_simulation_running)
|
|
{
|
|
for (int i = 0; i < NUM_WORKERS; i++)
|
|
{
|
|
pthread_mutex_lock(&workers[i].data_mutex);
|
|
|
|
long long current_time = get_current_time();
|
|
long long time_since_update = current_time - workers[i].last_state_update;
|
|
|
|
// Only check for stuck workers if they have been running for at least 1 second
|
|
if (current_time - workers[i].init_time > 1000 && time_since_update > STUCK_THRESHOLD)
|
|
{
|
|
printf("[%lld] WARNING: Worker %d stuck in %s\n",
|
|
time_diff(workers[i].init_time, current_time),
|
|
workers[i].id,
|
|
state_to_string(workers[i].current_state));
|
|
}
|
|
|
|
pthread_mutex_unlock(&workers[i].data_mutex);
|
|
}
|
|
usleep(100 * 1000);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
void *worker_routine(void *arg)
|
|
{
|
|
t_worker *worker = (t_worker *)arg;
|
|
|
|
while (g_simulation_running)
|
|
{
|
|
// WORKING
|
|
pthread_mutex_lock(&worker->data_mutex);
|
|
worker->current_state = WORKING;
|
|
worker->last_state_update = get_current_time();
|
|
printf("[%lld] Worker %d is %s\n", time_diff(worker->init_time, worker->last_state_update), worker->id, state_to_string(worker->current_state));
|
|
pthread_mutex_unlock(&worker->data_mutex);
|
|
precise_sleep(WORK_DURATION);
|
|
|
|
// RESTING
|
|
pthread_mutex_lock(&worker->data_mutex);
|
|
worker->current_state = RESTING;
|
|
worker->last_state_update = get_current_time();
|
|
printf("[%lld] Worker %d is %s\n", time_diff(worker->init_time, worker->last_state_update), worker->id, state_to_string(worker->current_state));
|
|
pthread_mutex_unlock(&worker->data_mutex);
|
|
precise_sleep(REST_DURATION);
|
|
|
|
// THINKING
|
|
pthread_mutex_lock(&worker->data_mutex);
|
|
worker->current_state = THINKING;
|
|
worker->last_state_update = get_current_time();
|
|
printf("[%lld] Worker %d is %s\n", time_diff(worker->init_time, worker->last_state_update), worker->id, state_to_string(worker->current_state));
|
|
pthread_mutex_unlock(&worker->data_mutex);
|
|
precise_sleep(THINK_DURATION);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
int main()
|
|
{
|
|
pthread_t monitor;
|
|
pthread_t workers_threads[NUM_WORKERS];
|
|
t_worker workers[NUM_WORKERS];
|
|
long long start_time = get_current_time();
|
|
|
|
for (int i = 0; i < NUM_WORKERS; i++)
|
|
{
|
|
workers[i].id = i + 1;
|
|
workers[i].current_state = WORKING;
|
|
workers[i].init_time = start_time;
|
|
workers[i].last_state_update = start_time;
|
|
pthread_mutex_init(&workers[i].data_mutex, NULL); // Inicializar o mutex
|
|
}
|
|
|
|
pthread_create(&monitor, NULL, &monitor_routine, workers);
|
|
|
|
for (int i = 0; i < NUM_WORKERS; i++)
|
|
{
|
|
pthread_create(&workers_threads[i], NULL, &worker_routine, &workers[i]);
|
|
}
|
|
|
|
sleep(10);
|
|
g_simulation_running = false;
|
|
|
|
for (int i = 0; i < NUM_WORKERS; i++)
|
|
{
|
|
pthread_join(workers_threads[i], NULL);
|
|
}
|
|
pthread_join(monitor, NULL);
|
|
|
|
for (int i = 0; i < NUM_WORKERS; i++)
|
|
{
|
|
pthread_mutex_destroy(&workers[i].data_mutex);
|
|
}
|
|
|
|
return (0);
|
|
}
|