Diagrama de Módulos
┌─────────────────────────────────────────────────────────┐
│ main.c │
│ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ TUI (padre) │ │ GUI (hijo) │ │
│ │ test_sim() │ │ run_gui() │ │
│ └────────┬────────┘ └───────────┬─────────────┘ │
└───────────┼────────────────────────────┼────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────┐
│ sim_engine.c │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Asignación │ │ Liberación │ │ Compactación │ │
│ │ de memoria │ │ de procesos │ │ de huecos │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────┐
│ ficheros.c │
│ ┌──────────────────┐ ┌─────────────────────────┐ │
│ │ cargar_procesos │ │ guardar_estado │ │
│ │ (entrada.txt) │ │ (particiones.txt) │ │
│ └──────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Flujo de Ejecución
- Inicio: main() ejecuta fork()
- Proceso hijo (pid == 0): Ejecuta la GUI con Raylib
- Proceso padre (pid > 0): Espera con waitpid() a que el hijo termine
- Después de cerrar GUI: El padre ejecuta la TUI en terminal (modo paso a paso)
- Cada tick de simulación:
- Se envejecen los procesos en memoria (decrementan t_restante)
- Se liberan procesos que han terminado (t_restante == 0)
- Se intentan asignar procesos de la cola de espera
- Se guarda el estado en el log
Estructuras de Datos Principales
Memoria
La estructura central que gestiona las particiones:
typedef struct {
int cant_particiones;
int ultimo_indice_asignado;
#define MAX_PARTICIONES
Máximo número de particiones simultáneas en memoria.
Estructura principal que representa la memoria del sistema.
Estructura que representa una partición de memoria.
Proceso
Representa un proceso en la simulación:
typedef struct {
char nombre[10];
int t_llegada;
int mem_requerida;
int t_ejecucion;
int t_restante;
bool en_memoria;
bool finalizado;
Estructura que representa un proceso en el simulador.
Partición
Representa un bloque de memoria (hueco o proceso):
typedef struct {
int dir_inicio;
int tamano;
int estado;
char nombre_proceso[10];
Algoritmos de Asignación
First Fit (Primer Hueco)
Busca secuencialmente desde el inicio de la memoria:
Para i = 0 hasta cant_particiones:
Si particiones[i].estado == HUECO Y
particiones[i].tamano >= mem_requerida:
Retornar i
Retornar -1 (no encontrado)
Ventajas: Simple, rápido para memorias pequeñas Desventajas: Fragmentación al inicio de la memoria
Next Fit (Siguiente Hueco)
Busca desde la última posición asignada (circular):
inicio = ultimo_indice_asignado
Para j = 0 hasta cant_particiones:
i = (inicio + j) % cant_particiones
Si particiones[i].estado == HUECO Y
particiones[i].tamano >= mem_requerida:
ultimo_indice_asignado = i
Retornar i
Retornar -1 (no encontrado)
Ventajas: Distribuye mejor la fragmentación Desventajas: Puede ser más lento en el peor caso
Gestión de Memoria
Alineación
Toda memoria se alinea a múltiplos de UNIDAD_MINIMA (100):
int tam_final;
int bloques = size / 100;
if (size % 100 != 0)
else
tam_final = bloques * 100;
} else
return tam_final;
}
#define UNIDAD_MINIMA
Unidad mínima de asignación. Toda memoria se alinea a múltiplos de este valor.
int alinear_size(int size)
Alinea un tamaño a múltiplos de UNIDAD_MINIMA.
Compactación
Cuando se libera un proceso, se fusionan huecos adyacentes:
Para cada par de particiones consecutivas:
Si ambas son HUECO:
Fusionar (sumar tamaños)
Eliminar la segunda
Repetir desde el inicio
Uso de fork()
El programa usa fork() para ejecutar GUI y TUI en paralelo:
pid_t pid = fork();
if (pid == 0) {
run_gui(&m, procesos, num_procesos);
_exit(0);
} else {
waitpid(pid, NULL, 0);
}
void test_sim()
Ejecuta la simulación en modo terminal (TUI).
void run_gui(Memoria *m, Proceso *procesos, int num_procesos)
Ejecuta la interfaz gráfica con Raylib.
Esto permite depurar en terminal mientras se visualiza en la GUI.